Skip to content

Commit 09a9a61

Browse files
committed
field proxy model to filter fields on their type (also fix #10181)
1 parent 003374f commit 09a9a61

15 files changed

+297
-37
lines changed

python/gui/gui.sip

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
%Include qgsfieldexpressionwidget.sip
3333
%Include qgsfieldmodel.sip
3434
%Include qgsfieldvalidator.sip
35+
%Include qgsfieldproxymodel.sip
3536
%Include qgsfiledropedit.sip
3637
%Include qgsfilterlineedit.sip
3738
%Include qgsformannotationitem.sip

python/gui/qgsfieldcombobox.sip

+6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ class QgsFieldComboBox : QComboBox
1919
*/
2020
explicit QgsFieldComboBox( QWidget *parent /TransferThis/ = 0 );
2121

22+
//! setFilters allows fitering according to the type of field
23+
void setFilters( QgsFieldProxyModel::Filters filters );
24+
25+
//! currently used filter on list of fields
26+
QgsFieldProxyModel::Filters filters();
27+
2228
//! return the currently selected field
2329
QString currentField();
2430

python/gui/qgsfieldexpressionwidget.sip

+8-2
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,19 @@ class QgsFieldExpressionWidget : QWidget
1313

1414
//! define the title used in the expression dialog
1515
void setExpressionDialogTitle( QString title );
16+
17+
//! setFilters allows fitering according to the type of field
18+
void setFilters( QgsFieldProxyModel::Filters filters );
1619

17-
//! set the geometry calculator used in the expression dialog
18-
void setGeomCalculator( const QgsDistanceArea &da );
20+
//! currently used filter on list of fields
21+
QgsFieldProxyModel::Filters filters();
1922

2023
//! return the title used for the expression dialog
2124
const QString expressionDialogTitle();
2225

26+
//! set the geometry calculator used in the expression dialog
27+
void setGeomCalculator( const QgsDistanceArea &da );
28+
2329
/**
2430
* @brief currentField returns the currently selected field or expression if allowed
2531
* @param isExpression determines if the string returned is the name of a field or an expression

python/gui/qgsfieldmodel.sip

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ class QgsFieldModel : QAbstractItemModel
1818
FieldIndexRole = 34, /* return field index if index corresponds to a field */
1919
ExpressionRole = 35, /* return field name or expression */
2020
IsExpressionRole = 36, /* return if index corresponds to an expression */
21-
ExpressionValidityRole = 37 /* return if expression is valid or not */
21+
ExpressionValidityRole = 37, /* return if expression is valid or not */
22+
FieldTypeRole = 38 /* return the field type (if a field, return QVariant if expression) */
2223
};
2324

2425
/**

python/gui/qgsfieldproxymodel.sip

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @brief The QgsMapLayerProxModel class provides an easy to use model to display the list of layers in widgets.
3+
* @note added in 2.3
4+
*/
5+
class QgsFieldProxyModel : QSortFilterProxyModel
6+
{
7+
8+
%TypeHeaderCode
9+
#include "qgsfieldproxymodel.h"
10+
%End
11+
12+
public:
13+
enum Filter
14+
{
15+
String = 1,
16+
Int = 2,
17+
LongLong = 4,
18+
Double = 8,
19+
Numeric = 14,
20+
Date = 16,
21+
All = 31
22+
};
23+
typedef QFlags<QgsFieldProxyModel::Filter> Filters;
24+
25+
/**
26+
* @brief QgsFieldProxModel creates a proxy model with a QgsFieldModel as source model.
27+
* It can be used to filter the fields based on their types.
28+
*/
29+
explicit QgsFieldProxyModel( QObject *parent /TransferThis/ = 0 );
30+
31+
//! sourceFieldModel returns the QgsFieldModel used in this QSortFilterProxyModel
32+
QgsFieldModel* sourceFieldModel() ;
33+
34+
/**
35+
* @brief setFilters set flags that affect how fields are filtered
36+
* @param filters are Filter flags
37+
* @note added in 2.3
38+
*/
39+
QgsFieldProxyModel* setFilters( Filters filters );
40+
const Filters& filters() const ;
41+
42+
// QSortFilterProxyModel interface
43+
public:
44+
bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const;
45+
bool lessThan( const QModelIndex &left, const QModelIndex &right ) const;
46+
};
47+

