Skip to content

Commit 58ea211

Browse files
authored
Streamline expression context generation (#3350)
* Save more data to QML * Virtual fields * Map tips * Display expression * Read only flag * Streamline expression context generation Whenever an object is able to generate an expression context it implements the method createExpressionContext() declared in QgsExpressionContextGenerator. This makes a cleaner API and allows using QgsFieldExpressionWidget and QgsDataDefinedButton from python because standard OO programming approaches are used instead of callbacks and void pointers. * Colorize output of doc and sip tests * Fix build * Fix sip complaints * Fix rebase problems * Workaround failing bindings test
1 parent f3e90f1 commit 58ea211

File tree

102 files changed

+643
-659
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+643
-659
lines changed

ci/travis/linux/qt4/before_install.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ curl -L https://github.com/opengisch/osgeo4travis/archive/qt4bin.tar.gz | tar -x
2121
curl -L https://cmake.org/files/v3.5/cmake-3.5.0-Linux-x86_64.tar.gz | tar --strip-components=1 -zxC /home/travis/osgeo4travis
2222

2323
popd
24-
pip install --user autopep8 nose2 pyyaml mock future
24+
pip install --user autopep8 nose2 pyyaml mock future termcolor

ci/travis/linux/qt5/before_install.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ curl -L https://github.com/opengisch/osgeo4travis/archive/qt5bin.tar.gz | tar -x
2828
curl -L https://cmake.org/files/v3.5/cmake-3.5.0-Linux-x86_64.tar.gz | tar --strip-components=1 -zxC /home/travis/osgeo4travis
2929
popd
3030

31-
pip install psycopg2 numpy nose2 pyyaml mock future
31+
pip install psycopg2 numpy nose2 pyyaml mock future termcolor

doc/api_break.dox

+12
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,18 @@ be returned in place of a null pointer.</li>
393393
QgsExpressionContext variables should be used in their place.</li>
394394
</ul>
395395

396+
\subsection qgis_api_break_3_0_QgsDataDefinedButton QgsDataDefinedButton
397+
398+
<ul>
399+
<li>registerGetExpressionContextCallback has been removed in favor of registerExpressionContextGenerator</li>
400+
</ul>
401+
402+
\subsection qgis_api_break_3_0_QgsFieldExpressionWidget QgsFieldExpressionWidget
403+
404+
<ul>
405+
<li>registerGetExpressionContextCallback has been removed in favor of registerExpressionContextGenerator</li>
406+
</ul>
407+
396408
\subsection qgis_api_break_3_0_QgsDataDefinedSymbolDialog QgsDataDefinedSymbolDialog
397409

398410
<ul>

python/core/composer/qgscomposerattributetablev2.sip

+1-1
Original file line numberDiff line numberDiff line change
@@ -281,5 +281,5 @@ class QgsComposerAttributeTableV2 : QgsComposerTableV2
281281
*/
282282
bool getTableContents( QgsComposerTableContents &contents );
283283

284-
virtual QgsExpressionContext* createExpressionContext() const /Factory/;
284+
virtual QgsExpressionContext createExpressionContext() const;
285285
};

python/core/composer/qgscomposerframe.sip

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,5 @@ class QgsComposerFrame: QgsComposerItem
7878
*/
7979
bool isEmpty() const;
8080

81-
virtual QgsExpressionContext* createExpressionContext() const;
81+
virtual QgsExpressionContext createExpressionContext() const;
8282
};

python/core/composer/qgscomposeritem.sip

+1-1
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ class QgsComposerItem : QgsComposerObject, QGraphicsRectItem
645645
* scopes for global, project, composition, atlas and item properties.
646646
* @note added in QGIS 2.12
647647
*/
648-
QgsExpressionContext* createExpressionContext() const /Factory/;
648+
QgsExpressionContext createExpressionContext() const;
649649

