QGIS API Documentation  2.14.0-Essen
qgsexpressionsorter.h
Go to the documentation of this file.
1 /***************************************************************************
2  qgsexpressionsorter.h - QgsExpressionSorter
3  -------------------------------------------
4 
5  begin : 15.1.2016
6  Copyright : (C) 2016 Matthias Kuhn
7  Email : matthias at opengis dot ch
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 #ifndef QGSEXPRESSIONSORTER_H
17 #define QGSEXPRESSIONSORTER_H
18 
19 #include "qgsfeaturerequest.h"
20 #include "qgsindexedfeature.h"
21 
23 class QgsExpressionSorter
24 {
25  public:
26  QgsExpressionSorter( const QList<QgsFeatureRequest::OrderByClause>& preparedOrderBys )
27  : mPreparedOrderBys( preparedOrderBys )
28  {}
29 
30  bool operator()( const QgsIndexedFeature& f1, const QgsIndexedFeature& f2 ) const
31  {
32  int i = 0;
33  Q_FOREACH ( const QgsFeatureRequest::OrderByClause& orderBy, mPreparedOrderBys )
34  {
35  const QVariant& v1 = f1.mIndexes.at( i );
36  const QVariant& v2 = f2.mIndexes.at( i );
37  ++i;
38 
39  // Both NULL: don't care
40  if ( v1.isNull() && v2.isNull() )
41  continue;
42 
43  // Check for NULLs first
44  if ( v1.isNull() != v2.isNull() )
45  {
46  if ( orderBy.nullsFirst() )
47  return v1.isNull();
48  else
49  return !v1.isNull();
50  }
51 
52  // Both values are not NULL
53  switch ( v1.type() )
54  {
55  case QVariant::Int:
56  case QVariant::UInt:
57  case QVariant::LongLong:
58  case QVariant::ULongLong:
59  if ( v1.toLongLong() == v2.toLongLong() )
60  continue;
61  if ( orderBy.ascending() )
62  return v1.toLongLong() < v2.toLongLong();
63  else
64  return v1.toLongLong() > v2.toLongLong();
65 
66  case QVariant::Double:
67  if ( qgsDoubleNear( v1.toDouble(), v2.toDouble() ) )
68  continue;
69  if ( orderBy.ascending() )
70  return v1.toDouble() < v2.toDouble();
71  else
72  return v1.toDouble() > v2.toDouble();
73 
74  case QVariant::Date:
75  if ( v1.toDate() == v2.toDate() )
76  continue;
77  if ( orderBy.ascending() )
78  return v1.toDate() < v2.toDate();
79  else
80  return v1.toDate() > v2.toDate();
81 
82  case QVariant::Time:
83  if ( v1.toTime() == v2.toTime() )
84  continue;
85  if ( orderBy.ascending() )
86  return v1.toTime() < v2.toTime();
87  else
88  return v1.toTime() > v2.toTime();
89 
90  case QVariant::DateTime:
91  if ( v1.toDateTime() == v2.toDateTime() )
92  continue;
93  if ( orderBy.ascending() )
94  return v1.toDateTime() < v2.toDateTime();
95  else
96  return v1.toDateTime() > v2.toDateTime();
97 
98  case QVariant::Bool:
99  if ( v1.toBool() == v2.toBool() )
100  continue;
101  if ( orderBy.ascending() )
102  return !v1.toBool();
103  else
104  return v1.toBool();
105 
106  default:
107  if ( 0 == v1.toString().localeAwareCompare( v2.toString() ) )
108  continue;
109  if ( orderBy.ascending() )
110  return v1.toString().localeAwareCompare( v2.toString() ) < 0;
111  else
112  return v1.toString().localeAwareCompare( v2.toString() ) > 0;
113  }
114  }
115 
116  // Equal
117  return true;
118  }
119 
120  void sortFeatures( QList<QgsFeature>& features, QgsExpressionContext* expressionContext )
121  {
122  QgsExpressionContextScope* scope = new QgsExpressionContextScope( QObject::tr( "Expression Sorter" ) );
123 
124  expressionContext->appendScope( scope );
125 
126  QList<QgsIndexedFeature> indexedFeatures;
127 
128  QgsIndexedFeature indexedFeature;
129 
130  Q_FOREACH ( const QgsFeature& f, features )
131  {
132  indexedFeature.mIndexes.resize( mPreparedOrderBys.size() );
133  indexedFeature.mFeature = f;
134 
135  expressionContext->setFeature( indexedFeature.mFeature );
136 
137  int i = 0;
138  Q_FOREACH ( const QgsFeatureRequest::OrderByClause& orderBy, mPreparedOrderBys )
139  {
140  indexedFeature.mIndexes.replace( i++, orderBy.expression().evaluate( expressionContext ) );
141  }
142  indexedFeatures.append( indexedFeature );
143  }
144 
145  delete expressionContext->popScope();
146 
147  qSort( indexedFeatures.begin(), indexedFeatures.end(), *this );
148 
149  features.clear();
150 
151  Q_FOREACH ( const QgsIndexedFeature& indexedFeature, indexedFeatures )
152  features.append( indexedFeature.mFeature );
153  }
154 
155  private:
156  QList<QgsFeatureRequest::OrderByClause> mPreparedOrderBys;
157 };
158 
160 
161 
162 #endif // QGSEXPRESSIONSORTER_H
qlonglong toLongLong(bool *ok) const
void clear()
Q_DECL_DEPRECATED QVariant evaluate(const QgsFeature *f)
Evaluate the feature and return the result.
int localeAwareCompare(const QString &other) const
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QDateTime toDateTime() const
QTime toTime() const
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
QString tr(const char *sourceText, const char *disambiguation, int n)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:285
bool ascending() const
Order ascending.
QgsExpression expression() const
The expression.
void append(const T &value)
void resize(int size)
bool isNull() const
Temporarily used structure to cache order by information.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
Single scope for storing variables and functions for use within a QgsExpressionContext.
bool nullsFirst() const
Set if NULLS should be returned first.
iterator end()
The OrderByClause class represents an order by clause for a QgsFeatureRequest.
QDate toDate() const
const T & at(int i) const
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
bool toBool() const
QVector< QVariant > mIndexes
void replace(int i, const T &value)
double toDouble(bool *ok) const
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
Type type() const
QString toString() const
iterator begin()