src/gui/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ qgsfieldcombobox.cpp
9292
qgsfieldexpressionwidget.cpp
9393
qgsfieldmodel.cpp
9494
qgsfieldvalidator.cpp
95+
qgsfieldproxymodel.cpp
9596
qgsfiledropedit.cpp
9697
qgsfilterlineedit.cpp
9798
qgsformannotationitem.cpp
@@ -238,6 +239,7 @@ qgsfieldcombobox.h
238239
qgsfieldexpressionwidget.h
239240
qgsfieldmodel.h
240241
qgsfieldvalidator.h
242+
qgsfieldproxymodel.h
241243
qgsfilterlineedit.h
242244
qgsformannotationitem.h
243245
qgsgenericprojectionselector.h
@@ -310,6 +312,7 @@ qgsfieldcombobox.h
310312
qgsfieldexpressionwidget.h
311313
qgsfieldmodel.h
312314
qgsfieldvalidator.h
315+
qgsfieldproxymodel.h
313316
qgsfiledropedit.h
314317
qgsfilterlineedit.h
315318
qgsgenericprojectionselector.h

src/gui/qgsfieldcombobox.cpp

+27-13
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,24 @@
1414
***************************************************************************/
1515

1616
#include "qgsfieldcombobox.h"
17-
#include "qgsfieldmodel.h"
17+
#include "qgsfieldproxymodel.h"
1818
#include "qgsmaplayer.h"
19+
#include "qgsvectorlayer.h"
1920

2021
QgsFieldComboBox::QgsFieldComboBox( QWidget *parent ) :
2122
QComboBox( parent )
2223
{
23-
mFieldModel = new QgsFieldModel( this );
24-
setModel( mFieldModel );
24+
mFieldProxyModel = new QgsFieldProxyModel( this );
25+
setModel( mFieldProxyModel );
2526

2627
connect( this, SIGNAL( currentIndexChanged( int ) ), this, SLOT( indexChanged( int ) ) );
2728
}
2829

