Skip to content

Commit bb8bced

Browse files
committedMar 26, 2020
move tree view from the expression builder to a dedicated class
1 parent c5841c3 commit bb8bced

15 files changed

+1681
-1122
lines changed
 

‎python/core/auto_generated/qgsfieldformatterregistry.sip.in

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ a default QgsFallbackFieldFormatter with a null id will be returned instead.
6161
%Docstring
6262
Returns a basic fallback field formatter which can be used
6363
to represent any field in an unspectacular manner.
64+
%End
65+
66+
static bool formatterCanProvideAvailableValues( QgsVectorLayer *layer, const QString &fieldName );
67+
%Docstring
68+
Returns if the formatter for a given layer and field name can provide available values
69+
70+
.. versionadded:: 3.14
6471
%End
6572

6673
signals:

‎python/gui/auto_generated/qgsexpressionbuilderwidget.sip.in

Lines changed: 41 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -10,86 +10,8 @@
1010

1111

1212

13-
class QgsExpressionItem : QStandardItem
14-
{
15-
%Docstring
16-
An expression item that can be used in the QgsExpressionBuilderWidget tree.
17-
%End
18-
19-
%TypeHeaderCode
20-
#include "qgsexpressionbuilderwidget.h"
21-
%End
22-
public:
23-
enum ItemType
24-
{
25-
Header,
26-
Field,
27-
ExpressionNode
28-
};
29-
30-
QgsExpressionItem( const QString &label,
31-
const QString &expressionText,
32-
const QString &helpText,
33-
QgsExpressionItem::ItemType itemType = ExpressionNode );
34-
35-
QgsExpressionItem( const QString &label,
36-
const QString &expressionText,
37-
QgsExpressionItem::ItemType itemType = ExpressionNode );
38-
39-
QString getExpressionText() const;
40-
41-
QString getHelpText() const;
42-
%Docstring
43-
Gets the help text that is associated with this expression item.
44-
45-
:return: The help text.
46-
%End
47-
48-
void setHelpText( const QString &helpText );
49-
%Docstring
50-
Set the help text for the current item
51-
52-
.. note::
53-
54-
The help text can be set as a html string.
55-
%End
56-
57-
QgsExpressionItem::ItemType getItemType() const;
58-
%Docstring
59-
Gets the type of expression item, e.g., header, field, ExpressionNode.
60-
61-
:return: The QgsExpressionItem.ItemType
62-
%End
63-
64-
static const int CUSTOM_SORT_ROLE;
65-
static const int ITEM_TYPE_ROLE;
66-
static const int SEARCH_TAGS_ROLE;
67-
68-
};
69-
70-
class QgsExpressionItemSearchProxy : QSortFilterProxyModel
71-
{
72-
%Docstring
73-
Search proxy used to filter the QgsExpressionBuilderWidget tree.
74-
The default search for a tree model only searches top level this will handle one
75-
level down
76-
%End
77-
78-
%TypeHeaderCode
79-
#include "qgsexpressionbuilderwidget.h"
80-
%End
81-
public:
82-
QgsExpressionItemSearchProxy();
83-
84-
virtual bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const;
8513

8614

87-
protected:
88-
89-
virtual bool lessThan( const QModelIndex &left, const QModelIndex &right ) const;
90-
91-
};
92-
9315