650650
public slots:
651651
/** Sets the item rotation

python/core/composer/qgscomposermap.sip

+1-1
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ class QgsComposerMap : QgsComposerItem
769769
* @note added in 2.6 */
770770
void requestedExtent( QgsRectangle& extent ) const;
771771

772-
virtual QgsExpressionContext* createExpressionContext() const;
772+
virtual QgsExpressionContext createExpressionContext() const;
773773

774774
signals:
775775
void extentChanged();

python/core/composer/qgscomposermapgrid.sip

+1-1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,6 @@ class QgsComposerMapGrid : QgsComposerMapItem
796796
*/
797797
QColor frameFillColor2() const;
798798

799-
virtual QgsExpressionContext* createExpressionContext() const;
799+
virtual QgsExpressionContext createExpressionContext() const;
800800

801801
};

python/core/composer/qgscomposerobject.sip

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class QgsComposerObject : QObject
142142
* scopes for global, project and composition properties.
143143
* @note added in QGIS 2.12
144144
*/
145-
virtual QgsExpressionContext* createExpressionContext() const /Factory/;
145+
virtual QgsExpressionContext createExpressionContext() const;
146146

147147
public slots:
148148

python/core/composer/qgscomposition.sip

+1-1
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,7 @@ class QgsComposition : QGraphicsScene
845845
* scopes for global, project, composition and atlas properties.
846846
* @note added in QGIS 2.12
847847
*/
848-
QgsExpressionContext* createExpressionContext() const;
848+
QgsExpressionContext createExpressionContext() const;
849849

850850
protected:
851851
void init();

python/core/core.sip

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
%Include qgserror.sip
5050
%Include qgsexpression.sip
5151
%Include qgsexpressioncontext.sip
52+
%Include qgsexpressioncontextgenerator.sip
5253
%Include qgsfeature.sip
5354
%Include qgsfeaturefilterprovider.sip
5455
%Include qgsfeatureiterator.sip
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/***************************************************************************
2+
qgsexpressioncontextgenerator.sip - QgsExpressionContextGenerator
3+
4+
---------------------
5+
begin : 1.8.2016
6+
copyright : (C) 2016 by Matthias Kuhn
7+
email : matthias@opengis.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+
/**
17+
* \ingroup core
18+
* Abstract interface for generating an expression context.
19+
*
20+
* You need to implement this interface in a class and register this class with
21+
* QgsFieldExpressionWidget::registerExpressionGenerator().
22+
*
23+
* Whenever this widget requires an expression context it will call the createExpressionContext()
24+
* method to get a context.
25+
*
26+
* @note added in QGIS 3.0
27+
*/
28+
29+
class QgsExpressionContextGenerator
30+
{
31+
%TypeHeaderCode
32+
#include "qgsexpressioncontextgenerator.h"
33+
%End
34+
35+
public:
36+
/**
37+
* This method needs to be reimplemented in all classes which implement this interface
38+
* and return an expression context.
39+
*/
40+
virtual QgsExpressionContext createExpressionContext() const = 0;
41+
};

python/core/qgsproject.sip

+2
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,8 @@ class QgsProject : QObject
324324
*/
325325
void setEvaluateDefaultValues( bool evaluateDefaultValues );
326326

327+
QgsExpressionContext createExpressionContext() const;
328+
327329
protected:
328330

329331
/** Set error message from read/write operation

python/core/qgsvectorlayer.sip

+2
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,8 @@ class QgsVectorLayer : QgsMapLayer
13851385
*/
13861386
void setMapTipTemplate( const QString& mapTipTemplate );
13871387

1388+
QgsExpressionContext createExpressionContext() const;
1389+
13881390
public slots:
13891391
/**
13901392
* Select feature by its ID

python/gui/qgsdatadefinedbutton.sip

+7-10
Original file line numberDiff line numberDiff line change
@@ -185,17 +185,14 @@ class QgsDataDefinedButton : QToolButton
185185
*/
186186
void clearCheckedWidgets();
187187

