Skip to content
Permalink
Browse files

Move QgsExpressionSorter out of QgsFeatureIterator for reusability

  • Loading branch information
m-kuhn committed Jan 15, 2016
1 parent 2da75da commit de25449c23bd116a4f1089002783b78c598090f8
@@ -0,0 +1,21 @@
/***************************************************************************
qgsexpressionsorter.cpp - QgsExpressionSorter
---------------------
begin : 15.1.2016
copyright : (C) 2016 by mku
email : [your-email-here]
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsexpressionsorter.h"

QgsExpressionSorter::QgsExpressionSorter()
{

}
@@ -0,0 +1,154 @@
/***************************************************************************
qgsexpressionsorter.h - QgsExpressionSorter
---------------------
begin : 15.1.2016
copyright : (C) 2016 by mku
email : [your-email-here]
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSEXPRESSIONSORTER_H
#define QGSEXPRESSIONSORTER_H

#include "qgsfeaturerequest.h"
#include "qgsindexedfeature.h"

/// @cond PRIVATE
class QgsExpressionSorter
{
public:
QgsExpressionSorter( const QList<QgsFeatureRequest::OrderByClause>& preparedOrderBys )
: mPreparedOrderBys( preparedOrderBys )
{}

bool operator()( const QgsIndexedFeature& f1, const QgsIndexedFeature& f2 ) const
{
int i = 0;
Q_FOREACH ( const QgsFeatureRequest::OrderByClause& orderBy, mPreparedOrderBys )
{
const QVariant& v1 = f1.mIndexes.at( i );
const QVariant& v2 = f2.mIndexes.at( i );
++i;

// Both NULL: don't care
if ( v1.isNull() && v2.isNull() )
continue;

// Check for NULLs first
if ( v1.isNull() != v2.isNull() )
{
if ( orderBy.nullsFirst() )
return v1.isNull();
else
return !v1.isNull();
}

// Both values are not NULL
switch ( v1.type() )
{
case QVariant::Int:
case QVariant::UInt:
case QVariant::LongLong:
case QVariant::ULongLong:
if ( v1.toLongLong() == v2.toLongLong() )
continue;
if ( orderBy.ascending() )
return v1.toLongLong() < v2.toLongLong();
else
return v1.toLongLong() > v2.toLongLong();

case QVariant::Double:
if ( qgsDoubleNear( v1.toDouble(), v2.toDouble() ) )
continue;
if ( orderBy.ascending() )
return v1.toDouble() < v2.toDouble();
else
return v1.toDouble() > v2.toDouble();

case QVariant::Date:
if ( v1.toDate() == v2.toDate() )
continue;
if ( orderBy.ascending() )
return v1.toDate() < v2.toDate();
else
return v1.toDate() > v2.toDate();

case QVariant::DateTime:
if ( v1.toDateTime() == v2.toDateTime() )
continue;
if ( orderBy.ascending() )
return v1.toDateTime() < v2.toDateTime();
else
return v1.toDateTime() > v2.toDateTime();

case QVariant::Bool:
if ( v1.toBool() == v2.toBool() )
continue;
if ( orderBy.ascending() )
return !v1.toBool();
else
return v1.toBool();

default:
if ( 0 == v1.toString().localeAwareCompare( v2.toString() ) )
continue;
if ( orderBy.ascending() )
return v1.toString().localeAwareCompare( v2.toString() ) < 0;
else
return v1.toString().localeAwareCompare( v2.toString() ) > 0;
}
}

// Equal
return true;
}

void sortFeatures( QList<QgsFeature>& features, QgsExpressionContext* expressionContext )
{
QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Expression Sorter" ) );

expressionContext->appendScope( scope );

QList<QgsIndexedFeature> indexedFeatures;

QgsIndexedFeature indexedFeature;

Q_FOREACH ( const QgsFeature& f, features )
{
indexedFeature.mIndexes.resize( mPreparedOrderBys.size() );
indexedFeature.mFeature = f;

expressionContext->setFeature( indexedFeature.mFeature );

int i = 0;
Q_FOREACH ( const QgsFeatureRequest::OrderByClause& orderBy, mPreparedOrderBys )
{
indexedFeature.mIndexes.replace( i++, orderBy.expression().evaluate( expressionContext ) );
}
indexedFeatures.append( indexedFeature );
}

expressionContext->popScope();

qSort( indexedFeatures.begin(), indexedFeatures.end(), *this );

features.clear();

Q_FOREACH ( const QgsIndexedFeature& indexedFeature, indexedFeatures )
features.append( indexedFeature.mFeature );
}

private:
QList<QgsFeatureRequest::OrderByClause> mPreparedOrderBys;
};

/// @endcond


#endif // QGSEXPRESSIONSORTER_H
@@ -18,104 +18,7 @@
#include "qgsgeometrysimplifier.h"
#include "qgssimplifymethod.h"

#include <algorithm>


/// @cond PRIVATE
class QgsExpressionSorter
{
public:
QgsExpressionSorter( const QList<QgsFeatureRequest::OrderByClause>& preparedOrderBys )
: mPreparedOrderBys( preparedOrderBys )
{}

bool operator()( const QgsIndexedFeature& f1, const QgsIndexedFeature& f2 ) const
{
int i = 0;
Q_FOREACH ( const QgsFeatureRequest::OrderByClause& orderBy, mPreparedOrderBys )
{
const QVariant& v1 = f1.mIndexes.at( i );
const QVariant& v2 = f2.mIndexes.at( i );
++i;

// Both NULL: don't care
if ( v1.isNull() && v2.isNull() )
continue;

// Check for NULLs first
if ( v1.isNull() != v2.isNull() )
{
if ( orderBy.nullsFirst() )
return v1.isNull();
else
return !v1.isNull();
}

// Both values are not NULL
switch ( v1.type() )
{
case QVariant::Int:
case QVariant::UInt:
case QVariant::LongLong:
case QVariant::ULongLong:
if ( v1.toLongLong() == v2.toLongLong() )
continue;
if ( orderBy.ascending() )
return v1.toLongLong() < v2.toLongLong();
else
return v1.toLongLong() > v2.toLongLong();

case QVariant::Double:
if ( qgsDoubleNear( v1.toDouble(), v2.toDouble() ) )
continue;
if ( orderBy.ascending() )
return v1.toDouble() < v2.toDouble();
else
return v1.toDouble() > v2.toDouble();

case QVariant::Date:
if ( v1.toDate() == v2.toDate() )
continue;
if ( orderBy.ascending() )
return v1.toDate() < v2.toDate();
else
return v1.toDate() > v2.toDate();

case QVariant::DateTime:
if ( v1.toDateTime() == v2.toDateTime() )
continue;
if ( orderBy.ascending() )
return v1.toDateTime() < v2.toDateTime();
else
return v1.toDateTime() > v2.toDateTime();

case QVariant::Bool:
if ( v1.toBool() == v2.toBool() )
continue;
if ( orderBy.ascending() )
return !v1.toBool();
else
return v1.toBool();

default:
if ( 0 == v1.toString().localeAwareCompare( v2.toString() ) )
continue;
if ( orderBy.ascending() )
return v1.toString().localeAwareCompare( v2.toString() ) < 0;
else
return v1.toString().localeAwareCompare( v2.toString() ) > 0;
}
}

// Equal
return true;
}

private:
QList<QgsFeatureRequest::OrderByClause> mPreparedOrderBys;
};

/// @endcond
#include "qgsexpressionsorter.h"

QgsAbstractFeatureIterator::QgsAbstractFeatureIterator( const QgsFeatureRequest& request )
: mRequest( request )
@@ -17,19 +17,10 @@

#include "qgsfeaturerequest.h"
#include "qgslogger.h"
#include "qgsindexedfeature.h"

class QgsAbstractGeometrySimplifier;

/** Temporarily used structure to cache order by information
* \note not available in Python bindings
*/
class QgsIndexedFeature
{
public:
QVector<QVariant> mIndexes;
QgsFeature mFeature;
};

/** \ingroup core
* Internal feature iterator to be implemented within data providers
*/
@@ -0,0 +1,33 @@
/***************************************************************************
qgsindexedfeature - %{Cpp:License:ClassName}
---------------------
begin : 15.1.2016
copyright : (C) 2016 by mku
email : [your-email-here]
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSINDEXEDFEATURE_H
#define QGSINDEXEDFEATURE_H

#include <QVector>
#include "qgsfeature.h"

/** Temporarily used structure to cache order by information
* \note not available in Python bindings
*/
class QgsIndexedFeature
{
public:
QVector<QVariant> mIndexes;
QgsFeature mFeature;
};


#endif // QGSINDEXEDFEATURE_H

0 comments on commit de25449

Please sign in to comment.
You can’t perform that action at this time.