9416
class QgsExpressionBuilderWidget : QWidget
9517
{
@@ -118,13 +40,17 @@ Sets layer in order to get the fields and values
11840
this needs to be called before calling loadFieldNames().
11941
%End
12042

121-
void loadFieldNames();
43+
QgsVectorLayer *layer() const;
12244
%Docstring
123-
Loads all the field names from the layer.
124-
@remarks Should this really be public couldn't we just do this for the user?
45+
Returns the current layer or a None.
12546
%End
12647

127-
void loadFieldNames( const QgsFields &fields );
48+
void loadFieldNames( const QgsFields &fields = QgsFields() );
49+
%Docstring
50+
51+
.. deprecated:: QGIS 3.14
52+
this is now done automatically
53+
%End
12854

12955
void loadFieldsAndValues( const QMap<QString, QStringList> &fieldValues );
13056
%Docstring
@@ -135,6 +61,9 @@ Loads field names and values from the specified map.
13561
The field values must be quoted appropriately if they are strings.
13662

13763
.. versionadded:: 2.12
64+
65+
.. deprecated::
66+
use setLayer() and expressionTree()->
13867
%End
13968

14069
void setGeomCalculator( const QgsDistanceArea &da );
@@ -187,67 +116,64 @@ preview result and for populating the list of available functions and variables.
187116
void setExpressionContext( const QgsExpressionContext &context );
188117
%Docstring
189118
Sets the expression context for the widget. The context is used for the expression
190-
preview result and for populating the list of available functions and variables.
119+
preview result and to populate the list of available functions and variables.
191120

192121
:param context: expression context
193122

194123
.. seealso:: :py:func:`expressionContext`
195124

196125
.. versionadded:: 2.12
197-
%End
198-
199-
void registerItem( const QString &group, const QString &label, const QString &expressionText,
200-
const QString &helpText = QString(),
201-
QgsExpressionItem::ItemType type = QgsExpressionItem::ExpressionNode,
202-
bool highlightedItem = false, int sortOrder = 1,
203-
QIcon icon = QIcon(),
204-
const QStringList &tags = QStringList() );
205-
%Docstring
206-
Registers a node item for the expression builder.
207-
208-
:param group: The group the item will be show in the tree view. If the group doesn't exist it will be created.
209-
:param label: The label that is show to the user for the item in the tree.
210-
:param expressionText: The text that is inserted into the expression area when the user double clicks on the item.
211-
:param helpText: The help text that the user will see when item is selected.
212-
:param type: The type of the expression item.
213-
:param highlightedItem: set to ``True`` to make the item highlighted, which inserts a bold copy of the item at the top level
214-
:param sortOrder: sort ranking for item
215-
:param icon: custom icon to show for item
216-
:param tags: tags to find function
217126
%End
218127

219128
bool isExpressionValid();
220129

221-
void saveToRecent( const QString &collection = "generic" );
130+
void saveToRecent( const QString &collection = "generic" );
222131
%Docstring
223132
Adds the current expression to the given ``collection``.
224133
By default it is saved to the collection "generic".
134+
135+
.. deprecated:: QGIS 3.14
136+
use expressionTree()->saveRecent() instead
225137
%End
226138

227-
void loadRecent( const QString &collection = QStringLiteral( "generic" ) );
139+
void loadRecent( const QString &collection = QStringLiteral( "generic" ) );
228140
%Docstring
229141
Loads the recent expressions from the given ``collection``.
230142
By default it is loaded from the collection "generic".
143+
144+
.. deprecated:: QGIS 3.14
145+
use expressionTree()->loadRecent() instead
231146
%End
232147

233-
void loadUserExpressions( );
148+
QgsExpressionTreeView *expressionTree() const;
149+
150+
void loadUserExpressions();
234151
%Docstring
235152
Loads the user expressions.
236153

154+
.. deprecated:: QGIS 3.14
155+
use expressionTree()->loadUserExpressions() instead
156+
237157
.. versionadded:: 3.12
238158
%End
239159

240-
void saveToUserExpressions( const QString &label, const QString expression, const QString &helpText );
160+
void saveToUserExpressions( const QString &label, const QString expression, const QString &helpText );
241161
%Docstring
242162
Stores the user ``expression`` with given ``label`` and ``helpText``.
243163

164+
.. deprecated:: QGIS 3.14
165+
use expressionTree()->saveToUserExpressions() instead
166+
244167
.. versionadded:: 3.12
245168
%End
246169

247-
void removeFromUserExpressions( const QString &label );
170+
void removeFromUserExpressions( const QString &label );
248171
%Docstring
249172
Removes the expression ``label`` from the user stored expressions.
250173

174+
.. deprecated:: QGIS 3.14
175+
use expressionTree()->removeFromUserExpressions() instead
176+
251177
.. versionadded:: 3.12
252178
%End
253179

@@ -276,12 +202,14 @@ Loads code into the function editor
276202
Updates the list of function files found at the given path
277203
%End
278204

279-
QStandardItemModel *model();
205+
QStandardItemModel *model();
280206
%Docstring
281207
Returns a pointer to the dialog's function item model.
282208
This method is exposed for testing purposes only - it should not be used to modify the model.
283209

284210
.. versionadded:: 3.0
211+
212+
.. deprecated:: QGIS 3.14
285213
%End
286214

287215
QgsProject *project();
@@ -386,24 +314,6 @@ the selected expression must be a user stored expression.
386314
Edits the selected expression from the stored user expressions,
387315
the selected expression must be a user stored expression.
388316

389-
.. versionadded:: 3.14
390-
%End
391-
392-
QJsonDocument exportUserExpressions();
393-
%Docstring
394-
Create the expressions JSON document storing all the user expressions to be exported.
395-
396-
:return: the created expressions JSON file
397-
398-
.. versionadded:: 3.14
399-
%End
400-
401-
void loadExpressionsFromJson( const QJsonDocument &expressionsDocument );
402-
%Docstring
403-
Load and permanently store the expressions from the expressions JSON document.
404-
405-
:param expressionsDocument: the parsed expressions JSON file
406-
407317
.. versionadded:: 3.14
408318
%End
409319

@@ -412,6 +322,9 @@ Load and permanently store the expressions from the expressions JSON document.
412322
Returns the list of expression items matching a ``label``.
413323

414324
.. versionadded:: 3.12
325+
326+
.. deprecated:: QGIS 3.14
327+
use expressionTree()->findExpressions instead
415328
%End
416329

417330

@@ -446,6 +359,7 @@ with the context.
446359
virtual void showEvent( QShowEvent *e );
447360

448361

362+
public:
449363
};
450364

