QGIS API Documentation 3.41.0-Master (45a0abf3bec)
Loading...
Searching...
No Matches
qgsquerybuilder.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsquerybuilder.cpp - Query Builder
3 --------------------------------------
4 Date : 2004-11-19
5 Copyright : (C) 2004 by Gary E.Sherman
6 Email : sherman at mrcc.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#include "qgsquerybuilder.h"
16#include "moc_qgsquerybuilder.cpp"
17#include "qgslogger.h"
18#include "qgssettings.h"
19#include "qgsvectorlayer.h"
21#include "qgsapplication.h"
22#include "qgshelp.h"
23#include "qgsgui.h"
24#include "qgsfieldproxymodel.h"
25#include "qgsfieldmodel.h"
26
27#include <QDomDocument>
28#include <QDomElement>
29#include <QFileDialog>
30#include <QInputDialog>
31#include <QListView>
32#include <QMessageBox>
33#include <QPushButton>
34#include <QTextStream>
35
36
37// constructor used when the query builder must make its own
38// connection to the database
40 QWidget *parent, Qt::WindowFlags fl )
41 : QgsSubsetStringEditorInterface( parent, fl )
42 , mPreviousFieldRow( -1 )
43 , mLayer( layer )
44{
45 setupUi( this );
47 connect( btnEqual, &QPushButton::clicked, this, &QgsQueryBuilder::btnEqual_clicked );
48 connect( btnLessThan, &QPushButton::clicked, this, &QgsQueryBuilder::btnLessThan_clicked );
49 connect( btnGreaterThan, &QPushButton::clicked, this, &QgsQueryBuilder::btnGreaterThan_clicked );
50 connect( btnPct, &QPushButton::clicked, this, &QgsQueryBuilder::btnPct_clicked );
51 connect( btnIn, &QPushButton::clicked, this, &QgsQueryBuilder::btnIn_clicked );
52 connect( btnNotIn, &QPushButton::clicked, this, &QgsQueryBuilder::btnNotIn_clicked );
53 connect( btnLike, &QPushButton::clicked, this, &QgsQueryBuilder::btnLike_clicked );
54 connect( btnILike, &QPushButton::clicked, this, &QgsQueryBuilder::btnILike_clicked );
55 connect( lstFields, &QListView::clicked, this, &QgsQueryBuilder::lstFields_clicked );
56 connect( lstFields, &QListView::doubleClicked, this, &QgsQueryBuilder::lstFields_doubleClicked );
57 connect( lstValues, &QListView::doubleClicked, this, &QgsQueryBuilder::lstValues_doubleClicked );
58 connect( btnLessEqual, &QPushButton::clicked, this, &QgsQueryBuilder::btnLessEqual_clicked );
59 connect( btnGreaterEqual, &QPushButton::clicked, this, &QgsQueryBuilder::btnGreaterEqual_clicked );
60 connect( btnNotEqual, &QPushButton::clicked, this, &QgsQueryBuilder::btnNotEqual_clicked );
61 connect( btnAnd, &QPushButton::clicked, this, &QgsQueryBuilder::btnAnd_clicked );
62 connect( btnNot, &QPushButton::clicked, this, &QgsQueryBuilder::btnNot_clicked );
63 connect( btnOr, &QPushButton::clicked, this, &QgsQueryBuilder::btnOr_clicked );
64 connect( btnGetAllValues, &QPushButton::clicked, this, &QgsQueryBuilder::btnGetAllValues_clicked );
65 connect( btnSampleValues, &QPushButton::clicked, this, &QgsQueryBuilder::btnSampleValues_clicked );
66 connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsQueryBuilder::showHelp );
67
68 QPushButton *pbn = new QPushButton( tr( "&Test" ) );
69 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
70 connect( pbn, &QAbstractButton::clicked, this, &QgsQueryBuilder::test );
71
72 pbn = new QPushButton( tr( "&Clear" ) );
73 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
74 connect( pbn, &QAbstractButton::clicked, this, &QgsQueryBuilder::clear );
75
76 pbn = new QPushButton( tr( "&Save…" ) );
77 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
78 pbn->setToolTip( tr( "Save query to QQF file" ) );
79 connect( pbn, &QAbstractButton::clicked, this, &QgsQueryBuilder::saveQuery );
80
81 pbn = new QPushButton( tr( "&Load…" ) );
82 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
83 pbn->setToolTip( tr( "Load query from QQF file" ) );
84 connect( pbn, &QAbstractButton::clicked, this, &QgsQueryBuilder::loadQuery );
85
86 setupGuiViews();
87
88 mModelFields = new QgsFieldProxyModel();
90 mModelFields->sourceFieldModel()->setLayer( layer );
91 lstFields->setModel( mModelFields );
92
93 mOrigSubsetString = layer->subsetString();
94 connect( layer, &QgsVectorLayer::subsetStringChanged, this, &QgsQueryBuilder::layerSubsetStringChanged );
95 layerSubsetStringChanged();
96
97 QString subsetStringDialect;
98 QString subsetStringHelpUrl;
99
100 if ( QgsDataProvider *provider = layer->dataProvider() )
101 {
102 lblDataUri->setText( tr( "Set provider filter on %1 (provider: %2)" ).arg( layer->name(), provider->name() ) );
103 subsetStringDialect = provider->subsetStringDialect();
104 subsetStringHelpUrl = provider->subsetStringHelpUrl();
105 }
106 else
107 {
108 lblDataUri->setText( tr( "Set provider filter on %1 (provider: %2)" ).arg( layer->name(), layer->providerType() ) );
109 }
110
111 if ( !subsetStringDialect.isEmpty() && !subsetStringHelpUrl.isEmpty() )
112 {
113 lblProviderFilterInfo->setOpenExternalLinks( true );
114 lblProviderFilterInfo->setText( tr( "Enter a <a href=\"%1\">%2</a> to filter the layer" ).arg( subsetStringHelpUrl ).arg( subsetStringDialect ) ) ;
115 }
116 else if ( !subsetStringDialect.isEmpty() )
117 {
118 lblProviderFilterInfo->setText( tr( "Enter a %1 to filter the layer" ).arg( subsetStringDialect ) ) ;
119 }
120 else
121 {
122 lblProviderFilterInfo->hide();
123 }
124
125 mTxtSql->setText( mOrigSubsetString );
126
127 mFilterLineEdit->setShowSearchIcon( true );
128 mFilterLineEdit->setPlaceholderText( tr( "Search…" ) );
129 connect( mFilterLineEdit, &QgsFilterLineEdit::textChanged, this, &QgsQueryBuilder::onTextChanged );
130}
131
132void QgsQueryBuilder::showEvent( QShowEvent *event )
133{
134 mTxtSql->setFocus();
135 QDialog::showEvent( event );
136}
137
138void QgsQueryBuilder::setupGuiViews()
139{
140 //Initialize the models
141 mModelValues = new QStandardItemModel();
142 mProxyValues = new QSortFilterProxyModel();
143 mProxyValues->setSourceModel( mModelValues );
144 // Modes
145 lstFields->setViewMode( QListView::ListMode );
146 lstValues->setViewMode( QListView::ListMode );
147 lstFields->setSelectionBehavior( QAbstractItemView::SelectRows );
148 lstValues->setSelectionBehavior( QAbstractItemView::SelectRows );
149 // Performance tip since Qt 4.1
150 lstFields->setUniformItemSizes( true );
151 lstValues->setUniformItemSizes( true );
152 // Colored rows
153 lstFields->setAlternatingRowColors( true );
154 lstValues->setAlternatingRowColors( true );
155 lstValues->setModel( mProxyValues );
156}
157
158void QgsQueryBuilder::fillValues( const QString &field, int limit )
159{
160 // clear the model
161 mModelValues->clear();
162
163 const int fieldIndex = mLayer->fields().lookupField( field );
164
165 // determine the field type
166 QList<QVariant> values = qgis::setToList( mLayer->uniqueValues( fieldIndex, limit ) );
167 std::sort( values.begin(), values.end() );
168
169 const QString nullValue = QgsApplication::nullRepresentation();
170
171 QgsDebugMsgLevel( QStringLiteral( "nullValue: %1" ).arg( nullValue ), 2 );
172
173 const auto constValues = values;
174 for ( const QVariant &var : constValues )
175 {
176 QString value;
177 if ( QgsVariantUtils::isNull( var ) )
178 value = nullValue;
179 else if ( var.userType() == QMetaType::Type::QDate && mLayer->providerType() == QLatin1String( "ogr" ) && mLayer->storageType() == QLatin1String( "ESRI Shapefile" ) )
180 value = var.toDate().toString( QStringLiteral( "yyyy/MM/dd" ) );
181 else if ( var.userType() == QMetaType::Type::QVariantList || var.userType() == QMetaType::Type::QStringList )
182 {
183 const QVariantList list = var.toList();
184 for ( const QVariant &val : list )
185 {
186 if ( !value.isEmpty() )
187 value.append( ", " );
188 value.append( QgsVariantUtils::isNull( val ) ? nullValue : val.toString() );
189 }
190 }
191 else
192 value = var.toString();
193
194 QStandardItem *myItem = new QStandardItem( value );
195 myItem->setEditable( false );
196 myItem->setData( var, Qt::UserRole + 1 );
197 mModelValues->insertRow( mModelValues->rowCount(), myItem );
198 QgsDebugMsgLevel( QStringLiteral( "Value is null: %1\nvalue: %2" ).arg( QgsVariantUtils::isNull( var ) ).arg( QgsVariantUtils::isNull( var ) ? nullValue : var.toString() ), 2 );
199 }
200}
201
202void QgsQueryBuilder::btnSampleValues_clicked()
203{
204 lstValues->setCursor( Qt::WaitCursor );
205
206 const QString prevSubsetString = mLayer->subsetString();
207 if ( mUseUnfilteredLayer->isChecked() && !prevSubsetString.isEmpty() )
208 {
209 mIgnoreLayerSubsetStringChangedSignal = true;
210 mLayer->setSubsetString( QString() );
211 }
212
213 //Clear and fill the mModelValues
214 fillValues( mModelFields->data( lstFields->currentIndex(), static_cast< int >( QgsFieldModel::CustomRole::FieldName ) ).toString(), 25 );
215
216 if ( prevSubsetString != mLayer->subsetString() )
217 {
218 mLayer->setSubsetString( prevSubsetString );
219 mIgnoreLayerSubsetStringChangedSignal = false;
220 }
221
222 lstValues->setCursor( Qt::ArrowCursor );
223}
224
225void QgsQueryBuilder::btnGetAllValues_clicked()
226{
227 lstValues->setCursor( Qt::WaitCursor );
228
229 const QString prevSubsetString = mLayer->subsetString();
230 if ( mUseUnfilteredLayer->isChecked() && !prevSubsetString.isEmpty() )
231 {
232 mIgnoreLayerSubsetStringChangedSignal = true;
233 mLayer->setSubsetString( QString() );
234 }
235
236 //Clear and fill the mModelValues
237 fillValues( mModelFields->data( lstFields->currentIndex(), static_cast< int >( QgsFieldModel::CustomRole::FieldName ) ).toString(), -1 );
238
239 if ( prevSubsetString != mLayer->subsetString() )
240 {
241 mLayer->setSubsetString( prevSubsetString );
242 mIgnoreLayerSubsetStringChangedSignal = false;
243 }
244
245 lstValues->setCursor( Qt::ArrowCursor );
246}
247
249{
250 // test the sql statement to see if it works
251 // by counting the number of records that would be
252 // returned
253
254 if ( mLayer->setSubsetString( mTxtSql->text() ) )
255 {
256 const long long featureCount { mLayer->featureCount() };
257 // Check for errors
258 if ( featureCount < 0 )
259 {
260 QMessageBox::warning( this,
261 tr( "Query Result" ),
262 tr( "An error occurred when executing the query, please check the expression syntax." ) );
263 }
264 else
265 {
266 QMessageBox::information( this,
267 tr( "Query Result" ),
268 tr( "The where clause returned %n row(s).", "returned test rows", featureCount ) );
269 }
270 }
271 else if ( mLayer->dataProvider()->hasErrors() )
272 {
273 QMessageBox::warning( this,
274 tr( "Query Result" ),
275 tr( "An error occurred when executing the query." )
276 + tr( "\nThe data provider said:\n%1" ).arg( mLayer->dataProvider()->errors().join( QLatin1Char( '\n' ) ) ) );
277 mLayer->dataProvider()->clearErrors();
278 }
279 else
280 {
281 QMessageBox::warning( this,
282 tr( "Query Result" ),
283 tr( "An error occurred when executing the query." ) );
284 }
285}
286
288{
289 if ( mTxtSql->text() != mOrigSubsetString )
290 {
291 if ( !mLayer->setSubsetString( mTxtSql->text() ) )
292 {
293 //error in query - show the problem
294 if ( mLayer->dataProvider()->hasErrors() )
295 {
296 QMessageBox::warning( this,
297 tr( "Query Result" ),
298 tr( "An error occurred when executing the query." )
299 + tr( "\nThe data provider said:\n%1" ).arg( mLayer->dataProvider()->errors().join( QLatin1Char( '\n' ) ) ) );
300 mLayer->dataProvider()->clearErrors();
301 }
302 else
303 {
304 QMessageBox::warning( this, tr( "Query Result" ), tr( "Error in query. The subset string could not be set." ) );
305 }
306
307 return;
308 }
309 }
310
311 QDialog::accept();
312}
313
315{
316 if ( mLayer->subsetString() != mOrigSubsetString )
317 mLayer->setSubsetString( mOrigSubsetString );
318
319 QDialog::reject();
320}
321
322void QgsQueryBuilder::btnEqual_clicked()
323{
324 mTxtSql->insertText( QStringLiteral( " = " ) );
325 mTxtSql->setFocus();
326}
327
328void QgsQueryBuilder::btnLessThan_clicked()
329{
330 mTxtSql->insertText( QStringLiteral( " < " ) );
331 mTxtSql->setFocus();
332}
333
334void QgsQueryBuilder::btnGreaterThan_clicked()
335{
336 mTxtSql->insertText( QStringLiteral( " > " ) );
337 mTxtSql->setFocus();
338}
339
340void QgsQueryBuilder::btnPct_clicked()
341{
342 mTxtSql->insertText( QStringLiteral( "%" ) );
343 mTxtSql->setFocus();
344}
345
346void QgsQueryBuilder::btnIn_clicked()
347{
348 mTxtSql->insertText( QStringLiteral( " IN " ) );
349 mTxtSql->setFocus();
350}
351
352void QgsQueryBuilder::btnNotIn_clicked()
353{
354 mTxtSql->insertText( QStringLiteral( " NOT IN " ) );
355 mTxtSql->setFocus();
356}
357
358void QgsQueryBuilder::btnLike_clicked()
359{
360 mTxtSql->insertText( QStringLiteral( " LIKE " ) );
361 mTxtSql->setFocus();
362}
363
364QString QgsQueryBuilder::sql() const
365{
366 return mTxtSql->text();
367}
368
369void QgsQueryBuilder::setSql( const QString &sqlStatement )
370{
371 mTxtSql->setText( sqlStatement );
372}
373
374void QgsQueryBuilder::lstFields_clicked( const QModelIndex &index )
375{
376 if ( mPreviousFieldRow != index.row() )
377 {
378 mPreviousFieldRow = index.row();
379
380 btnSampleValues->setEnabled( true );
381 btnGetAllValues->setEnabled( true );
382
383 mModelValues->clear();
384 mFilterLineEdit->clear();
385 }
386}
387
388void QgsQueryBuilder::lstFields_doubleClicked( const QModelIndex &index )
389{
390 mTxtSql->insertText( '\"' + mModelFields->data( index, static_cast< int >( QgsFieldModel::CustomRole::FieldName ) ).toString() + '\"' );
391 mTxtSql->setFocus();
392}
393
394void QgsQueryBuilder::lstValues_doubleClicked( const QModelIndex &index )
395{
396 const QVariant value = index.data( Qt::UserRole + 1 );
397 if ( QgsVariantUtils::isNull( value ) )
398 mTxtSql->insertText( QStringLiteral( "NULL" ) );
399 else if ( value.userType() == QMetaType::Type::QDate && mLayer->providerType() == QLatin1String( "ogr" ) && mLayer->storageType() == QLatin1String( "ESRI Shapefile" ) )
400 mTxtSql->insertText( '\'' + value.toDate().toString( QStringLiteral( "yyyy/MM/dd" ) ) + '\'' );
401 else if ( value.userType() == QMetaType::Type::Int || value.userType() == QMetaType::Type::Double || value.userType() == QMetaType::Type::LongLong || value.userType() == QMetaType::Type::Bool )
402 mTxtSql->insertText( value.toString() );
403 else
404 mTxtSql->insertText( '\'' + value.toString().replace( '\'', QLatin1String( "''" ) ) + '\'' );
405
406 mTxtSql->setFocus();
407}
408
409void QgsQueryBuilder::btnLessEqual_clicked()
410{
411 mTxtSql->insertText( QStringLiteral( " <= " ) );
412 mTxtSql->setFocus();
413}
414
415void QgsQueryBuilder::btnGreaterEqual_clicked()
416{
417 mTxtSql->insertText( QStringLiteral( " >= " ) );
418 mTxtSql->setFocus();
419}
420
421void QgsQueryBuilder::btnNotEqual_clicked()
422{
423 mTxtSql->insertText( QStringLiteral( " != " ) );
424 mTxtSql->setFocus();
425}
426
427void QgsQueryBuilder::btnAnd_clicked()
428{
429 mTxtSql->insertText( QStringLiteral( " AND " ) );
430 mTxtSql->setFocus();
431}
432
433void QgsQueryBuilder::btnNot_clicked()
434{
435 mTxtSql->insertText( QStringLiteral( " NOT " ) );
436 mTxtSql->setFocus();
437}
438
439void QgsQueryBuilder::btnOr_clicked()
440{
441 mTxtSql->insertText( QStringLiteral( " OR " ) );
442 mTxtSql->setFocus();
443}
444
445void QgsQueryBuilder::onTextChanged( const QString &text )
446{
447 mProxyValues->setFilterCaseSensitivity( Qt::CaseInsensitive );
448 mProxyValues->setFilterWildcard( text );
449}
450
452{
453 mTxtSql->clear();
454 mLayer->setSubsetString( QString() );
455}
456
457void QgsQueryBuilder::btnILike_clicked()
458{
459 mTxtSql->insertText( QStringLiteral( " ILIKE " ) );
460 mTxtSql->setFocus();
461}
462
464{
465 lblDataUri->setText( uri );
466}
467
468void QgsQueryBuilder::showHelp()
469{
470 QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html#query-builder" ) );
471}
472
474{
475 const bool ok = saveQueryToFile( mTxtSql->text() );
476 Q_UNUSED( ok )
477}
478
479bool QgsQueryBuilder::saveQueryToFile( const QString &subset )
480{
481 QgsSettings s;
482 const QString lastQueryFileDir = s.value( QStringLiteral( "/UI/lastQueryFileDir" ), QDir::homePath() ).toString();
483 //save as qqf (QGIS query file)
484 QString saveFileName = QFileDialog::getSaveFileName( nullptr, tr( "Save Query to File" ), lastQueryFileDir, tr( "Query files (*.qqf *.QQF)" ) );
485 if ( saveFileName.isNull() )
486 {
487 return false;
488 }
489
490 if ( !saveFileName.endsWith( QLatin1String( ".qqf" ), Qt::CaseInsensitive ) )
491 {
492 saveFileName += QLatin1String( ".qqf" );
493 }
494
495 QFile saveFile( saveFileName );
496 if ( !saveFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
497 {
498 QMessageBox::critical( nullptr, tr( "Save Query to File" ), tr( "Could not open file for writing." ) );
499 return false ;
500 }
501
502 QDomDocument xmlDoc;
503 QDomElement queryElem = xmlDoc.createElement( QStringLiteral( "Query" ) );
504 const QDomText queryTextNode = xmlDoc.createTextNode( subset );
505 queryElem.appendChild( queryTextNode );
506 xmlDoc.appendChild( queryElem );
507
508 QTextStream fileStream( &saveFile );
509 xmlDoc.save( fileStream, 2 );
510
511 const QFileInfo fi( saveFile );
512 s.setValue( QStringLiteral( "/UI/lastQueryFileDir" ), fi.absolutePath() );
513 return true;
514}
515
517{
518 QString subset;
519 if ( loadQueryFromFile( subset ) )
520 {
521 mTxtSql->clear();
522 mTxtSql->insertText( subset );
523 }
524}
525
527{
528 const QgsSettings s;
529 const QString lastQueryFileDir = s.value( QStringLiteral( "/UI/lastQueryFileDir" ), QDir::homePath() ).toString();
530
531 const QString queryFileName = QFileDialog::getOpenFileName( nullptr, tr( "Load Query from File" ), lastQueryFileDir, tr( "Query files" ) + " (*.qqf);;" + tr( "All files" ) + " (*)" );
532 if ( queryFileName.isNull() )
533 {
534 return false;
535 }
536
537 QFile queryFile( queryFileName );
538 if ( !queryFile.open( QIODevice::ReadOnly ) )
539 {
540 QMessageBox::critical( nullptr, tr( "Load Query from File" ), tr( "Could not open file for reading." ) );
541 return false;
542 }
543 QDomDocument queryDoc;
544 if ( !queryDoc.setContent( &queryFile ) )
545 {
546 QMessageBox::critical( nullptr, tr( "Load Query from File" ), tr( "File is not a valid xml document." ) );
547 return false;
548 }
549
550 const QDomElement queryElem = queryDoc.firstChildElement( QStringLiteral( "Query" ) );
551 if ( queryElem.isNull() )
552 {
553 QMessageBox::critical( nullptr, tr( "Load Query from File" ), tr( "File is not a valid query document." ) );
554 return false;
555 }
556
557 subset = queryElem.text();
558 return true;
559}
560
561void QgsQueryBuilder::layerSubsetStringChanged()
562{
563 if ( mIgnoreLayerSubsetStringChangedSignal )
564 return;
565 mUseUnfilteredLayer->setDisabled( mLayer->subsetString().isEmpty() );
566}
static QString nullRepresentation()
Returns the string used to represent the value NULL throughout QGIS.
Abstract base class for spatial data provider implementations.
@ FieldName
Return field name if index corresponds to a field.
void setLayer(QgsVectorLayer *layer)
Set the layer from which fields are displayed.
The QgsFieldProxyModel class provides an easy to use model to display the list of fields of a layer.
QgsFieldModel * sourceFieldModel()
Returns the QgsFieldModel used in this QSortFilterProxyModel.
@ AllTypes
All field types.
@ OriginProvider
Fields with a provider origin, since QGIS 3.38.
QgsFieldProxyModel * setFilters(QgsFieldProxyModel::Filters filters)
Set flags that affect how fields are filtered in the model.
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition qgsgui.cpp:209
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:39
QString name
Definition qgsmaplayer.h:80
QString providerType() const
Returns the provider type (provider key) for this layer.
static bool loadQueryFromFile(QString &subset)
Load query from the XML file.
void loadQuery()
Load query from the XML file.
void saveQuery()
Save query to the XML file.
void accept() override
void reject() override
void setDatasourceDescription(const QString &uri)
void setSql(const QString &sqlStatement)
Set the sql statement to display in the dialog.
virtual void test()
The default implementation tests that the constructed sql statement to see if the vector layer data p...
static bool saveQueryToFile(const QString &subset)
Save query to the XML file.
void showEvent(QShowEvent *event) override
QgsQueryBuilder(QgsVectorLayer *layer, QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
This constructor is used when the query builder is called from the vector layer properties dialog.
QString sql() const
Returns the sql statement entered in the dialog.
This class is a composition of two QSettings instances:
Definition qgssettings.h:64
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Interface for a dialog that can edit subset strings.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
void clearErrors()
Clear recorded errors.
QStringList errors() const
Gets recorded errors.
bool hasErrors() const
Provider has errors to report.
Represents a vector layer which manages a vector based data sets.
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
void subsetStringChanged()
Emitted when the layer's subset string has changed.
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
virtual bool setSubsetString(const QString &subset)
Sets the string (typically sql) used to define a subset of the layer.
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const FINAL
Calculates a list of unique values contained within an attribute in the layer.
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39