Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsfeaturerequest.cpp 3 : : --------------------- 4 : : begin : Mai 2012 5 : : copyright : (C) 2012 by Martin Dobias 6 : : email : wonder dot sk at gmail dot com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : #include "qgsfeaturerequest.h" 16 : : 17 : : #include "qgsfields.h" 18 : : #include "qgsgeometry.h" 19 : : 20 : : #include <QStringList> 21 : : 22 : : //constants 23 : 10 : const QString QgsFeatureRequest::ALL_ATTRIBUTES = QStringLiteral( "#!allattributes!#" ); 24 : : 25 : 451 : QgsFeatureRequest::QgsFeatureRequest() 26 : : { 27 : 451 : } 28 : : 29 : 24 : QgsFeatureRequest::QgsFeatureRequest( QgsFeatureId fid ) 30 : 24 : : mFilter( FilterFid ) 31 : 24 : , mFilterFid( fid ) 32 : : { 33 : 24 : } 34 : : 35 : 0 : QgsFeatureRequest::QgsFeatureRequest( const QgsFeatureIds &fids ) 36 : 0 : : mFilter( FilterFids ) 37 : 0 : , mFilterFids( fids ) 38 : : { 39 : : 40 : 0 : } 41 : : 42 : 0 : QgsFeatureRequest::QgsFeatureRequest( const QgsRectangle &rect ) 43 : 0 : : mFilterRect( rect ) 44 : : { 45 : 0 : } 46 : : 47 : 0 : QgsFeatureRequest::QgsFeatureRequest( const QgsExpression &expr, const QgsExpressionContext &context ) 48 : 0 : : mFilter( FilterExpression ) 49 : 0 : , mFilterExpression( new QgsExpression( expr ) ) 50 : 0 : , mExpressionContext( context ) 51 : : { 52 : 0 : } 53 : : 54 : 371 : QgsFeatureRequest::QgsFeatureRequest( const QgsFeatureRequest &rh ) 55 : : { 56 : 371 : operator=( rh ); 57 : 371 : } 58 : : 59 : 533 : QgsFeatureRequest &QgsFeatureRequest::operator=( const QgsFeatureRequest &rh ) 60 : : { 61 : 533 : if ( &rh == this ) 62 : 0 : return *this; 63 : : 64 : 533 : mFlags = rh.mFlags; 65 : 533 : mFilter = rh.mFilter; 66 : 533 : mFilterRect = rh.mFilterRect; 67 : 533 : mFilterFid = rh.mFilterFid; 68 : 533 : mFilterFids = rh.mFilterFids; 69 : 533 : if ( rh.mFilterExpression ) 70 : : { 71 : 0 : mFilterExpression.reset( new QgsExpression( *rh.mFilterExpression ) ); 72 : 0 : } 73 : : else 74 : : { 75 : 533 : mFilterExpression.reset( nullptr ); 76 : : } 77 : 533 : mInvalidGeometryFilter = rh.mInvalidGeometryFilter; 78 : 533 : mInvalidGeometryCallback = rh.mInvalidGeometryCallback; 79 : 533 : mExpressionContext = rh.mExpressionContext; 80 : 533 : mAttrs = rh.mAttrs; 81 : 533 : mSimplifyMethod = rh.mSimplifyMethod; 82 : 533 : mLimit = rh.mLimit; 83 : 533 : mOrderBy = rh.mOrderBy; 84 : 533 : mCrs = rh.mCrs; 85 : 533 : mTransformContext = rh.mTransformContext; 86 : 533 : mTransformErrorCallback = rh.mTransformErrorCallback; 87 : 533 : mTimeout = rh.mTimeout; 88 : 533 : mRequestMayBeNested = rh.mRequestMayBeNested; 89 : 533 : return *this; 90 : 533 : } 91 : : 92 : 0 : QgsFeatureRequest &QgsFeatureRequest::setFilterRect( const QgsRectangle &rect ) 93 : : { 94 : 0 : mFilterRect = rect; 95 : 0 : return *this; 96 : : } 97 : : 98 : 0 : QgsFeatureRequest &QgsFeatureRequest::setFilterFid( QgsFeatureId fid ) 99 : : { 100 : 0 : mFilter = FilterFid; 101 : 0 : mFilterFid = fid; 102 : 0 : return *this; 103 : : } 104 : : 105 : 57 : QgsFeatureRequest &QgsFeatureRequest::setFilterFids( const QgsFeatureIds &fids ) 106 : : { 107 : 57 : mFilter = FilterFids; 108 : 57 : mFilterFids = fids; 109 : 57 : return *this; 110 : : } 111 : : 112 : 0 : QgsFeatureRequest &QgsFeatureRequest::setInvalidGeometryCheck( QgsFeatureRequest::InvalidGeometryCheck check ) 113 : : { 114 : 0 : mInvalidGeometryFilter = check; 115 : 0 : return *this; 116 : : } 117 : : 118 : 0 : QgsFeatureRequest &QgsFeatureRequest::setInvalidGeometryCallback( const std::function<void ( const QgsFeature & )> &callback ) 119 : : { 120 : 0 : mInvalidGeometryCallback = callback; 121 : 0 : return *this; 122 : : } 123 : : 124 : 0 : QgsFeatureRequest &QgsFeatureRequest::setFilterExpression( const QString &expression ) 125 : : { 126 : 0 : mFilter = FilterExpression; 127 : 0 : mFilterExpression.reset( new QgsExpression( expression ) ); 128 : 0 : return *this; 129 : 0 : } 130 : : 131 : 0 : QgsFeatureRequest &QgsFeatureRequest::combineFilterExpression( const QString &expression ) 132 : : { 133 : 0 : if ( mFilterExpression ) 134 : : { 135 : 0 : setFilterExpression( QStringLiteral( "(%1) AND (%2)" ).arg( mFilterExpression->expression(), expression ) ); 136 : 0 : } 137 : : else 138 : : { 139 : 0 : setFilterExpression( expression ); 140 : : } 141 : 0 : return *this; 142 : 0 : } 143 : : 144 : 0 : QgsFeatureRequest &QgsFeatureRequest::setExpressionContext( const QgsExpressionContext &context ) 145 : : { 146 : 0 : mExpressionContext = context; 147 : 0 : return *this; 148 : : } 149 : : 150 : 0 : QgsFeatureRequest &QgsFeatureRequest::addOrderBy( const QString &expression, bool ascending ) 151 : : { 152 : 0 : mOrderBy.append( OrderByClause( expression, ascending ) ); 153 : 0 : return *this; 154 : 0 : } 155 : : 156 : 0 : QgsFeatureRequest &QgsFeatureRequest::addOrderBy( const QString &expression, bool ascending, bool nullsfirst ) 157 : : { 158 : 0 : mOrderBy.append( OrderByClause( expression, ascending, nullsfirst ) ); 159 : 0 : return *this; 160 : 0 : } 161 : : 162 : 550 : QgsFeatureRequest::OrderBy QgsFeatureRequest::orderBy() const 163 : : { 164 : 550 : return mOrderBy; 165 : : } 166 : : 167 : 4 : QgsFeatureRequest &QgsFeatureRequest::setOrderBy( const QgsFeatureRequest::OrderBy &orderBy ) 168 : : { 169 : 4 : mOrderBy = orderBy; 170 : 4 : return *this; 171 : : } 172 : : 173 : 0 : QgsFeatureRequest &QgsFeatureRequest::setLimit( long limit ) 174 : : { 175 : 0 : mLimit = limit; 176 : 0 : return *this; 177 : : } 178 : : 179 : 0 : QgsFeatureRequest &QgsFeatureRequest::setFlags( QgsFeatureRequest::Flags flags ) 180 : : { 181 : 0 : mFlags = flags; 182 : 0 : return *this; 183 : : } 184 : : 185 : 139 : QgsFeatureRequest &QgsFeatureRequest::setSubsetOfAttributes( const QgsAttributeList &attrs ) 186 : : { 187 : 139 : mFlags |= SubsetOfAttributes; 188 : 139 : mAttrs = attrs; 189 : 139 : return *this; 190 : : } 191 : : 192 : 67 : QgsFeatureRequest &QgsFeatureRequest::setNoAttributes() 193 : : { 194 : 67 : return setSubsetOfAttributes( QgsAttributeList() ); 195 : 0 : } 196 : : 197 : 0 : QgsFeatureRequest &QgsFeatureRequest::setSubsetOfAttributes( const QStringList &attrNames, const QgsFields &fields ) 198 : : { 199 : 0 : if ( attrNames.contains( QgsFeatureRequest::ALL_ATTRIBUTES ) ) 200 : : { 201 : : //attribute string list contains the all attributes flag, so we must fetch all attributes 202 : 0 : return *this; 203 : : } 204 : : 205 : 0 : mFlags |= SubsetOfAttributes; 206 : 0 : mAttrs.clear(); 207 : : 208 : 0 : const auto constAttrNames = attrNames; 209 : 0 : for ( const QString &attrName : constAttrNames ) 210 : : { 211 : 0 : int attrNum = fields.lookupField( attrName ); 212 : 0 : if ( attrNum != -1 && !mAttrs.contains( attrNum ) ) 213 : 0 : mAttrs.append( attrNum ); 214 : : } 215 : : 216 : 0 : return *this; 217 : 0 : } 218 : : 219 : 0 : QgsFeatureRequest &QgsFeatureRequest::setSubsetOfAttributes( const QSet<QString> &attrNames, const QgsFields &fields ) 220 : : { 221 : 0 : if ( attrNames.contains( QgsFeatureRequest::ALL_ATTRIBUTES ) ) 222 : : { 223 : : //attribute string list contains the all attributes flag, so we must fetch all attributes 224 : 0 : return *this; 225 : : } 226 : : 227 : 0 : mFlags |= SubsetOfAttributes; 228 : 0 : mAttrs.clear(); 229 : : 230 : 0 : const auto constAttrNames = attrNames; 231 : 0 : for ( const QString &attrName : constAttrNames ) 232 : : { 233 : 0 : int attrNum = fields.lookupField( attrName ); 234 : 0 : if ( attrNum != -1 && !mAttrs.contains( attrNum ) ) 235 : 0 : mAttrs.append( attrNum ); 236 : : } 237 : : 238 : 0 : return *this; 239 : 0 : } 240 : : 241 : 0 : QgsFeatureRequest &QgsFeatureRequest::setSimplifyMethod( const QgsSimplifyMethod &simplifyMethod ) 242 : : { 243 : 0 : mSimplifyMethod = simplifyMethod; 244 : 0 : return *this; 245 : : } 246 : : 247 : : 248 : 476 : QgsCoordinateReferenceSystem QgsFeatureRequest::destinationCrs() const 249 : : { 250 : 476 : return mCrs; 251 : : } 252 : : 253 : 0 : QgsCoordinateTransformContext QgsFeatureRequest::transformContext() const 254 : : { 255 : 0 : return mTransformContext; 256 : : } 257 : : 258 : 0 : QgsFeatureRequest &QgsFeatureRequest::setDestinationCrs( const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context ) 259 : : { 260 : 0 : mCrs = crs; 261 : 0 : mTransformContext = context; 262 : 0 : return *this; 263 : : } 264 : : 265 : 0 : QgsFeatureRequest &QgsFeatureRequest::setTransformErrorCallback( const std::function<void ( const QgsFeature & )> &callback ) 266 : : { 267 : 0 : mTransformErrorCallback = callback; 268 : 0 : return *this; 269 : : } 270 : : 271 : 3 : bool QgsFeatureRequest::acceptFeature( const QgsFeature &feature ) 272 : : { 273 : 3 : if ( !mFilterRect.isNull() ) 274 : : { 275 : 0 : if ( !feature.hasGeometry() || 276 : : ( 277 : 0 : ( mFlags & ExactIntersect && !feature.geometry().intersects( mFilterRect ) ) 278 : 0 : || 279 : 0 : ( !( mFlags & ExactIntersect ) && !feature.geometry().boundingBoxIntersects( mFilterRect ) ) 280 : : ) 281 : : ) 282 : 0 : return false; 283 : 0 : } 284 : : 285 : 3 : switch ( mFilter ) 286 : : { 287 : : case QgsFeatureRequest::FilterNone: 288 : 3 : return true; 289 : : 290 : : case QgsFeatureRequest::FilterFid: 291 : 0 : return ( feature.id() == mFilterFid ); 292 : : 293 : : case QgsFeatureRequest::FilterExpression: 294 : 0 : mExpressionContext.setFeature( feature ); 295 : 0 : return ( mFilterExpression->evaluate( &mExpressionContext ).toBool() ); 296 : : 297 : : case QgsFeatureRequest::FilterFids: 298 : 0 : return ( mFilterFids.contains( feature.id() ) ); 299 : : } 300 : : 301 : 0 : return true; 302 : 3 : } 303 : : 304 : 0 : int QgsFeatureRequest::connectionTimeout() const 305 : : { 306 : 0 : return mTimeout; 307 : : } 308 : : 309 : 0 : QgsFeatureRequest &QgsFeatureRequest::setConnectionTimeout( int connectionTimeout ) 310 : : { 311 : 0 : mTimeout = connectionTimeout; 312 : 0 : return *this; 313 : : } 314 : : 315 : 92 : int QgsFeatureRequest::timeout() const 316 : : { 317 : 92 : return mTimeout; 318 : : } 319 : : 320 : 92 : QgsFeatureRequest &QgsFeatureRequest::setTimeout( int timeout ) 321 : : { 322 : 92 : mTimeout = timeout; 323 : 92 : return *this; 324 : : } 325 : : 326 : 92 : bool QgsFeatureRequest::requestMayBeNested() const 327 : : { 328 : 92 : return mRequestMayBeNested; 329 : : } 330 : : 331 : 0 : QgsFeatureRequest &QgsFeatureRequest::setRequestMayBeNested( bool requestMayBeNested ) 332 : : { 333 : 0 : mRequestMayBeNested = requestMayBeNested; 334 : 0 : return *this; 335 : : } 336 : : 337 : : 338 : : #include "qgsfeatureiterator.h" 339 : : #include "qgslogger.h" 340 : : 341 : 393 : QgsAbstractFeatureSource::~QgsAbstractFeatureSource() 342 : 393 : { 343 : 393 : while ( !mActiveIterators.empty() ) 344 : : { 345 : 0 : QgsAbstractFeatureIterator *it = *mActiveIterators.begin(); 346 : 0 : QgsDebugMsgLevel( QStringLiteral( "closing active iterator" ), 2 ); 347 : 0 : it->close(); 348 : : } 349 : 393 : } 350 : : 351 : 318 : void QgsAbstractFeatureSource::iteratorOpened( QgsAbstractFeatureIterator *it ) 352 : : { 353 : 318 : mActiveIterators.insert( it ); 354 : 318 : } 355 : : 356 : 318 : void QgsAbstractFeatureSource::iteratorClosed( QgsAbstractFeatureIterator *it ) 357 : : { 358 : 318 : mActiveIterators.remove( it ); 359 : 318 : } 360 : : 361 : : 362 : : 363 : 0 : QgsFeatureRequest::OrderByClause::OrderByClause( const QString &expression, bool ascending ) 364 : 0 : : mExpression( expression ) 365 : 0 : , mAscending( ascending ) 366 : : { 367 : : // postgres behavior: default for ASC: NULLS LAST, default for DESC: NULLS FIRST 368 : 0 : mNullsFirst = !ascending; 369 : 0 : } 370 : : 371 : 0 : QgsFeatureRequest::OrderByClause::OrderByClause( const QString &expression, bool ascending, bool nullsfirst ) 372 : 0 : : mExpression( expression ) 373 : 0 : , mAscending( ascending ) 374 : 0 : , mNullsFirst( nullsfirst ) 375 : : { 376 : 0 : } 377 : : 378 : 0 : QgsFeatureRequest::OrderByClause::OrderByClause( const QgsExpression &expression, bool ascending ) 379 : 0 : : mExpression( expression ) 380 : 0 : , mAscending( ascending ) 381 : : { 382 : : // postgres behavior: default for ASC: NULLS LAST, default for DESC: NULLS FIRST 383 : 0 : mNullsFirst = !ascending; 384 : 0 : } 385 : : 386 : 0 : QgsFeatureRequest::OrderByClause::OrderByClause( const QgsExpression &expression, bool ascending, bool nullsfirst ) 387 : 0 : : mExpression( expression ) 388 : 0 : , mAscending( ascending ) 389 : 0 : , mNullsFirst( nullsfirst ) 390 : : { 391 : : 392 : 0 : } 393 : : 394 : 0 : bool QgsFeatureRequest::OrderByClause::ascending() const 395 : : { 396 : 0 : return mAscending; 397 : : } 398 : : 399 : 0 : void QgsFeatureRequest::OrderByClause::setAscending( bool ascending ) 400 : : { 401 : 0 : mAscending = ascending; 402 : 0 : } 403 : : 404 : 0 : bool QgsFeatureRequest::OrderByClause::nullsFirst() const 405 : : { 406 : 0 : return mNullsFirst; 407 : : } 408 : : 409 : 0 : void QgsFeatureRequest::OrderByClause::setNullsFirst( bool nullsFirst ) 410 : : { 411 : 0 : mNullsFirst = nullsFirst; 412 : 0 : } 413 : : 414 : 0 : QString QgsFeatureRequest::OrderByClause::dump() const 415 : : { 416 : 0 : return QStringLiteral( "%1 %2 %3" ) 417 : 0 : .arg( mExpression.expression(), 418 : 0 : mAscending ? "ASC" : "DESC", 419 : 0 : mNullsFirst ? "NULLS FIRST" : "NULLS LAST" ); 420 : 0 : } 421 : : 422 : 0 : QgsExpression QgsFeatureRequest::OrderByClause::expression() const 423 : : { 424 : 0 : return mExpression; 425 : : } 426 : : 427 : 0 : bool QgsFeatureRequest::OrderByClause::prepare( QgsExpressionContext *context ) 428 : : { 429 : 0 : return mExpression.prepare( context ); 430 : : } 431 : : 432 : 928 : QgsFeatureRequest::OrderBy::OrderBy() = default; 433 : : 434 : 0 : QgsFeatureRequest::OrderBy::OrderBy( const QList<QgsFeatureRequest::OrderByClause> &other ) 435 : 0 : { 436 : 0 : const auto constOther = other; 437 : 0 : for ( const QgsFeatureRequest::OrderByClause &clause : constOther ) 438 : : { 439 : 0 : append( clause ); 440 : : } 441 : 0 : } 442 : : 443 : 0 : QList<QgsFeatureRequest::OrderByClause> QgsFeatureRequest::OrderBy::list() const 444 : : { 445 : 0 : return *this; 446 : : } 447 : : 448 : 0 : void QgsFeatureRequest::OrderBy::save( QDomElement &elem ) const 449 : : { 450 : 0 : QDomDocument doc = elem.ownerDocument(); 451 : 0 : QList<OrderByClause>::ConstIterator it; 452 : 0 : for ( it = constBegin(); it != constEnd(); ++it ) 453 : : { 454 : 0 : const OrderByClause &clause = *it; 455 : 0 : QDomElement clauseElem = doc.createElement( QStringLiteral( "orderByClause" ) ); 456 : 0 : clauseElem.setAttribute( QStringLiteral( "asc" ), clause.ascending() ); 457 : 0 : clauseElem.setAttribute( QStringLiteral( "nullsFirst" ), clause.nullsFirst() ); 458 : 0 : clauseElem.appendChild( doc.createTextNode( clause.expression().expression() ) ); 459 : : 460 : 0 : elem.appendChild( clauseElem ); 461 : 0 : } 462 : 0 : } 463 : : 464 : 0 : void QgsFeatureRequest::OrderBy::load( const QDomElement &elem ) 465 : : { 466 : 0 : clear(); 467 : : 468 : 0 : QDomNodeList clauses = elem.childNodes(); 469 : : 470 : 0 : for ( int i = 0; i < clauses.size(); ++i ) 471 : : { 472 : 0 : QDomElement clauseElem = clauses.at( i ).toElement(); 473 : 0 : QString expression = clauseElem.text(); 474 : 0 : bool asc = clauseElem.attribute( QStringLiteral( "asc" ) ).toInt() != 0; 475 : 0 : bool nullsFirst = clauseElem.attribute( QStringLiteral( "nullsFirst" ) ).toInt() != 0; 476 : : 477 : 0 : append( OrderByClause( expression, asc, nullsFirst ) ); 478 : 0 : } 479 : 0 : } 480 : : 481 : 0 : QSet<QString> QgsFeatureRequest::OrderBy::usedAttributes() const 482 : : { 483 : 0 : QSet<QString> usedAttributes; 484 : : 485 : 0 : QList<OrderByClause>::ConstIterator it; 486 : 0 : for ( it = constBegin(); it != constEnd(); ++it ) 487 : : { 488 : 0 : const OrderByClause &clause = *it; 489 : : 490 : 0 : usedAttributes.unite( clause.expression().referencedColumns() ); 491 : 0 : } 492 : : 493 : 0 : return usedAttributes; 494 : 0 : } 495 : : 496 : 0 : QSet<int> QgsFeatureRequest::OrderBy::usedAttributeIndices( const QgsFields &fields ) const 497 : : { 498 : 0 : QSet<int> usedAttributeIdx; 499 : 0 : for ( const OrderByClause &clause : *this ) 500 : : { 501 : 0 : const auto referencedColumns = clause.expression().referencedColumns(); 502 : 0 : for ( const QString &fieldName : referencedColumns ) 503 : : { 504 : 0 : int idx = fields.lookupField( fieldName ); 505 : 0 : if ( idx >= 0 ) 506 : : { 507 : 0 : usedAttributeIdx.insert( idx ); 508 : 0 : } 509 : : } 510 : 0 : } 511 : 0 : return usedAttributeIdx; 512 : 0 : } 513 : : 514 : 0 : QString QgsFeatureRequest::OrderBy::dump() const 515 : : { 516 : 0 : QStringList results; 517 : : 518 : 0 : QList<OrderByClause>::ConstIterator it; 519 : 0 : for ( it = constBegin(); it != constEnd(); ++it ) 520 : : { 521 : 0 : const OrderByClause &clause = *it; 522 : : 523 : 0 : results << clause.dump(); 524 : 0 : } 525 : : 526 : 0 : return results.join( QLatin1String( ", " ) ); 527 : 0 : }