451365

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
/************************************************************************
2+
* This file has been generated automatically from *
3+
* *
4+
* src/gui/qgsexpressiontreeview.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
12+
13+
14+
15+
16+
class QgsExpressionItem : QStandardItem
17+
{
18+
%Docstring
19+
An expression item that can be used in the QgsExpressionBuilderWidget tree.
20+
%End
21+
22+
%TypeHeaderCode
23+
#include "qgsexpressiontreeview.h"
24+
%End
25+
public:
26+
enum ItemType
27+
{
28+
Header,
29+
Field,
30+
ExpressionNode
31+
};
32+
33+
QgsExpressionItem( const QString &label,
34+
const QString &expressionText,
35+
const QString &helpText,
36+
QgsExpressionItem::ItemType itemType = ExpressionNode );
37+
38+
QgsExpressionItem( const QString &label,
39+
const QString &expressionText,
40+
QgsExpressionItem::ItemType itemType = ExpressionNode );
41+
42+
QString getExpressionText() const;
43+
44+
QString getHelpText() const;
45+
%Docstring
46+
Gets the help text that is associated with this expression item.
47+
48+
:return: The help text.
49+
%End
50+
51+
void setHelpText( const QString &helpText );
52+
%Docstring
53+
Set the help text for the current item
54+
55+
.. note::
56+
57+
The help text can be set as a html string.
58+
%End
59+
60+
QgsExpressionItem::ItemType getItemType() const;
61+
%Docstring
62+
Gets the type of expression item, e.g., header, field, ExpressionNode.
63+
64+
:return: The QgsExpressionItem.ItemType
65+
%End
66+
67+
static const int CUSTOM_SORT_ROLE;
68+
static const int ITEM_TYPE_ROLE;
69+
static const int SEARCH_TAGS_ROLE;
70+
71+
};
72+
73+
74+
class QgsExpressionItemSearchProxy : QSortFilterProxyModel
75+
{
76+
%Docstring
77+
Search proxy used to filter the QgsExpressionBuilderWidget tree.
78+
The default search for a tree model only searches top level this will handle one
79+
level down
80+
%End
81+
82+
%TypeHeaderCode
83+
#include "qgsexpressiontreeview.h"
84+
%End
85+
public:
86+
QgsExpressionItemSearchProxy();
87+
88+
virtual bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const;
89+
90+
91+
protected:
92+
93+
virtual bool lessThan( const QModelIndex &left, const QModelIndex &right ) const;
94+
95+
};
96+
97+
class QgsExpressionTreeView : QTreeView
98+
{
99+
%Docstring
100+
QgsExpressionTreeView is a tree view to list all expressions
101+
functions, variables and fields that can be used in an expression.
102+
103+
.. seealso:: :py:class:`QgsExpressionBuilderWidget`
104+
105+
.. versionadded:: 3.14
106+
%End
107+
108+
%TypeHeaderCode
109+
#include "qgsexpressiontreeview.h"
110+
%End
111+
public:
112+
113+
class MenuProvider
114+
{
115+
%Docstring
116+
Implementation of this interface can be implemented to allow QgsExpressionTreeView
117+
instance to provide custom context menus (opened upon right-click).
118+
%End
119+
120+
%TypeHeaderCode
121+
#include "qgsexpressiontreeview.h"
122+
%End
123+
public:
124+
explicit MenuProvider();
125+
virtual ~MenuProvider();
126+
127+
virtual QMenu *createContextMenu( QgsExpressionItem *item ) /Factory/;
128+
%Docstring
129+
Returns a newly created menu instance
130+
%End
131+
};
132+
133+
QgsExpressionTreeView( QWidget *parent = 0 );
134+
135+
void setLayer( QgsVectorLayer *layer );
136+
%Docstring
137+
Sets layer in order to get the fields and values
138+
%End
139+
140+
void setExpressionContext( const QgsExpressionContext &context );
141+
%Docstring
142+
Sets the expression context for the tree view. The context is used
143+
to populate the list of available functions and variables.
144+
145+
:param context: expression context
146+
147+
.. seealso:: :py:func:`expressionContext`
148+
%End
149+
150+
QgsProject *project();
151+
%Docstring
152+
Returns the project currently associated with the widget.
153+
154+
.. seealso:: :py:func:`setProject`
155+
%End
156+
157+
void setProject( QgsProject *project );
158+
%Docstring
159+
Sets the ``project`` currently associated with the widget. This
160+
controls which layers and relations and other project-specific items are shown in the widget.
161+
162+
.. seealso:: :py:func:`project`
163+
%End
164+
165+
void setMenuProvider( MenuProvider *provider );
166+
%Docstring
167+
Sets the menu provider.
168+
This does not take ownership of the provider
169+
%End
170+
171+
void refresh();
172+
%Docstring
173+
Refreshes the content of the tree
174+
%End
175+
176+
QgsExpressionItem *currentItem() const;
177+
%Docstring
178+
Returns the current item or a None
179+
%End
180+
181+
182+
void loadRecent( const QString &collection = QStringLiteral( "generic" ) );
183+
%Docstring
184+
Loads the recent expressions from the given ``collection``.
185+
By default it is loaded from the collection "generic".
186+
%End
187+
188+
void saveToRecent( const QString &expressionText, const QString &collection = "generic" );
189+
%Docstring
190+
Adds the current expression to the given ``collection``.
191+
By default it is saved to the collection "generic".
192+
%End
193+
194+
void saveToUserExpressions( const QString &label, const QString expression, const QString &helpText );
195+
%Docstring
196+
Stores the user ``expression`` with given ``label`` and ``helpText``.
197+
%End
198+
199+
void removeFromUserExpressions( const QString &label );
200+
%Docstring
201+
Removes the expression ``label`` from the user stored expressions.
202+
%End
203+
204+
void loadUserExpressions( );
205+
%Docstring
206+
Loads the user expressions.
207+
This is done on request since it can be very slow if there are thousands of user expressions
208+
%End
209+
210+
const QList<QgsExpressionItem *> findExpressions( const QString &label );
211+
%Docstring
212+
Returns the list of expression items matching a ``label``.
213+
%End
214+
215+
216+
QJsonDocument exportUserExpressions();
217+
%Docstring
218+
Create the expressions JSON document storing all the user expressions to be exported.
219+
220+
:return: the created expressions JSON file
221+
%End
222+
223+
void loadExpressionsFromJson( const QJsonDocument &expressionsDocument );
224+
%Docstring
225+
Load and permanently store the expressions from the expressions JSON document.
226+
227+
:param expressionsDocument: the parsed expressions JSON file
228+
%End
229+
230+
signals:
231+
void expressionItemDoubleClicked( const QString &text );
232+
%Docstring
233+
Emitted when a expression item is double clicked
234+
%End
235+
236+
void currentExpressionItemChanged( QgsExpressionItem *item );
237+
%Docstring
238+
Emitter when the current expression item changed
239+
%End
240+
241+
public slots:
242+
void setSearchText( const QString &text );
243+
244+
245+
};
246+
247+
/************************************************************************
248+
* This file has been generated automatically from *
249+
* *
250+
* src/gui/qgsexpressiontreeview.h *
251+
* *
252+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
253+
************************************************************************/