188-
//! Callback function for retrieving the expression context for the button
189-
//typedef QgsExpressionContext( *ExpressionContextCallback )( const void* context );
190-
191-
/** Register callback function for retrieving the expression context for the button
192-
* @param fnGetExpressionContext call back function, will be called when the data defined
193-
* button requires the current expression context
194-
* @param context context for callback function
195-
* @note added in QGIS 2.12
196-
* @note not available in Python bindings
188+
/**
189+
* Register an expression context generator class that will be used to retrieve
190+
* an expression context for the button.
191+
* @param generator A QgsExpressionContextGenerator class that will be used to
192+
* create an expression context when required.
193+
* @note added in QGIS 3.0
197194
*/
198-
//void registerGetExpressionContextCallback( ExpressionContextCallback fnGetExpressionContext, const void* context );
195+
void registerExpressionContextGenerator( QgsExpressionContextGenerator* generator );
199196

200197
/**
201198
* Sets an assistant used to define the data defined object properties.

python/gui/qgsfieldexpressionwidget.sip

+7-10
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,14 @@ class QgsFieldExpressionWidget : QWidget
5656
//! Returns the currently used layer
5757
QgsVectorLayer* layer() const;
5858

59-
//! Callback function for retrieving the expression context for the expression
60-
//typedef QgsExpressionContext( *ExpressionContextCallback )( const void* context );
61-
62-
/** Register callback function for retrieving the expression context for the expression
63-
* @param fnGetExpressionContext call back function, will be called when the widget requires
64-
* the current expression context
65-
* @param context context for callback function
66-
* @note added in QGIS 2.12
67-
* @note not available in Python bindings
59+
/**
60+
* Register an expression context generator class that will be used to retrieve
61+
* an expression context for the widget.
62+
* @param generator A QgsExpressionContextGenerator class that will be used to
63+
* create an expression context when required.
64+
* @note added in QGIS 3.0
6865
*/
69-
//void registerGetExpressionContextCallback( ExpressionContextCallback fnGetExpressionContext, const void* context );
66+
void registerExpressionContextGenerator( QgsExpressionContextGenerator* generator );
7067

7168
signals:
7269
//! the signal is emitted when the currently selected field changes

python/gui/symbology-ng/qgsrendererwidget.sip

+7-1
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,15 @@ class QgsDataDefinedValueDialog : QDialog
122122
void dataDefinedChanged();
123123

124124
protected:
125-
QgsDataDefined symbolDataDefined() const;
125+
/**
126+
* Should be called in the constructor of child classes.
127+
*
128+
* @note May be missing Python bindings depending on the platform.
129+
*/
126130
void init( const QString& description ); // needed in children ctor to call virtual
127131

132+
private:
133+
QgsDataDefined symbolDataDefined() const;
128134
virtual QgsDataDefined symbolDataDefined( const QgsSymbol* ) const = 0;
129135
virtual double value( const QgsSymbol* ) const = 0;
130136
virtual void setDataDefined( QgsSymbol* symbol, const QgsDataDefined& dd ) = 0;

python/gui/symbology-ng/qgssymbollayerwidget.sip

+2-8
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,9 @@ class QgsSymbolLayerWidget : QWidget
5151
void setExpressionContext( QgsExpressionContext* context );
5252

5353
protected:
54+
void registerDataDefinedButton( QgsDataDefinedButton* button, const QString& propertyName, QgsDataDefinedButton::DataType type, const QString& description );
5455

55-
void registerDataDefinedButton( QgsDataDefinedButton * button, const QString & propertyName, QgsDataDefinedButton::DataType type, const QString & description );
56-
57-
/** Get label for data defined entry.
58-
* Implemented only for 'size' of marker symbols
59-
* @note added in 2.1
60-
* @deprecated no longer used
61-
*/
62-
virtual QString dataDefinedPropertyLabel( const QString &entryName ) /Deprecated/;
56+
QgsExpressionContext createExpressionContext() const;
6357

