Skip to content

Commit 2797ed7

Browse files
committed
Merge pull request #2743 from 3nids/testfieldwidget2
Fix label expression/field lose when removing a join in layer properties
2 parents 793e7b2 + d6169b8 commit 2797ed7

11 files changed

+203
-19
lines changed

python/core/qgsvectorlayer.sip

+3-2
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,9 @@ class QgsVectorLayer : QgsMapLayer
446446
@note since 2.6 returns bool indicating whether the join can be added */
447447
bool addJoin( const QgsVectorJoinInfo& joinInfo );
448448

449-
/** Removes a vector layer join */
450-
void removeJoin( const QString& joinLayerId );
449+
/** Removes a vector layer join
450+
@returns true if join was found and successfully removed */
451+
bool removeJoin( const QString& joinLayerId );
451452

452453
const QList<QgsVectorJoinInfo> vectorJoins() const;
453454

python/core/qgsvectorlayerjoinbuffer.sip

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ class QgsVectorLayerJoinBuffer : QObject
1212
@return (since 2.6) whether the join was successfully added */
1313
bool addJoin( const QgsVectorJoinInfo& joinInfo );
1414

15-
/** Removes a vector layer join*/
16-
void removeJoin( const QString& joinLayerId );
15+
/** Removes a vector layer join
16+
@returns true if join was found and successfully removed */
17+
bool removeJoin( const QString& joinLayerId );
1718

1819
/** Updates field map with joined attributes
1920
@param fields map to append joined attributes

src/core/qgsvectorlayer.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -2764,10 +2764,14 @@ void QgsVectorLayer::checkJoinLayerRemove( const QString& theLayerId )
27642764
removeJoin( theLayerId );
27652765
}
27662766

2767-
void QgsVectorLayer::removeJoin( const QString& joinLayerId )
2767+
bool QgsVectorLayer::removeJoin( const QString& joinLayerId )
27682768
{
2769+
bool res = false;
27692770
if ( mJoinBuffer )
2770-
mJoinBuffer->removeJoin( joinLayerId );
2771+
{
2772+
res = mJoinBuffer->removeJoin( joinLayerId );
2773+
}
2774+
return res;
27712775
}
27722776

27732777
const QList< QgsVectorJoinInfo > QgsVectorLayer::vectorJoins() const

src/core/qgsvectorlayer.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -554,8 +554,9 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
554554
@note since 2.6 returns bool indicating whether the join can be added */
555555
bool addJoin( const QgsVectorJoinInfo& joinInfo );
556556

557-
/** Removes a vector layer join */
558-
void removeJoin( const QString& joinLayerId );
557+
/** Removes a vector layer join
558+
@returns true if join was found and successfully removed */
559+
bool removeJoin( const QString& joinLayerId );
559560

560561
const QList<QgsVectorJoinInfo> vectorJoins() const;
561562

src/core/qgsvectorlayerjoinbuffer.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -94,20 +94,25 @@ bool QgsVectorLayerJoinBuffer::addJoin( const QgsVectorJoinInfo& joinInfo )
9494
}
9595

9696

97-
void QgsVectorLayerJoinBuffer::removeJoin( const QString& joinLayerId )
97+
bool QgsVectorLayerJoinBuffer::removeJoin( const QString& joinLayerId )
9898
{
99+
bool res = false;
99100
for ( int i = 0; i < mVectorJoins.size(); ++i )
100101
{
101102
if ( mVectorJoins.at( i ).joinLayerId == joinLayerId )
102103
{
103104
mVectorJoins.removeAt( i );
105+
res = true;
104106
}
105107
}
106108

107109
if ( QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinLayerId ) ) )
110+
{
108111
disconnect( vl, SIGNAL( updatedFields() ), this, SLOT( joinedLayerUpdatedFields() ) );
112+
}
109113

110114
emit joinedFieldsChanged();
115+
return res;
111116
}
112117