‎python/gui/gui_auto.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
%Include auto_generated/qgsexpressionhighlighter.sip
7575
%Include auto_generated/qgsexpressionlineedit.sip
7676
%Include auto_generated/qgsexpressionselectiondialog.sip
77+
%Include auto_generated/qgsexpressiontreeview.sip
7778
%Include auto_generated/qgsextentgroupbox.sip
7879
%Include auto_generated/qgsextentwidget.sip
7980
%Include auto_generated/qgsexternalresourcewidget.sip

‎src/core/qgsfieldformatterregistry.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
* (at your option) any later version. *
1414
* *
1515
***************************************************************************/
16+
1617
#include "qgsfieldformatterregistry.h"
1718
#include "qgsfieldformatter.h"
1819

20+
#include "qgsapplication.h"
1921
#include "qgsvaluerelationfieldformatter.h"
2022
#include "qgsvaluemapfieldformatter.h"
2123
#include "qgsdatetimefieldformatter.h"
@@ -77,3 +79,20 @@ QgsFieldFormatter *QgsFieldFormatterRegistry::fallbackFieldFormatter() const
7779
{
7880
return mFallbackFieldFormatter;
7981
}
82+
83+
bool QgsFieldFormatterRegistry::formatterCanProvideAvailableValues( QgsVectorLayer *layer, const QString &fieldName )
84+
{
85+
if ( layer )
86+
{
87+
const QgsFields fields = layer->fields();
88+
int fieldIndex = fields.lookupField( fieldName );
89+
if ( fieldIndex != -1 )
90+
{
91+
const QgsEditorWidgetSetup setup = fields.at( fieldIndex ).editorWidgetSetup();
92+
const QgsFieldFormatter *formatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() );
93+
94+
return ( formatter->flags() & QgsFieldFormatter::CanProvideAvailableValues );
95+
}
96+
}
97+
return false;
98+
}