6458
signals:
6559
/**

python/gui/symbology-ng/qgssymbolslistwidget.sip

-6
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,4 @@ class QgsSymbolsListWidget : QWidget
6868

6969
signals:
7070
void changed();
71-
72-
protected:
73-
void populateSymbolView();
74-
void populateSymbols( const QStringList& symbols );
75-
void updateSymbolColor();
76-
void updateSymbolInfo();
7771
};

src/app/composer/qgsatlascompositionwidget.cpp

+5-17
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,6 @@
2626
#include "qgscomposermap.h"
2727
#include "qgsvectorlayer.h"
2828

29-
static QgsExpressionContext _getExpressionContext( const void* context )
30-
{
31-
const QgsComposition* composition = ( const QgsComposition* ) context;
32-
if ( !composition )
33-
{
34-
return QgsExpressionContext();
35-
}
36-
37-
QScopedPointer< QgsExpressionContext > expContext( composition->createExpressionContext() );
38-
return QgsExpressionContext( *expContext );
39-
}
40-
4129
QgsAtlasCompositionWidget::QgsAtlasCompositionWidget( QWidget* parent, QgsComposition* c ):
4230
QWidget( parent ), mComposition( c )
4331
{
@@ -58,7 +46,7 @@ QgsAtlasCompositionWidget::QgsAtlasCompositionWidget( QWidget* parent, QgsCompos
5846
// connect to updates
5947
connect( &mComposition->atlasComposition(), SIGNAL( parameterChanged() ), this, SLOT( updateGuiElements() ) );
6048

61-
mPageNameWidget->registerGetExpressionContextCallback( &_getExpressionContext, mComposition );
49+
mPageNameWidget->registerExpressionContextGenerator( mComposition );
6250

6351
updateGuiElements();
6452
}
@@ -133,8 +121,8 @@ void QgsAtlasCompositionWidget::on_mAtlasFilenameExpressionButton_clicked()
133121
return;
134122
}
135123

136-
QScopedPointer<QgsExpressionContext> context( mComposition->createExpressionContext() );
137-
QgsExpressionBuilderDialog exprDlg( atlasMap->coverageLayer(), mAtlasFilenamePatternEdit->text(), this, "generic", *context );
124+
QgsExpressionContext context = mComposition->createExpressionContext();
125+
QgsExpressionBuilderDialog exprDlg( atlasMap->coverageLayer(), mAtlasFilenamePatternEdit->text(), this, "generic", context );
138126
exprDlg.setWindowTitle( tr( "Expression based filename" ) );
139127

140128
if ( exprDlg.exec() == QDialog::Accepted )
@@ -306,8 +294,8 @@ void QgsAtlasCompositionWidget::on_mAtlasFeatureFilterButton_clicked()
306294
return;
307295
}
308296

309-
QScopedPointer<QgsExpressionContext> context( mComposition->createExpressionContext() );
310-
QgsExpressionBuilderDialog exprDlg( vl, mAtlasFeatureFilterEdit->text(), this, "generic", *context );
297+
QgsExpressionContext context = mComposition->createExpressionContext();
298+
QgsExpressionBuilderDialog exprDlg( vl, mAtlasFeatureFilterEdit->text(), this, "generic", context );
311299
exprDlg.setWindowTitle( tr( "Expression based filter" ) );
312300

313301
if ( exprDlg.exec() == QDialog::Accepted )

src/app/composer/qgsattributeselectiondialog.cpp

+7-8
Original file line numberDiff line numberDiff line change
@@ -99,18 +99,17 @@ QgsComposerColumnSourceDelegate::QgsComposerColumnSourceDelegate( QgsVectorLayer
9999

100100
}
101101

102-
static QgsExpressionContext _getExpressionContext( const void* context )
102+
QgsExpressionContext QgsComposerColumnSourceDelegate::createExpressionContext() const
103103
{
104-
const QgsComposerObject* object = ( const QgsComposerObject* ) context;
105-
if ( !object )
104+
if ( !mComposerObject )
106105
{
107106
return QgsExpressionContext();
108107
}
109108

110-
QScopedPointer< QgsExpressionContext > expContext( object->createExpressionContext() );
111-
expContext->lastScope()->setVariable( "row_number", 1 );
112-
expContext->setHighlightedVariables( QStringList() << "row_number" );
113-
return QgsExpressionContext( *expContext );
109+
QgsExpressionContext expContext = mComposerObject->createExpressionContext();
110+
expContext.lastScope()->setVariable( "row_number", 1 );
111+
expContext.setHighlightedVariables( QStringList() << "row_number" );
112+
return expContext;
114113
}
115114

116115
QWidget* QgsComposerColumnSourceDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
@@ -120,7 +119,7 @@ QWidget* QgsComposerColumnSourceDelegate::createEditor( QWidget* parent, const Q
120119

121120
QgsFieldExpressionWidget *fieldExpression = new QgsFieldExpressionWidget( parent );
122121
fieldExpression->setLayer( mVectorLayer );
123-
fieldExpression->registerGetExpressionContextCallback( &_getExpressionContext, mComposerObject );
122+
fieldExpression->registerExpressionContextGenerator( this );
124123

125124
//listen out for field changes
126125
connect( fieldExpression, SIGNAL( fieldChanged( QString ) ), this, SLOT( commitAndCloseEditor() ) );

src/app/composer/qgsattributeselectiondialog.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <QSet>
2424
#include <QItemDelegate>
2525
#include "ui_qgsattributeselectiondialogbase.h"
26+
#include "qgsexpressioncontextgenerator.h"
2627

2728
class QGridLayout;
2829
class QgsVectorLayer;
@@ -56,7 +57,7 @@ class QgsComposerColumnAlignmentDelegate : public QItemDelegate
5657
// QgsComposerColumnAlignmentDelegate
5758

5859
/** A delegate for showing column attribute source as a QgsFieldExpressionWidget*/
59-
class QgsComposerColumnSourceDelegate : public QItemDelegate
60+
class QgsComposerColumnSourceDelegate : public QItemDelegate, private QgsExpressionContextGenerator
6061
{
6162
Q_OBJECT
6263

@@ -71,6 +72,7 @@ class QgsComposerColumnSourceDelegate : public QItemDelegate
7172
private:
7273
QgsVectorLayer* mVectorLayer;
7374
const QgsComposerObject* mComposerObject;
75+
QgsExpressionContext createExpressionContext() const override;
7476
};
7577

