Skip to content

Commit ada9ce4

Browse files
authoredJul 8, 2017
Merge pull request #4825
Various new expression functions and possibilities
2 parents 6b6a52b + 89a06f6 commit ada9ce4

26 files changed

+402
-75
lines changed
 

‎python/core/expression/qgsexpressionfunction.sip

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,11 @@ The help text for the function.
249249
:rtype: QVariant
250250
%End
251251

252+
virtual QVariant run( QgsExpressionNode::NodeList *args, const QgsExpressionContext *context, QgsExpression *parent );
253+
%Docstring
254+
:rtype: QVariant
255+
%End
256+
252257
bool operator==( const QgsExpressionFunction &other ) const;
253258

254259
virtual bool handlesNull() const;

‎python/core/geometry/qgscompoundcurve.sip

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class QgsCompoundCurve: QgsCurve
7777

7878
void addCurve( QgsCurve *c /Transfer/ );
7979
%Docstring
80-
Adds a curve to the geometr (takes ownership)
80+
Adds a curve to the geometry (takes ownership)
8181
%End
8282

8383
void removeCurve( int i );

‎python/core/qgsexpressioncontext.sip

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,15 @@ class QgsExpressionContextUtils
809809
:rtype: QgsExpressionContextScope
810810
%End
811811

812+
static QgsExpressionContextScope *mapToolCaptureScope( const QList<QgsPointLocator::Match> &matches ) /Factory/;
813+
%Docstring
814+
Sets the expression context variables which are available for expressions triggered by
815+
a map tool capture like add feature.
816+
817+
.. versionadded:: 3.0
818+
:rtype: QgsExpressionContextScope
819+
%End
820+
812821
static QgsExpressionContextScope *updateSymbolScope( const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope = 0 );
813822
%Docstring
814823
Updates a symbol scope related to a QgsSymbol to an expression context.

‎python/gui/qgsmaptoolcapture.sip

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ Adds a whole curve (e.g. circularstring) to the captured geometry. Curve must be
4242
:rtype: QgsCompoundCurve
4343
%End
4444

45+
QList<QgsPointLocator::Match> snappingMatches() const;
46+
%Docstring
47+
Return a list of matches for each point on the captureCurve.
48+
49+
.. versionadded:: 3.0
50+
:rtype: list of QgsPointLocator.Match
51+
%End
52+
4553
virtual void cadCanvasMoveEvent( QgsMapMouseEvent *e );
4654

4755
virtual void keyPressEvent( QKeyEvent *e );
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "array_first",
3+
"type": "function",
4+
"description": "Returns the first value of an array.",
5+
"arguments": [ {"arg":"array","description":"an array"} ],
6+
"examples": [ { "expression":"array_first(array('a','b','c'))", "returns":"'a'"}]
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "array_last",
3+
"type": "function",
4+
"description": "Returns the last value of an array.",
5+
"arguments": [ {"arg":"array","description":"an array"} ],
6+
"examples": [ { "expression":"array_last(array('a','b','c'))", "returns":"'c'"}]
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "get_feature_by_id",
3+
"type": "function",
4+
"description": "Returns the feature with an id on a layer.",
5+
"arguments": [ {"arg":"layer","description":"layer, layer name or layer id"},
6+
{"arg":"feature_id","description":"the id of the feature which should be returned"}],
7+
"examples": [ { "expression":"get_feature('streets', 1)", "returns":"the feature with the id 1 on the layer \"streets\""}]
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "with_variable",
3+
"type": "function",
4+
"description": "This function sets a variable for any expression code that will be provided as 3rd argument. This is only useful for complicated expressions, where the same calculated value needs to be used in different places.",
5+
"arguments": [
6+
{"arg":"name","description":"the name of the variable to set"},
7+
{"arg":"value","description":"the value to set"},
8+
{"arg":"node","description":"the expression for which the variable will be available"}
9+
],
10+
"examples": [ { "expression":"with_variable('my_sum', 1 + 2 + 3, @my_sum * 2 + @my_sum * 5)", "returns":"42"}]
11+
}

‎src/app/qgsattributetypedialog.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ QgsAttributeTypeDialog::QgsAttributeTypeDialog( QgsVectorLayer *vl, int fieldIdx
7171
isFieldEditableCheckBox->setEnabled( false );
7272
}
7373