‎src/core/qgsfieldformatterregistry.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "qgis_core.h"
2525

2626
class QgsFieldFormatter;
27+
class QgsVectorLayer;
2728

2829
/**
2930
* \ingroup core
@@ -78,6 +79,12 @@ class CORE_EXPORT QgsFieldFormatterRegistry : public QObject
7879
*/
7980
QgsFieldFormatter *fallbackFieldFormatter() const;
8081

82+
/**
83+
* Returns if the formatter for a given layer and field name can provide available values
84+
* \since QGIS 3.14
85+
*/
86+
static bool formatterCanProvideAvailableValues( QgsVectorLayer *layer, const QString &fieldName );
87+
8188
signals:
8289

8390
/**

‎src/gui/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ SET(QGIS_GUI_SRCS
383383
qgsexpressionlineedit.cpp
384384
qgsexpressionselectiondialog.cpp
385385
qgsexpressionstoredialog.cpp
386+
qgsexpressiontreeview.cpp
386387
qgsextentgroupbox.cpp
387388
qgsextentwidget.cpp
388389
qgsexternalresourcewidget.cpp
@@ -602,6 +603,7 @@ SET(QGIS_GUI_HDRS
602603
qgsexpressionhighlighter.h
603604
qgsexpressionlineedit.h
604605
qgsexpressionselectiondialog.h
606+
qgsexpressiontreeview.h
605607
qgsextentgroupbox.h
606608
qgsextentwidget.h
607609
qgsexternalresourcewidget.h

‎src/gui/qgsexpressionbuilderdialog.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ void QgsExpressionBuilderDialog::done( int r )
8080

8181
void QgsExpressionBuilderDialog::accept()
8282
{
83-
builder->saveToRecent( mRecentKey );
83+
builder->expressionTree()->saveToRecent( builder->expressionText(), mRecentKey );
8484
QDialog::accept();
8585
}
8686

‎src/gui/qgsexpressionbuilderwidget.cpp

Lines changed: 79 additions & 759 deletions
Large diffs are not rendered by default.

‎src/gui/qgsexpressionbuilderwidget.h

Lines changed: 52 additions & 224 deletions
Large diffs are not rendered by default.

‎src/gui/qgsexpressionselectiondialog.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ void QgsExpressionSelectionDialog::done( int r )
223223

224224
void QgsExpressionSelectionDialog::saveRecent()
225225
{
226-
mExpressionBuilder->saveToRecent( QStringLiteral( "selection" ) );
226+
mExpressionBuilder->expressionTree()->saveToRecent( mExpressionBuilder->expressionText(), QStringLiteral( "selection" ) );
227227
}
228228

229229
void QgsExpressionSelectionDialog::showHelp()

‎src/gui/qgsexpressiontreeview.cpp

Lines changed: 852 additions & 0 deletions
Large diffs are not rendered by default.

‎src/gui/qgsexpressiontreeview.h

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
/***************************************************************************
2+
qgsexpressiontreeview.h
3+
--------------------------------------
4+
Date : march 2020 - quarantine day 9
5+
Copyright : (C) 2020 by Denis Rouzaud
6+
Email : denis@opengis.ch
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+
#ifndef QGSEXPRESSIONTREEVIEW_H
17+
#define QGSEXPRESSIONTREEVIEW_H
18+
19+
#include <QTreeView>
20+
#include <QStandardItemModel>
21+
#include <QSortFilterProxyModel>
22+
23+
#include "qgis_gui.h"
24+
#include "qgis_sip.h"
25+
#include "qgsexpressioncontext.h"
26+
#include "qgsproject.h"
27+
28+
29+
class QgsVectorLayer;
30+
31+
32+
33+
/**
34+
* \ingroup gui
35+
* An expression item that can be used in the QgsExpressionBuilderWidget tree.
36+
*/
37+
class GUI_EXPORT QgsExpressionItem : public QStandardItem
38+
{
39+
public:
40+
enum ItemType
41+
{
42+
Header,
43+
Field,
44+
ExpressionNode
45+
};
46+
47+
QgsExpressionItem( const QString &label,
48+
const QString &expressionText,
49+
const QString &helpText,
50+
QgsExpressionItem::ItemType itemType = ExpressionNode )
51+
: QStandardItem( label )
52+
{
53+
mExpressionText = expressionText;
54+
mHelpText = helpText;
55+
mType = itemType;
56+
setData( itemType, ITEM_TYPE_ROLE );
57+
}
58+
59+
QgsExpressionItem( const QString &label,
60+
const QString &expressionText,
61+
QgsExpressionItem::ItemType itemType = ExpressionNode )
62+
: QStandardItem( label )
63+
{
64+
mExpressionText = expressionText;
65+
mType = itemType;
66+
setData( itemType, ITEM_TYPE_ROLE );
67+
}
68+
69+
QString getExpressionText() const { return mExpressionText; }
70+
71+
/**
72+
* Gets the help text that is associated with this expression item.
73+
*
74+
* \returns The help text.
75+
*/
76+
QString getHelpText() const { return mHelpText; }
77+
78+
/**
79+
* Set the help text for the current item
80+
*
81+
* \note The help text can be set as a html string.
82+
*/
83+
void setHelpText( const QString &helpText ) { mHelpText = helpText; }
84+
85+
/**
86+
* Gets the type of expression item, e.g., header, field, ExpressionNode.
87+
*
88+
* \returns The QgsExpressionItem::ItemType
89+
*/
90+
QgsExpressionItem::ItemType getItemType() const { return mType; }
91+
92+
//! Custom sort order role
93+
static const int CUSTOM_SORT_ROLE = Qt::UserRole + 1;
94+
//! Item type role
95+
static const int ITEM_TYPE_ROLE = Qt::UserRole + 2;
96+
//! Search tags role
97+
static const int SEARCH_TAGS_ROLE = Qt::UserRole + 3;
98+
99+
private:
100+
QString mExpressionText;
101+
QString mHelpText;
102+
QgsExpressionItem::ItemType mType;
103+
};
104+
105+
106+
/**
107+
* \ingroup gui
108+
* Search proxy used to filter the QgsExpressionBuilderWidget tree.
109+
* The default search for a tree model only searches top level this will handle one
110+
* level down
111+
*/
112+
class GUI_EXPORT QgsExpressionItemSearchProxy : public QSortFilterProxyModel
113+
{
114+
Q_OBJECT
115+
116+
public:
117+
QgsExpressionItemSearchProxy();
118+
119+
bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const override;
120+
121+
protected:
122+
123+
bool lessThan( const QModelIndex &left, const QModelIndex &right ) const override;
124+
};
125+
126+
/**
127+
* \ingroup gui
128+
* QgsExpressionTreeView is a tree view to list all expressions
129+
* functions, variables and fields that can be used in an expression.
130+
* \see QgsExpressionBuilderWidget
131+
* \since QGIS 3.14
132+
*/
133+
class GUI_EXPORT QgsExpressionTreeView : public QTreeView
134+
{
135+
Q_OBJECT
136+
public:
137+
138+
/**
139+
* Implementation of this interface can be implemented to allow QgsExpressionTreeView
140+
* instance to provide custom context menus (opened upon right-click).
141+
*/
142+
class MenuProvider
143+
{
144+
public:
145+
explicit MenuProvider() = default;
146+
virtual ~MenuProvider() = default;
147+
148+
//! Returns a newly created menu instance
149+
virtual QMenu *createContextMenu( QgsExpressionItem *item ) SIP_FACTORY {Q_UNUSED( item ) return nullptr;}
150+
};
151+
152+
QgsExpressionTreeView( QWidget *parent = nullptr );
153+
154+
/**
155+
* Sets layer in order to get the fields and values
156+
*/
157+
void setLayer( QgsVectorLayer *layer );
158+
159+
/**
160+
* Sets the expression context for the tree view. The context is used
161+
* to populate the list of available functions and variables.
162+
* \param context expression context
163+
* \see expressionContext
164+
*/
165+
void setExpressionContext( const QgsExpressionContext &context );
166+
167+
/**
168+
* Returns the project currently associated with the widget.
169+
* \see setProject()
170+
*/
171+
QgsProject *project();
172+
173+
/**
174+
* Sets the \a project currently associated with the widget. This
175+
* controls which layers and relations and other project-specific items are shown in the widget.
176+
* \see project()
177+
*/
178+
void setProject( QgsProject *project );
179+
180+
/**
181+
* Sets the menu provider.
182+
* This does not take ownership of the provider
183+
*/
184+
void setMenuProvider( MenuProvider *provider );
185+
186+
/**
187+
* Refreshes the content of the tree
188+
*/
189+
void refresh();
190+
191+
/**
192+
* Returns the current item or a nullptr
193+
*/
194+
QgsExpressionItem *currentItem() const;
195+
196+
/**
197+
* Returns a pointer to the dialog's function item model.
198+
* This method is exposed for testing purposes only - it should not be used to modify the model
199+
* \note will be removed in QGIS 4
200+
*/
201+
Q_DECL_DEPRECATED QStandardItemModel *model() SIP_SKIP; // TODO remove QGIS 4
202+
203+
/**
204+
* Loads the recent expressions from the given \a collection.
205+
* By default it is loaded from the collection "generic".
206+
*/
207+
void loadRecent( const QString &collection = QStringLiteral( "generic" ) );
208+
209+
/**
210+
* Adds the current expression to the given \a collection.
211+
* By default it is saved to the collection "generic".
212+
*/
213+
void saveToRecent( const QString &expressionText, const QString &collection = "generic" );
214+
215+
/**
216+
* Stores the user \a expression with given \a label and \a helpText.
217+
*/
218+
void saveToUserExpressions( const QString &label, const QString expression, const QString &helpText );
219+
220+
/**
221+
* Removes the expression \a label from the user stored expressions.
222+
*/
223+
void removeFromUserExpressions( const QString &label );
224+
225+
/**
226+
* Loads the user expressions.
227+
* This is done on request since it can be very slow if there are thousands of user expressions
228+
*/
229+
void loadUserExpressions( );
230+
231+
/**
232+
* Returns the list of expression items matching a \a label.
233+
*/
234+
const QList<QgsExpressionItem *> findExpressions( const QString &label );
235+
236+
/**
237+
* Returns the user expression labels
238+
*/
239+
QStringList userExpressionLabels() const SIP_SKIP;
240+
241+
/**
242+
* Create the expressions JSON document storing all the user expressions to be exported.
243+
* \returns the created expressions JSON file
244+
*/
245+
QJsonDocument exportUserExpressions();
246+
247+
/**
248+
* Load and permanently store the expressions from the expressions JSON document.
249+
* \param expressionsDocument the parsed expressions JSON file
250+
*/
251+
void loadExpressionsFromJson( const QJsonDocument &expressionsDocument );
252+
253+
signals:
254+
//! Emitted when a expression item is double clicked
255+
void expressionItemDoubleClicked( const QString &text );
256+
257+
//! Emitter when the current expression item changed
258+
void currentExpressionItemChanged( QgsExpressionItem *item );
259+
260+
public slots:
261+
void setSearchText( const QString &text );
262+
263+
264+
private slots:
265+
void onDoubleClicked( const QModelIndex &index );
266+
267+
void showContextMenu( QPoint pt );
268+
269+
void currentChanged( const QModelIndex &index, const QModelIndex & );
270+
271+
private:
272+
void updateFunctionTree();
273+
274+
/**
275+
* Registers a node item for the expression builder.
276+
* \param group The group the item will be show in the tree view. If the group doesn't exist it will be created.
277+
* \param label The label that is show to the user for the item in the tree.
278+
* \param expressionText The text that is inserted into the expression area when the user double clicks on the item.
279+
* \param helpText The help text that the user will see when item is selected.
280+
* \param type The type of the expression item.
281+
* \param highlightedItem set to TRUE to make the item highlighted, which inserts a bold copy of the item at the top level
282+
* \param sortOrder sort ranking for item
283+
* \param icon custom icon to show for item
284+
* \param tags tags to find function
285+
*/
286+
void registerItem( const QString &group, const QString &label, const QString &expressionText,
287+
const QString &helpText = QString(),
288+
QgsExpressionItem::ItemType type = QgsExpressionItem::ExpressionNode,
289+
bool highlightedItem = false, int sortOrder = 1,
290+
QIcon icon = QIcon(),
291+
const QStringList &tags = QStringList() );
292+
293+
/**
294+
* Registers a node item for the expression builder, adding multiple items when the function exists in multiple groups
295+
* \param groups The groups the item will be show in the tree view. If a group doesn't exist it will be created.
296+
* \param label The label that is show to the user for the item in the tree.
297+
* \param expressionText The text that is inserted into the expression area when the user double clicks on the item.
298+
* \param helpText The help text that the user will see when item is selected.
299+
* \param type The type of the expression item.
300+
* \param highlightedItem set to TRUE to make the item highlighted, which inserts a bold copy of the item at the top level
301+
* \param sortOrder sort ranking for item
302+
* \param tags tags to find function
303+
*/
304+
void registerItemForAllGroups( const QStringList &groups, const QString &label, const QString &expressionText,
305+
const QString &helpText = QString(),
306+
QgsExpressionItem::ItemType type = QgsExpressionItem::ExpressionNode,
307+
bool highlightedItem = false, int sortOrder = 1, const QStringList &tags = QStringList() );
308+
309+
void loadExpressionContext();
310+
void loadRelations();
311+
void loadLayers();
312+
void loadFieldNames();
313+
314+
/**
315+
* Display a message box to ask the user what to do when an expression
316+
* with the same \a label already exists. Answering "Yes" will replace
317+
* the old expression with the one from the file, while "No" will keep
318+
* the old expression.
319+
* \param isApplyToAll whether the decision of the user should be applied to any future label collision
320+
* \param isOkToOverwrite whether to overwrite the old expression with the new one in case of label collision
321+
* \param label the label of the expression
322+
* \param oldExpression the old expression for a given label
323+
* \param newExpression the new expression for a given label
324+
*/
325+
void showMessageBoxConfirmExpressionOverwrite( bool &isApplyToAll, bool &isOkToOverwrite, const QString &label, const QString &oldExpression, const QString &newExpression );
326+
327+
328+
std::unique_ptr<QStandardItemModel> mModel;
329+
std::unique_ptr<QgsExpressionItemSearchProxy> mProxyModel;
330+
QMap<QString, QgsExpressionItem *> mExpressionGroups;
331+
332+
MenuProvider *mMenuProvider = nullptr;
333+
334+
QgsVectorLayer *mLayer = nullptr;
335+
QPointer< QgsProject > mProject;
336+
QgsExpressionContext mExpressionContext;
337+
QString mRecentKey;
338+
339+
QStringList mUserExpressionLabels;
340+
};
341+
342+
#endif // QGSEXPRESSIONTREEVIEW_H

