43 QgsFeatureFilterWidget::QgsFeatureFilterWidget( QWidget *parent )
49 mFilterColumnsMenu =
new QMenu(
this );
50 mActionFilterColumnsMenu->setMenu( mFilterColumnsMenu );
51 mStoredFilterExpressionMenu =
new QMenu(
this );
52 mActionStoredFilterExpressions->setMenu( mStoredFilterExpressionMenu );
56 mActionShowAllFilter->setIcon( filterIcon );
57 mActionAdvancedFilter->setIcon( filterIcon );
58 mActionSelectedFilter->setIcon( filterIcon );
59 mActionVisibleFilter->setIcon( filterIcon );
60 mActionEditedFilter->setIcon( filterIcon );
64 mStoreFilterExpressionButton->setDefaultAction( mActionHandleStoreFilterExpression );
65 connect( mActionSaveAsStoredFilterExpression, &QAction::triggered,
this, &QgsFeatureFilterWidget::saveAsStoredFilterExpression );
66 connect( mActionEditStoredFilterExpression, &QAction::triggered,
this, &QgsFeatureFilterWidget::editStoredFilterExpression );
67 connect( mActionHandleStoreFilterExpression, &QAction::triggered,
this, &QgsFeatureFilterWidget::handleStoreFilterExpression );
68 mApplyFilterButton->setDefaultAction( mActionApplyFilter );
71 connect( mActionAdvancedFilter, &QAction::triggered,
this, &QgsFeatureFilterWidget::filterExpressionBuilder );
72 connect( mActionShowAllFilter, &QAction::triggered,
this, &QgsFeatureFilterWidget::filterShowAll );
73 connect( mActionSelectedFilter, &QAction::triggered,
this, &QgsFeatureFilterWidget::filterSelected );
74 connect( mActionVisibleFilter, &QAction::triggered,
this, &QgsFeatureFilterWidget::filterVisible );
75 connect( mActionEditedFilter, &QAction::triggered,
this, &QgsFeatureFilterWidget::filterEdited );
76 connect( mFilterQuery, &QLineEdit::returnPressed,
this, &QgsFeatureFilterWidget::filterQueryAccepted );
77 connect( mActionApplyFilter, &QAction::triggered,
this, &QgsFeatureFilterWidget::filterQueryAccepted );
78 connect( mFilterQuery, &QLineEdit::textChanged,
this, &QgsFeatureFilterWidget::onFilterQueryTextChanged );
86 mEditorContext = context;
87 mMessageBar = messageBar;
88 mMessageBarTimeout = messageBarTimeout;
94 mFilterQueryTimer.setSingleShot(
true );
95 connect( &mFilterQueryTimer, &QTimer::timeout,
this, &QgsFeatureFilterWidget::updateCurrentStoredFilterExpression );
98 storedFilterExpressionBoxInit();
99 storeExpressionButtonInit();
102 void QgsFeatureFilterWidget::filterShowAll()
104 mFilterButton->setDefaultAction( mActionShowAllFilter );
105 mFilterButton->setPopupMode( QToolButton::InstantPopup );
106 mFilterQuery->setVisible(
false );
107 mFilterQuery->setText( QString() );
108 if ( mCurrentSearchWidgetWrapper )
110 mCurrentSearchWidgetWrapper->widget()->setVisible(
false );
112 mApplyFilterButton->setVisible(
false );
113 mStoreFilterExpressionButton->setVisible(
false );
117 void QgsFeatureFilterWidget::filterSelected()
119 mFilterButton->setDefaultAction( mActionSelectedFilter );
120 mFilterButton->setPopupMode( QToolButton::InstantPopup );
121 mFilterQuery->setVisible(
false );
122 mApplyFilterButton->setVisible(
false );
123 mStoreFilterExpressionButton->setVisible(
false );
127 void QgsFeatureFilterWidget::filterVisible()
129 if ( !mLayer->isSpatial() )
135 mFilterButton->setDefaultAction( mActionVisibleFilter );
136 mFilterButton->setPopupMode( QToolButton::InstantPopup );
137 mFilterQuery->setVisible(
false );
138 mApplyFilterButton->setVisible(
false );
139 mStoreFilterExpressionButton->setVisible(
false );
143 void QgsFeatureFilterWidget::filterEdited()
145 mFilterButton->setDefaultAction( mActionEditedFilter );
146 mFilterButton->setPopupMode( QToolButton::InstantPopup );
147 mFilterQuery->setVisible(
false );
148 mApplyFilterButton->setVisible(
false );
149 mStoreFilterExpressionButton->setVisible(
false );
154 void QgsFeatureFilterWidget::filterQueryAccepted()
156 if ( ( mFilterQuery->isVisible() && mFilterQuery->text().isEmpty() ) ||
157 ( mCurrentSearchWidgetWrapper && mCurrentSearchWidgetWrapper->widget()->isVisible()
158 && mCurrentSearchWidgetWrapper->expression().isEmpty() ) )
163 filterQueryChanged( mFilterQuery->text() );
166 void QgsFeatureFilterWidget::filterQueryChanged(
const QString &query )
169 if ( mFilterButton->defaultAction() == mActionAdvancedFilter )
173 else if ( mCurrentSearchWidgetWrapper )
175 str = mCurrentSearchWidgetWrapper->expression();
178 setFilterExpression( str );
181 void QgsFeatureFilterWidget::columnBoxInit()
183 const auto constActions = mFilterColumnsMenu->actions();
184 for ( QAction *a : constActions )
186 mFilterColumnsMenu->removeAction( a );
187 mFilterButton->removeAction( a );
191 mFilterButton->addAction( mActionShowAllFilter );
192 mFilterButton->addAction( mActionSelectedFilter );
193 if ( mLayer->isSpatial() )
195 mFilterButton->addAction( mActionVisibleFilter );
197 mFilterButton->addAction( mActionEditedFilter );
198 mFilterButton->addAction( mActionFilterColumnsMenu );
199 mFilterButton->addAction( mActionAdvancedFilter );
200 mFilterButton->addAction( mActionStoredFilterExpressions );
202 const QList<QgsField> fields = mLayer->fields().toList();
204 const auto constFields = fields;
205 for (
const QgsField &field : constFields )
207 int idx = mLayer->fields().lookupField( field.name() );
213 QIcon icon = mLayer->fields().iconForField( idx );
214 QString alias = mLayer->attributeDisplayName( idx );
217 QAction *filterAction =
new QAction( icon, alias, mFilterButton );
218 filterAction->setData( field.name() );
220 connect( filterAction, &QAction::triggered,
this, [ = ] { filterColumnChanged( filterAction ); } );
221 mFilterColumnsMenu->addAction( filterAction );
226 void QgsFeatureFilterWidget::handleStoreFilterExpression()
228 if ( !mActionHandleStoreFilterExpression->isChecked() )
230 mLayer->storedExpressionManager()->removeStoredExpression( mActionHandleStoreFilterExpression->data().toString() );
234 mLayer->storedExpressionManager()->addStoredExpression( mFilterQuery->text(), mFilterQuery->text() );
237 updateCurrentStoredFilterExpression();
238 storedFilterExpressionBoxInit();
241 void QgsFeatureFilterWidget::storedFilterExpressionBoxInit()
243 const auto constActions = mStoredFilterExpressionMenu->actions();
244 for ( QAction *a : constActions )
246 mStoredFilterExpressionMenu->removeAction( a );
250 const QList< QgsStoredExpression > storedExpressions = mLayer->storedExpressionManager()->storedExpressions();
253 QAction *storedExpressionAction =
new QAction( storedExpression.name, mFilterButton );
254 connect( storedExpressionAction, &QAction::triggered,
this, [ = ]()
258 mStoredFilterExpressionMenu->addAction( storedExpressionAction );
262 void QgsFeatureFilterWidget::storeExpressionButtonInit()
264 if ( mActionHandleStoreFilterExpression->isChecked() )
266 mActionHandleStoreFilterExpression->setToolTip( tr(
"Delete stored expression" ) );
267 mActionHandleStoreFilterExpression->setText( tr(
"Delete Stored Expression" ) );
268 mActionHandleStoreFilterExpression->setIcon(
QgsApplication::getThemeIcon( QStringLiteral(
"mActionHandleStoreFilterExpressionChecked.svg" ) ) );
269 mStoreFilterExpressionButton->removeAction( mActionSaveAsStoredFilterExpression );
270 mStoreFilterExpressionButton->addAction( mActionEditStoredFilterExpression );
274 mActionHandleStoreFilterExpression->setToolTip( tr(
"Save expression with the text as name" ) );
275 mActionHandleStoreFilterExpression->setText( tr(
"Save Expression" ) );
276 mActionHandleStoreFilterExpression->setIcon(
QgsApplication::getThemeIcon( QStringLiteral(
"mActionHandleStoreFilterExpressionUnchecked.svg" ) ) );
277 mStoreFilterExpressionButton->addAction( mActionSaveAsStoredFilterExpression );
278 mStoreFilterExpressionButton->removeAction( mActionEditStoredFilterExpression );
283 void QgsFeatureFilterWidget::filterColumnChanged( QAction *filterAction )
285 mFilterButton->setDefaultAction( filterAction );
286 mFilterButton->setPopupMode( QToolButton::InstantPopup );
289 if ( mCurrentSearchWidgetWrapper )
291 mCurrentSearchWidgetWrapper->widget()->setVisible(
false );
292 delete mCurrentSearchWidgetWrapper;
294 QString fieldName = mFilterButton->defaultAction()->data().toString();
296 int fldIdx = mLayer->fields().lookupField( fieldName );
301 createSearchWidget( setup.
type(), mLayer, fldIdx, setup.
config(), mFilterContainer, mEditorContext );
302 if ( mCurrentSearchWidgetWrapper->applyDirectly() )
305 mApplyFilterButton->setVisible(
false );
306 mStoreFilterExpressionButton->setVisible(
false );
311 mApplyFilterButton->setVisible(
true );
312 mStoreFilterExpressionButton->setVisible(
true );
315 replaceSearchWidget( mFilterQuery, mCurrentSearchWidgetWrapper->widget() );
318 void QgsFeatureFilterWidget::filterExpressionBuilder()
324 dlg.setWindowTitle( tr(
"Expression Based Filter" ) );
329 dlg.setGeomCalculator( myDa );
331 if ( dlg.exec() == QDialog::Accepted )
337 void QgsFeatureFilterWidget::saveAsStoredFilterExpression()
339 QgsDialog *dlg =
new QgsDialog(
this,
nullptr, QDialogButtonBox::Save | QDialogButtonBox::Cancel );
340 dlg->setWindowTitle( tr(
"Save Expression As" ) );
341 QVBoxLayout *layout = dlg->
layout();
342 dlg->resize( std::max( 400, this->width() / 2 ), dlg->height() );
344 QLabel *nameLabel =
new QLabel( tr(
"Name" ), dlg );
345 QLineEdit *nameEdit =
new QLineEdit( dlg );
346 layout->addWidget( nameLabel );
347 layout->addWidget( nameEdit );
349 if ( dlg->exec() == QDialog::Accepted )
351 mLayer->storedExpressionManager()->addStoredExpression( nameEdit->text(), mFilterQuery->text() );
353 updateCurrentStoredFilterExpression();
354 storedFilterExpressionBoxInit();
358 void QgsFeatureFilterWidget::editStoredFilterExpression()
360 QgsDialog *dlg =
new QgsDialog(
this,
nullptr, QDialogButtonBox::Save | QDialogButtonBox::Cancel );
361 dlg->setWindowTitle( tr(
"Edit expression" ) );
362 QVBoxLayout *layout = dlg->
layout();
363 dlg->resize( std::max( 400, this->width() / 2 ), dlg->height() );
365 QLabel *nameLabel =
new QLabel( tr(
"Name" ), dlg );
366 QLineEdit *nameEdit =
new QLineEdit( mLayer->storedExpressionManager()->storedExpression( mActionHandleStoreFilterExpression->data().toString() ).name, dlg );
367 QLabel *expressionLabel =
new QLabel( tr(
"Expression" ), dlg );
369 expressionEdit->
setExpression( mLayer->storedExpressionManager()->storedExpression( mActionHandleStoreFilterExpression->data().toString() ).expression );
371 layout->addWidget( nameLabel );
372 layout->addWidget( nameEdit );
373 layout->addWidget( expressionLabel );
374 layout->addWidget( expressionEdit );
376 if ( dlg->exec() == QDialog::Accepted )
379 mLayer->storedExpressionManager()->updateStoredExpression( mActionHandleStoreFilterExpression->data().toString(), nameEdit->text(), expressionEdit->
expression(), QgsStoredExpression::Category::FilterExpression );
382 mFilterQuery->setValue( expressionEdit->
expression() );
384 storedFilterExpressionBoxInit();
388 void QgsFeatureFilterWidget::updateCurrentStoredFilterExpression()
390 QgsStoredExpression currentStoredExpression = mLayer->storedExpressionManager()->findStoredExpressionByExpression( mFilterQuery->value() );
393 mActionHandleStoreFilterExpression->setChecked( !currentStoredExpression.
id.isNull() );
395 mActionHandleStoreFilterExpression->setData( currentStoredExpression.
id );
396 mActionEditStoredFilterExpression->setData( currentStoredExpression.
id );
399 storeExpressionButtonInit();
402 void QgsFeatureFilterWidget::setFilterExpression(
const QString &filterString,
QgsAttributeForm::FilterType type,
bool alwaysShowFilter )
405 if ( !mFilterQuery->text().isEmpty() && !filterString.isEmpty() )
410 filter = filterString;
414 filter = QStringLiteral(
"(%1) AND (%2)" ).arg( mFilterQuery->text(), filterString );
418 filter = QStringLiteral(
"(%1) OR (%2)" ).arg( mFilterQuery->text(), filterString );
422 else if ( !filterString.isEmpty() )
424 filter = filterString;
432 mFilterQuery->setText( filter );
434 if ( alwaysShowFilter || !mCurrentSearchWidgetWrapper || !mCurrentSearchWidgetWrapper->applyDirectly() )
437 mFilterButton->setDefaultAction( mActionAdvancedFilter );
438 mFilterButton->setPopupMode( QToolButton::MenuButtonPopup );
439 mFilterQuery->setVisible(
true );
440 mApplyFilterButton->setVisible(
true );
441 mStoreFilterExpressionButton->setVisible(
true );
442 if ( mCurrentSearchWidgetWrapper )
445 replaceSearchWidget( mCurrentSearchWidgetWrapper->widget(), mFilterQuery );
457 if ( filterExpression.hasParserError() )
459 mMessageBar->pushMessage( tr(
"Parsing error" ), filterExpression.parserErrorString(),
Qgis::Warning, mMessageBarTimeout );
465 if ( !filterExpression.prepare( &context ) )
467 mMessageBar->pushMessage( tr(
"Evaluation error" ), filterExpression.evalErrorString(),
Qgis::Warning, mMessageBarTimeout );
470 bool fetchGeom = filterExpression.needsGeometry();
472 QApplication::setOverrideCursor( Qt::WaitCursor );
474 filterExpression.setGeomCalculator( &myDa );
494 context.setFeature( f );
495 if ( filterExpression.evaluate( &context ).toInt() != 0 )
496 filteredFeatures << f.
id();
499 if ( filterExpression.hasEvalError() )
505 mMainView->setFilteredFeatures( filteredFeatures );
507 QApplication::restoreOverrideCursor();
509 if ( filterExpression.hasEvalError() )
511 mMessageBar->pushMessage( tr(
"Error filtering" ), filterExpression.evalErrorString(),
Qgis::Warning, mMessageBarTimeout );
517 void QgsFeatureFilterWidget::replaceSearchWidget( QWidget *oldw, QWidget *neww )
519 mFilterLayout->removeWidget( oldw );
520 oldw->setVisible(
false );
521 mFilterLayout->addWidget( neww, 0, 0,
nullptr );
522 neww->setVisible(
true );
526 void QgsFeatureFilterWidget::onFilterQueryTextChanged(
const QString &value )
529 mFilterQueryTimer.start( 300 );
Class for parsing and evaluation of expressions (formerly called "search strings").
Wrapper for iterator of features from vector data provider or vector layer.
QSet< QgsFeatureId > QgsFeatureIds
This class contains context information for attribute editor widgets.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
A generic dialog with layout and button box.
A bar for displaying non-blocking messages to the user.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Show only visible features (depends on the map canvas)
Show only selected features.
void setExpression(const QString &expression)
Sets the current expression to show in the widget.
QString expression() const
Returns the current expression shown in the widget.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories...
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QString id
generated uuid used for identification
Show only features which have unsaved changes.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Encapsulate a field in an attribute table or data source.
Show only features whose ids are on the filter list. {.
QgsCoordinateTransformContext transformContext
A general purpose distance and area calculator, capable of performing ellipsoid based calculations...
void attributeAdded(int idx)
Will be emitted, when a new attribute has been added to this vector layer.
The QgsExpressionLineEdit widget includes a line edit for entering expressions together with a button...
static QgsProject * instance()
Returns the QgsProject singleton instance.
QVBoxLayout * layout()
Returns the central layout. Widgets added to it must have this dialog as parent.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
bool nextFeature(QgsFeature &f)
void attributeDeleted(int idx)
Will be emitted, when an attribute has been deleted from this vector layer.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Represents a vector layer which manages a vector based data sets.
Stored expression containing name, content (expression text) and a category tag.
A generic dialog for building expression strings.
This widget is used to show the attributes of a set of features of a QgsVectorLayer.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.