7678
// QgsComposerColumnWidthDelegate

src/app/composer/qgscomposerarrowwidget.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,8 @@ void QgsComposerArrowWidget::on_mLineStyleButton_clicked()
311311

312312
QgsLineSymbol* newSymbol = mArrow->lineSymbol()->clone();
313313
QgsSymbolSelectorDialog d( newSymbol, QgsStyle::defaultStyle(), nullptr, this );
314-
d.setExpressionContext( mArrow->createExpressionContext() );
314+
QgsExpressionContext context = mArrow->createExpressionContext();
315+
d.setExpressionContext( &context );
315316

316317
if ( d.exec() == QDialog::Accepted )
317318
{

src/app/composer/qgscomposerattributetablewidget.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -741,8 +741,8 @@ void QgsComposerAttributeTableWidget::on_mFeatureFilterButton_clicked()
741741
return;
742742
}
743743

744-
QScopedPointer<QgsExpressionContext> context( mComposerTable->createExpressionContext() );
745-
QgsExpressionBuilderDialog exprDlg( mComposerTable->sourceLayer(), mFeatureFilterEdit->text(), this, "generic", *context );
744+
QgsExpressionContext context = mComposerTable->createExpressionContext();
745+
QgsExpressionBuilderDialog exprDlg( mComposerTable->sourceLayer(), mFeatureFilterEdit->text(), this, "generic", context );
746746
exprDlg.setWindowTitle( tr( "Expression based filter" ) );
747747
if ( exprDlg.exec() == QDialog::Accepted )
748748
{

0 commit comments

Comments
 (0)