‎src/gui/vector/qgsfieldcalculator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ QgsFieldCalculator::QgsFieldCalculator( QgsVectorLayer *vl, QWidget *parent )
161161

162162
void QgsFieldCalculator::accept()
163163
{
164-
builder->saveToRecent( QStringLiteral( "fieldcalc" ) );
164+
builder->expressionTree()->saveToRecent( builder->expressionText(), QStringLiteral( "fieldcalc" ) );
165165

166166
if ( !mVectorLayer )
167167
return;

‎src/ui/qgsexpressionbuilder.ui

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,12 @@
206206
<property name="orientation">
207207
<enum>Qt::Horizontal</enum>
208208
</property>
209+
<property name="sizeHint" stdset="0">
210+
<size>
211+
<width>0</width>
212+
<height>0</height>
213+
</size>
214+
</property>
209215
</spacer>
210216
</item>
211217
</layout>
@@ -586,7 +592,7 @@
586592
<widget class="QWidget" name="layoutWidget1">
587593
<layout class="QGridLayout" name="gridLayout_9">
588594
<item row="1" column="0" colspan="2">
589-
<widget class="QTreeView" name="expressionTree">
595+
<widget class="QgsExpressionTreeView" name="mExpressionTreeView">
590596
<property name="frameShape">
591597
<enum>QFrame::StyledPanel</enum>
592598
</property>
@@ -828,7 +834,7 @@ Change the name of the script and save to allow QGIS to auto load on startup.</s
828834
<string/>
829835
</property>
830836
<property name="icon">
831-
<iconset>
837+
<iconset resource="../../images/images.qrc">
832838
<normaloff>:/images/themes/default/console/iconNewTabEditorConsole.svg</normaloff>:/images/themes/default/console/iconNewTabEditorConsole.svg</iconset>
833839
</property>
834840
<property name="iconSize">
@@ -920,7 +926,7 @@ Saved scripts are auto loaded on QGIS startup.</string>
920926
<string>Save and Load Functions</string>
921927
</property>
922928
<property name="icon">
923-
<iconset>
929+
<iconset resource="../../images/images.qrc">
924930
<normaloff>:/images/themes/default/mActionStart.svg</normaloff>:/images/themes/default/mActionStart.svg</iconset>
925931
</property>
926932
</widget>
@@ -968,24 +974,32 @@ Saved scripts are auto loaded on QGIS startup.</string>
968974
<header>qgscollapsiblegroupbox.h</header>
969975
<container>1</container>
970976
</customwidget>
971-
<customwidget>
972-
<class>QgsFilterLineEdit</class>
973-
<extends>QLineEdit</extends>
974-
<header>qgsfilterlineedit.h</header>
975-
</customwidget>
976977
<customwidget>
977978
<class>QgsCodeEditorExpression</class>
978979
<extends>QWidget</extends>
979980
<header>qgscodeeditorexpression.h</header>
980981
<container>1</container>
981982
</customwidget>
983+
<customwidget>
984+
<class>QgsFilterLineEdit</class>
985+
<extends>QLineEdit</extends>
986+
<header>qgsfilterlineedit.h</header>
987+
</customwidget>
982988
<customwidget>
983989
<class>QgsCodeEditorPython</class>
984990
<extends>QWidget</extends>
985991
<header>qgscodeeditorpython.h</header>
986992
<container>1</container>
987993
</customwidget>
994+
<customwidget>
995+
<class>QgsExpressionTreeView</class>
996+
<extends>QTreeView</extends>
997+
<header>qgsexpressiontreeview.h</header>
998+
</customwidget>
988999
</customwidgets>
989-
<resources/>
1000+
<resources>
1001+
<include location="../../images/images.qrc"/>
1002+
<include location="../../images/images.qrc"/>
1003+
</resources>
9901004
<connections/>
9911005
</ui>

0 commit comments

Comments
 (0)
Please sign in to comment.