113118
void QgsVectorLayerJoinBuffer::cacheJoinLayer( QgsVectorJoinInfo& joinInfo )

src/core/qgsvectorlayerjoinbuffer.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ class CORE_EXPORT QgsVectorLayerJoinBuffer : public QObject
4141
@return (since 2.6) whether the join was successfully added */
4242
bool addJoin( const QgsVectorJoinInfo& joinInfo );
4343

44-
/** Removes a vector layer join*/
45-
void removeJoin( const QString& joinLayerId );
44+
/** Removes a vector layer join
45+
@returns true if join was found and successfully removed */
46+
bool removeJoin( const QString& joinLayerId );
4647

4748
/** Updates field map with joined attributes
4849
@param fields map to append joined attributes

src/gui/qgsfieldexpressionwidget.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ QgsFieldExpressionWidget::QgsFieldExpressionWidget( QWidget *parent )
5858
connect( mCombo->lineEdit(), SIGNAL( editingFinished() ), this, SLOT( expressionEditingFinished() ) );
5959
connect( mCombo, SIGNAL( activated( int ) ), this, SLOT( currentFieldChanged() ) );
6060
connect( mButton, SIGNAL( clicked() ), this, SLOT( editExpression() ) );
61+
connect( mFieldProxyModel, SIGNAL( modelAboutToBeReset() ), this, SLOT( beforeResetModel() ) );
62+
connect( mFieldProxyModel, SIGNAL( modelReset() ), this, SLOT( afterResetModel() ) );
6163
// NW TODO - Fix in 2.6
6264
// connect( mCombo->lineEdit(), SIGNAL( returnPressed() ), this, SIGNAL( returnPressed() ) );
6365

@@ -148,13 +150,17 @@ void QgsFieldExpressionWidget::setLayer( QgsMapLayer *layer )
148150

149151
void QgsFieldExpressionWidget::setLayer( QgsVectorLayer *layer )
150152
{
153+
disconnect( mFieldProxyModel->sourceFieldModel()->layer(), SIGNAL( updatedFields() ), this, SLOT( reloadLayer() ) );
154+
151155
mExpressionContext.reset( new QgsExpressionContext() );
152156
mExpressionContext->appendScope( QgsExpressionContextUtils::globalScope() );
153157
mExpressionContext->appendScope( QgsExpressionContextUtils::projectScope() );
154158
if ( layer )
155159
mExpressionContext->appendScope( QgsExpressionContextUtils::layerScope( layer ) );
156160

157161
mFieldProxyModel->sourceFieldModel()->setLayer( layer );
162+
163+
connect( mFieldProxyModel->sourceFieldModel()->layer(), SIGNAL( updatedFields() ), SLOT( reloadLayer() ), Qt::UniqueConnection );
158164
}
159165

160166
void QgsFieldExpressionWidget::setField( const QString &fieldName )
@@ -231,6 +237,23 @@ void QgsFieldExpressionWidget::changeEvent( QEvent* event )
231237
}
232238
}
233239

240+
void QgsFieldExpressionWidget::reloadLayer()
241+
{
242+
setLayer( mFieldProxyModel->sourceFieldModel()->layer() );
243+
}
244+
245+
void QgsFieldExpressionWidget::beforeResetModel()
246+
{
247+
// Backup expression
248+
mBackupExpression = mCombo->currentText();
249+
}
250+
251+
void QgsFieldExpressionWidget::afterResetModel()
252+
{
253+
// Restore expression
254+
mCombo->lineEdit()->setText( mBackupExpression );
255+
}
256+
234257
void QgsFieldExpressionWidget::currentFieldChanged()
235258
{
236259
updateLineEditStyle();

src/gui/qgsfieldexpressionwidget.h

+9
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@ class GUI_EXPORT QgsFieldExpressionWidget : public QWidget
147147
protected:
148148
void changeEvent( QEvent* event ) override;
149149

150+
private slots:
151+
void reloadLayer();
152+
153+
void beforeResetModel();
154+
void afterResetModel();
155+
150156
private:
151157
QComboBox* mCombo;
152158
QToolButton* mButton;
@@ -156,6 +162,9 @@ class GUI_EXPORT QgsFieldExpressionWidget : public QWidget
156162
QScopedPointer< QgsExpressionContext > mExpressionContext;
157163
ExpressionContextCallback mExpressionContextCallback;
158164
const void* mExpressionContextCallbackContext;
165+
QString mBackupExpression;
166+
167+
friend class TestQgsFieldExpressionWidget;
159168
};
160169

161170
#endif // QGSFIELDEXPRESSIONWIDGET_H

src/gui/qgsfieldmodel.h

+7-8
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ class GUI_EXPORT QgsFieldModel : public QAbstractItemModel
6767
//! returns the currently used layer
6868
QgsVectorLayer* layer() { return mLayer; }
6969

70+
// QAbstractItemModel interface
71+
QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const override;
72+
QModelIndex parent( const QModelIndex &child ) const override;
73+
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
74+
int columnCount( const QModelIndex &parent ) const override;
75+
QVariant data( const QModelIndex &index, int role ) const override;
76+
7077
public slots:
7178
//! set the layer of whch fields are displayed
7279
void setLayer( QgsVectorLayer *layer );
@@ -86,14 +93,6 @@ class GUI_EXPORT QgsFieldModel : public QAbstractItemModel
8693

8794
private:
8895
void fetchFeature();
89-
90-
// QAbstractItemModel interface
91-
public:
92-
QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const override;
93-
QModelIndex parent( const QModelIndex &child ) const override;
94-
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
95-
int columnCount( const QModelIndex &parent ) const override;
96-
QVariant data( const QModelIndex &index, int role ) const override;
9796
};
9897

9998
#endif // QGSFIELDMODEL_H

tests/src/gui/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ ADD_QGIS_TEST(zoomtest testqgsmaptoolzoom.cpp)
123123
#ADD_QGIS_TEST(histogramtest testqgsrasterhistogram.cpp)
124124
ADD_QGIS_TEST(doublespinbox testqgsdoublespinbox.cpp)
125125
ADD_QGIS_TEST(dualviewtest testqgsdualview.cpp )
126+
ADD_QGIS_TEST(fieldexpressionwidget testqgsfieldexpressionwidget.cpp )
126127
ADD_QGIS_TEST(filewidget testqgsfilewidget.cpp )
127128
ADD_QGIS_TEST(mapcanvastest testqgsmapcanvas.cpp )
128129
ADD_QGIS_TEST(projectionissues testprojectionissues.cpp)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/***************************************************************************
2+
testqgsfieldexpressionwidget.cpp
3+
--------------------------------------
4+
Date : January 2016
5+
Copyright : (C) 2016 Denis Rouzaud
6+
Email : denis.rouzaud@gmail.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+
16+
17+
#include <QtTest/QtTest>
18+
#include <QObject>
19+
20+
//qgis includes...
21+
#include <qgsvectorlayer.h>
22+
#include <qgsapplication.h>
23+
#include <qgsvectorlayerjoinbuffer.h>
24+
#include <qgsmaplayerregistry.h>
25+
#include <qgsfieldexpressionwidget.h>
26+
#include <qgsproject.h>
27+
28+
/** @ingroup UnitTests
29+
* This is a unit test for the field expression widget
30+
*
31+
* @see QgsFieldExpressionWidget
32+
*/
33+
class TestQgsFieldExpressionWidget : public QObject
34+
{
35+
Q_OBJECT
36+
37+
public:
38+
TestQgsFieldExpressionWidget()
39+
: mLayerA( nullptr )
40+
, mLayerB( nullptr )
41+
{}
42+
43+
private slots:
44+
void initTestCase(); // will be called before the first testfunction is executed.
45+
void cleanupTestCase(); // will be called after the last testfunction was executed.
46+
void init(); // will be called before each testfunction is executed.
47+
void cleanup(); // will be called after every testfunction.
48+
49+
void testRemoveJoin();
50+
51+
private:
52+
QgsFieldExpressionWidget* mWidget;
53+
QgsVectorLayer* mLayerA;
54+
QgsVectorLayer* mLayerB;
55+
};
56+
57+
// runs before all tests
58+
void TestQgsFieldExpressionWidget::initTestCase()
59+
{
60+
QgsApplication::init();
61+
QgsApplication::initQgis();
62+
63+
// Set up the QSettings environment
64+
QCoreApplication::setOrganizationName( "QGIS" );
65+
QCoreApplication::setOrganizationDomain( "qgis.org" );
66+
QCoreApplication::setApplicationName( "QGIS-TEST" );
67+
68+
// Create memory layers
69+
// LAYER A //
70+
mLayerA = new QgsVectorLayer( "Point?field=id_a:integer", "A", "memory" );
71+
QVERIFY( mLayerA->isValid() );
72+
QVERIFY( mLayerA->fields().count() == 1 );
73+
QgsMapLayerRegistry::instance()->addMapLayer( mLayerA );
74+
// LAYER B //
75+
mLayerB = new QgsVectorLayer( "Point?field=id_b:integer&field=value_b", "B", "memory" );
76+
QVERIFY( mLayerB->isValid() );
77+
QVERIFY( mLayerB->fields().count() == 2 );
78+
QgsMapLayerRegistry::instance()->addMapLayer( mLayerB );
79+
80+
// init widget
81+
mWidget = new QgsFieldExpressionWidget();
82+
mWidget->setLayer( mLayerA );
83+
84+
85+
}
86+
87+
void TestQgsFieldExpressionWidget::init()
88+
{
89+
}
90+
91+
void TestQgsFieldExpressionWidget::cleanup()
92+
{
93+
}
94+
95+
void TestQgsFieldExpressionWidget::cleanupTestCase()
96+
{
97+
QgsApplication::exitQgis();
98+
}
99+
100+
void TestQgsFieldExpressionWidget::testRemoveJoin()
101+
{
102+
103+
QVERIFY( mLayerA->fields().count() == 1 );
104+
105+
QgsVectorJoinInfo joinInfo;
106+
joinInfo.targetFieldName = "id_a";
107+
joinInfo.joinLayerId = mLayerB->id();
108+
joinInfo.joinFieldName = "id_b";
109+
joinInfo.memoryCache = false;
110+
joinInfo.prefix = "B_";
111+
mLayerA->addJoin( joinInfo );
112+
113+
QVERIFY( mLayerA->fields().count() == 2 );
114+
115+
const QString expr = "'hello '|| B_value_b";
116+
mWidget->setField( expr );
117+
118+
bool isExpression, isValid;
119+
QVERIFY( mWidget->isValidExpression() );
120+
QCOMPARE( mWidget->currentField( &isExpression, &isValid ), expr );
121+
QVERIFY( isExpression );
122+
QVERIFY( isValid );
123+
124+
QVERIFY( mLayerA->removeJoin( mLayerB->id() ) );
125+
126+
QVERIFY( mLayerA->fields().count() == 1 );
127+
128+
QCOMPARE( mWidget->mCombo->currentText(), expr );
129+
130+
QCOMPARE( mWidget->currentField( &isExpression, &isValid ), expr );
131+
QVERIFY( isExpression );
132+
// QVERIFY( !isValid ); TODO: the expression should not be valid anymore since the field doesn't exist anymore. Maybe we need a new expression method to get more details.
133+
}
134+
135+
136+
QTEST_MAIN( TestQgsFieldExpressionWidget )
137+
#include "testqgsfieldexpressionwidget.moc"
138+
139+

0 commit comments

Comments
 (0)