74+
mExpressionWidget->registerExpressionContextGenerator( this );
75+
7476
connect( mExpressionWidget, &QgsExpressionLineEdit::expressionChanged, this, &QgsAttributeTypeDialog::defaultExpressionChanged );
7577
connect( mUniqueCheckBox, &QCheckBox::toggled, this, [ = ]( bool checked )
7678
{
@@ -293,6 +295,18 @@ void QgsAttributeTypeDialog::setDefaultValueExpression( const QString &expressio
293295
mExpressionWidget->setExpression( expression );
294296
}
295297

298+
QgsExpressionContext QgsAttributeTypeDialog::createExpressionContext() const
299+
{
300+
QgsExpressionContext context;
301+
context
302+
<< QgsExpressionContextUtils::globalScope()
303+
<< QgsExpressionContextUtils::projectScope( QgsProject::instance() )
304+
<< QgsExpressionContextUtils::layerScope( mLayer )
305+
<< QgsExpressionContextUtils::mapToolCaptureScope( QList<QgsPointLocator::Match>() );
306+
307+
return context;
308+
}
309+
296310
QString QgsAttributeTypeDialog::constraintExpression() const
297311
{
298312
return constraintExpressionWidget->asExpression();

‎src/app/qgsattributetypedialog.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
class QDialog;
2828

29-
class APP_EXPORT QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttributeTypeDialog
29+
class APP_EXPORT QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttributeTypeDialog, QgsExpressionContextGenerator
3030
{
3131
Q_OBJECT
3232

@@ -163,6 +163,8 @@ class APP_EXPORT QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttribut
163163
*/
164164
void setDefaultValueExpression( const QString &expression );
165165

166+
QgsExpressionContext createExpressionContext() const override;
167+
166168
private slots:
167169

168170
/**

‎src/app/qgsfeatureaction.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ bool QgsFeatureAction::editFeature( bool showModal )
161161
return true;
162162
}
163163

164-
bool QgsFeatureAction::addFeature( const QgsAttributeMap &defaultAttributes, bool showModal )
164+
bool QgsFeatureAction::addFeature( const QgsAttributeMap &defaultAttributes, bool showModal, QgsExpressionContextScope *scope SIP_TRANSFER )
165165
{
166166
if ( !mLayer || !mLayer->isEditable() )
167167
return false;
@@ -188,6 +188,9 @@ bool QgsFeatureAction::addFeature( const QgsAttributeMap &defaultAttributes, boo
188188
// create new feature template - this will initialize the attributes to valid values, handling default
189189
// values and field constraints
190190
QgsExpressionContext context = mLayer->createExpressionContext();
191+
if ( scope )
192+
context.appendScope( scope );
193+
191194
QgsFeature newFeature = QgsVectorLayerUtils::createFeature( mLayer, mFeature->geometry(), initialAttributeValues,
192195
&context );
193196
*mFeature = newFeature;

‎src/app/qgsfeatureaction.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class QgsIdentifyResultsDialog;
2929
class QgsVectorLayer;
3030
class QgsHighlight;
3131
class QgsAttributeDialog;
32+
class QgsExpressionContextScope;
3233

3334
class APP_EXPORT QgsFeatureAction : public QAction
3435
{
@@ -51,7 +52,7 @@ class APP_EXPORT QgsFeatureAction : public QAction
5152
*
5253
* \returns true if feature was added if showModal is true. If showModal is false, returns true in every case
5354
*/
54-
bool addFeature( const QgsAttributeMap &defaultAttributes = QgsAttributeMap(), bool showModal = true );
55+
bool addFeature( const QgsAttributeMap &defaultAttributes = QgsAttributeMap(), bool showModal = true, QgsExpressionContextScope *scope = nullptr );
5556

5657
private slots:
5758
void onFeatureSaved( const QgsFeature &feature );

‎src/app/qgsmaptooladdfeature.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ QgsMapToolAddFeature::~QgsMapToolAddFeature()
4848

4949
bool QgsMapToolAddFeature::addFeature( QgsVectorLayer *vlayer, QgsFeature *f, bool showModal )
5050
{
51+
QgsExpressionContextScope *scope = QgsExpressionContextUtils::mapToolCaptureScope( snappingMatches() );
5152
QgsFeatureAction *action = new QgsFeatureAction( tr( "add feature" ), *f, vlayer, QString(), -1, this );
52-
bool res = action->addFeature( QgsAttributeMap(), showModal );
53+
bool res = action->addFeature( QgsAttributeMap(), showModal, scope );
5354
if ( showModal )
5455
delete action;
5556
return res;
@@ -250,6 +251,7 @@ void QgsMapToolAddFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
250251
bool hasCurvedSegments = captureCurve()->hasCurvedSegments();
251252
bool providerSupportsCurvedSegments = vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::CircularGeometries;
252253

254+
QList<QgsPointLocator::Match> snappingMatchesList;
253255
QgsCurve *curveToAdd = nullptr;
254256
if ( hasCurvedSegments && providerSupportsCurvedSegments )
255257
{
@@ -258,13 +260,13 @@ void QgsMapToolAddFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
258260
else
259261
{
260262
curveToAdd = captureCurve()->curveToLine();
263+
snappingMatchesList = snappingMatches();
261264
}
262265

263266
if ( mode() == CaptureLine )
264267
{
265-
QgsGeometry *g = new QgsGeometry( curveToAdd );
266-
f->setGeometry( *g );
267-
delete g;
268+
QgsGeometry g( curveToAdd );
269+
f->setGeometry( g );
268270
}
269271
else
270272
{
@@ -278,9 +280,8 @@ void QgsMapToolAddFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
278280
poly = new QgsPolygonV2();
279281
}
280282
poly->setExteriorRing( curveToAdd );
281-
QgsGeometry *g = new QgsGeometry( poly );
282-
f->setGeometry( *g );
283-
delete g;
283+
QgsGeometry g( poly );
284+
f->setGeometry( g );
284285

285286
QgsGeometry featGeom = f->geometry();
286287
int avoidIntersectionsReturn = featGeom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );

‎src/app/qgsmaptooladdfeature.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ class APP_EXPORT QgsMapToolAddFeature : public QgsMapToolCapture
4444
void setCheckGeometryType( bool checkGeometryType );
4545

4646
private:
47-
QVariant snappingMatchesAsVariable() const;
4847

4948
/** Check if CaptureMode matches layer type. Default is true.
5049
* \since QGIS 2.12 */

‎src/core/expression/qgsexpression.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,19 @@ void QgsExpression::initVariableHelp()
673673
sVariableHelpTexts.insert( QStringLiteral( "grid_number" ), QCoreApplication::translate( "variable_help", "Current grid annotation value." ) );
674674
sVariableHelpTexts.insert( QStringLiteral( "grid_axis" ), QCoreApplication::translate( "variable_help", "Current grid annotation axis (e.g., 'x' for longitude, 'y' for latitude)." ) );
675675

676+
// map tool capture variables
677+
sVariableHelpTexts.insert( QStringLiteral( "snapping_results" ), QCoreApplication::translate( "variable_help",
678+
"<p>An array with an item for each snapped point.</p>"
679+
"<p>Each item is a map with the following keys:</p>"
680+
"<dl>"
681+
"<dt>valid</dt><dd>Boolean that indicates if the snapping result is valid</dd>"
682+
"<dt>layer</dt><dd>The layer on which the snapped feature is</dd>"
683+
"<dt>feature_id</dt><dd>The feature id of the snapped feature</dd>"
684+
"<dt>vertex_index</dt><dd>The index of the snapped vertex</dd>"
685+
"<dt>distance</dt><dd>The distance between the mouse cursor and the snapped point at the time of snapping</dd>"
686+
"</dl>" ) );
687+
688+
676689
//symbol variables
677690
sVariableHelpTexts.insert( QStringLiteral( "geometry_part_count" ), QCoreApplication::translate( "variable_help", "Number of parts in rendered feature's geometry." ) );
678691
sVariableHelpTexts.insert( QStringLiteral( "geometry_part_num" ), QCoreApplication::translate( "variable_help", "Current geometry part number for feature being rendered." ) );

0 commit comments

Comments
 (0)