30+
void QgsFieldComboBox::setFilters( QgsFieldProxyModel::Filters filters )
31+
{
32+
mFieldProxyModel->setFilters( filters );
33+
}
34+
2935
void QgsFieldComboBox::setLayer( QgsMapLayer *layer )
3036
{
3137
QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( layer );
@@ -37,38 +43,46 @@ void QgsFieldComboBox::setLayer( QgsMapLayer *layer )
3743

3844
void QgsFieldComboBox::setLayer( QgsVectorLayer *layer )
3945
{
40-
mFieldModel->setLayer( layer );
46+
mFieldProxyModel->sourceFieldModel()->setLayer( layer );
4147
}
4248

4349
QgsVectorLayer *QgsFieldComboBox::layer()
4450
{
45-
return mFieldModel->layer();
51+
return mFieldProxyModel->sourceFieldModel()->layer();
4652
}
4753

4854
void QgsFieldComboBox::setField( QString fieldName )
4955
{
50-
QModelIndex idx = mFieldModel->indexFromName( fieldName );
56+
QModelIndex idx = mFieldProxyModel->sourceFieldModel()->indexFromName( fieldName );
5157
if ( idx.isValid() )
5258
{
53-
setCurrentIndex( idx.row() );
54-
}
55-
else
56-
{
57-
setCurrentIndex( -1 );
59+
QModelIndex proxyIdx = mFieldProxyModel->mapFromSource( idx );
60+
if ( proxyIdx.isValid() )
61+
{
62+
setCurrentIndex( idx.row() );
63+
return;
64+
}
5865
}
66+
setCurrentIndex( -1 );
5967
}
6068

6169
QString QgsFieldComboBox::currentField()
6270
{
6371
int i = currentIndex();
6472

65-
const QModelIndex index = mFieldModel->index( i, 0 );
73+
const QModelIndex proxyIndex = mFieldProxyModel->index( i, 0 );
74+
if ( !proxyIndex.isValid() )
75+
{
76+
return "";
77+
}
78+
79+
const QModelIndex index = mFieldProxyModel->mapToSource( proxyIndex );
6680
if ( !index.isValid() )
6781
{
6882
return "";
6983
}
7084

71-
QString name = mFieldModel->data( index, QgsFieldModel::FieldNameRole ).toString();
85+
QString name = mFieldProxyModel->data( index, QgsFieldModel::FieldNameRole ).toString();
7286
return name;
7387
}
7488

src/gui/qgsfieldcombobox.h

+11-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818

1919
#include <QComboBox>
2020

21-
class QgsFieldModel;
21+
#include "qgsfieldproxymodel.h"
22+
2223
class QgsMapLayer;
2324
class QgsVectorLayer;
2425

@@ -32,13 +33,21 @@ class QgsVectorLayer;
3233
class GUI_EXPORT QgsFieldComboBox : public QComboBox
3334
{
3435
Q_OBJECT
36+
Q_PROPERTY( QgsFieldProxyModel::Filters filters READ filters WRITE setFilters )
37+
3538
public:
3639
/**
3740
* @brief QgsFieldComboBox creates a combo box to display the fields of a layer.
3841
* The layer can be either manually given or dynamically set by connecting the signal QgsMapLayerComboBox::layerChanged to the slot setLayer.
3942
*/
4043
explicit QgsFieldComboBox( QWidget *parent = 0 );
4144

45+
//! setFilters allows fitering according to the type of field
46+
void setFilters( QgsFieldProxyModel::Filters filters );
47+
48+
//! currently used filter on list of fields
49+
QgsFieldProxyModel::Filters filters() { return mFieldProxyModel->filters(); }
50+
4251
//! return the currently selected field
4352
QString currentField();
4453

@@ -63,7 +72,7 @@ class GUI_EXPORT QgsFieldComboBox : public QComboBox
6372
void indexChanged( int i );
6473

6574
private:
66-
QgsFieldModel* mFieldModel;
75+
QgsFieldProxyModel* mFieldProxyModel;
6776
};
6877

6978
#endif // QGSFIELDCOMBOBOX_H

src/gui/qgsfieldexpressionwidget.cpp

+25-16
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#include "qgsapplication.h"
2020
#include "qgsfieldexpressionwidget.h"
2121
#include "qgsexpressionbuilderdialog.h"
22-
#include "qgsfieldmodel.h"
22+
#include "qgsfieldproxymodel.h"
2323
#include "qgsdistancearea.h"
2424

2525
QgsFieldExpressionWidget::QgsFieldExpressionWidget( QWidget *parent )
@@ -32,9 +32,9 @@ QgsFieldExpressionWidget::QgsFieldExpressionWidget( QWidget *parent )
3232
mCombo = new QComboBox( this );
3333
mCombo->setEditable( true );
3434
mCombo->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Minimum );
35-
mFieldModel = new QgsFieldModel( mCombo );
36-
mFieldModel->setAllowExpression( true );
37-
mCombo->setModel( mFieldModel );
35+
mFieldProxyModel = new QgsFieldProxyModel( mCombo );
36+
mFieldProxyModel->sourceFieldModel()->setAllowExpression( true );
37+
mCombo->setModel( mFieldProxyModel );
3838

3939
mButton = new QToolButton( this );
4040
mButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
@@ -59,6 +59,11 @@ void QgsFieldExpressionWidget::setExpressionDialogTitle( QString title )
5959
mExpressionDialogTitle = title;
6060
}
6161

62+
void QgsFieldExpressionWidget::setFilters( QgsFieldProxyModel::Filters filters )
63+
{
64+
mFieldProxyModel->setFilters( filters );
65+
}
66+
6267
void QgsFieldExpressionWidget::setGeomCalculator( const QgsDistanceArea &da )
6368
{
6469
mDa = QSharedPointer<const QgsDistanceArea>( new QgsDistanceArea( da ) );
@@ -76,27 +81,28 @@ QString QgsFieldExpressionWidget::currentField( bool *isExpression , bool *isVal
7681
}
7782

7883
int i = mCombo->currentIndex();
79-
const QModelIndex index = mFieldModel->index( i, 0 );
84+
const QModelIndex proxyIndex = mFieldProxyModel->index( i, 0 );
85+
if ( !proxyIndex.isValid() )
86+
return "";
87+
const QModelIndex index = mFieldProxyModel->mapToSource( proxyIndex );
8088
if ( !index.isValid() )
81-
{
8289
return "";
83-
}
8490

8591
if ( isExpression )
8692
{
87-
*isExpression = mFieldModel->data( index, QgsFieldModel::IsExpressionRole ).toBool();
93+
*isExpression = mFieldProxyModel->data( index, QgsFieldModel::IsExpressionRole ).toBool();
8894
}
8995
if ( isValid )
9096
{
91-
*isValid = mFieldModel->data( index, QgsFieldModel::ExpressionValidityRole ).toBool();
97+
*isValid = mFieldProxyModel->data( index, QgsFieldModel::ExpressionValidityRole ).toBool();
9298
}
93-
QString expression = mFieldModel->data( index, QgsFieldModel::ExpressionRole ).toString();
99+
QString expression = mFieldProxyModel->data( index, QgsFieldModel::ExpressionRole ).toString();
94100
return expression;
95101
}
96102

97103
QgsVectorLayer *QgsFieldExpressionWidget::layer()
98104
{
99-
return mFieldModel->layer();
105+
return mFieldProxyModel->sourceFieldModel()->layer();
100106
}
101107

102108
void QgsFieldExpressionWidget::setLayer( QgsMapLayer *layer )
@@ -110,21 +116,24 @@ void QgsFieldExpressionWidget::setLayer( QgsMapLayer *layer )
110116

111117
void QgsFieldExpressionWidget::setLayer( QgsVectorLayer *layer )
112118
{
113-
mFieldModel->setLayer( layer );
119+
mFieldProxyModel->sourceFieldModel()->setLayer( layer );
114120
}
115121

116122
void QgsFieldExpressionWidget::setField( const QString fieldName )
117123
{
118124
if ( fieldName.isEmpty() )
119125
return;
120126

121-
QModelIndex idx = mFieldModel->indexFromName( fieldName );
127+
QModelIndex idx = mFieldProxyModel->sourceFieldModel()->indexFromName( fieldName );
122128
if ( !idx.isValid() )
123129
{
124130
// new expression
125-
idx = mFieldModel->setExpression( fieldName );
131+
idx = mFieldProxyModel->sourceFieldModel()->setExpression( fieldName );
126132
}
127-
mCombo->setCurrentIndex( idx.row() );
133+
134+
QModelIndex proxyIndex = mFieldProxyModel->mapFromSource( idx );
135+
136+
mCombo->setCurrentIndex( proxyIndex.row() );
128137

129138
currentFieldChanged();
130139
}
@@ -159,7 +168,7 @@ void QgsFieldExpressionWidget::expressionEdited( const QString expression )
159168
void QgsFieldExpressionWidget::expressionEditingFinished()
160169
{
161170
const QString expression = mCombo->lineEdit()->text();
162-
QModelIndex idx = mFieldModel->setExpression( expression );
171+
QModelIndex idx = mFieldProxyModel->sourceFieldModel()->setExpression( expression );
163172
mCombo->setCurrentIndex( idx.row() );
164173
currentFieldChanged();
165174
}

0 commit comments

Comments
 (0)