QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgsprocessingpointcloudexpressionlineedit.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingpointcloudexpressionlineedit.cpp
3 ---------------------
4 begin : April 2023
5 copyright : (C) 2023 by Alexander Bruy
6 email : alexander dot bruy at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include "qgsapplication.h"
21#include "qgsfilterlineedit.h"
22#include "qgsgui.h"
23#include "qgspointcloudexpression.h"
24#include "qgspointcloudlayer.h"
25
26#include <QHBoxLayout>
27#include <QListView>
28#include <QMessageBox>
29#include <QPushButton>
30#include <QToolButton>
31
32#include "moc_qgsprocessingpointcloudexpressionlineedit.cpp"
33
35
36QgsProcessingPointCloudExpressionLineEdit::QgsProcessingPointCloudExpressionLineEdit( QWidget *parent )
37 : QWidget( parent )
38{
39 mLineEdit = new QgsFilterLineEdit();
40 mLineEdit->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
41
42 mButton = new QToolButton();
43 mButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
44 mButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpression.svg" ) ) );
45 connect( mButton, &QAbstractButton::clicked, this, &QgsProcessingPointCloudExpressionLineEdit::editExpression );
46
47 QHBoxLayout *layout = new QHBoxLayout();
48 layout->setContentsMargins( 0, 0, 0, 0 );
49 layout->addWidget( mLineEdit );
50 layout->addWidget( mButton );
51 setLayout( layout );
52
53 setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
54 setFocusProxy( mLineEdit );
55 connect( mLineEdit, &QLineEdit::textChanged, this, static_cast<void ( QgsProcessingPointCloudExpressionLineEdit::* )( const QString & )>( &QgsProcessingPointCloudExpressionLineEdit::expressionEdited ) );
56
57 setExpression( expression() );
58}
59
60QgsProcessingPointCloudExpressionLineEdit::~QgsProcessingPointCloudExpressionLineEdit() = default;
61
62void QgsProcessingPointCloudExpressionLineEdit::setLayer( QgsPointCloudLayer *layer )
63{
64 mLayer = layer;
65}
66
67QgsPointCloudLayer *QgsProcessingPointCloudExpressionLineEdit::layer() const
68{
69 return mLayer;
70}
71
72QString QgsProcessingPointCloudExpressionLineEdit::expression() const
73{
74 if ( mLineEdit )
75 return mLineEdit->text();
76
77 return QString();
78}
79
80void QgsProcessingPointCloudExpressionLineEdit::setExpression( const QString &newExpression )
81{
82 if ( mLineEdit )
83 mLineEdit->setText( newExpression );
84}
85
86void QgsProcessingPointCloudExpressionLineEdit::editExpression()
87{
88 const QString currentExpression = expression();
89 QgsProcessingPointCloudExpressionDialog dlg( mLayer );
90 dlg.setExpression( currentExpression );
91
92 if ( dlg.exec() )
93 {
94 const QString newExpression = dlg.expression();
95 setExpression( newExpression );
96 }
97}
98
99void QgsProcessingPointCloudExpressionLineEdit::expressionEdited()
100{
101 emit expressionChanged( expression() );
102}
103
104void QgsProcessingPointCloudExpressionLineEdit::expressionEdited( const QString &expression )
105{
106 emit expressionChanged( expression );
107}
108
109
110QgsProcessingPointCloudExpressionDialog::QgsProcessingPointCloudExpressionDialog( QgsPointCloudLayer *layer, const QString &startExpression, QWidget *parent )
111 : QDialog( parent )
112 , mLayer( layer )
113 , mInitialText( startExpression )
114{
115 setupUi( this );
117
118 mModelAttributes = new QStandardItemModel();
119 mModelValues = new QStandardItemModel();
120 lstAttributes->setModel( mModelAttributes );
121 lstValues->setModel( mModelValues );
122
123 populateAttributes();
124
125 connect( lstAttributes->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsProcessingPointCloudExpressionDialog::lstAttributes_currentChanged );
126 connect( lstAttributes, &QListView::doubleClicked, this, &QgsProcessingPointCloudExpressionDialog::lstAttributes_doubleClicked );
127 connect( lstValues, &QListView::doubleClicked, this, &QgsProcessingPointCloudExpressionDialog::lstValues_doubleClicked );
128 connect( btnEqual, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnEqual_clicked );
129 connect( btnLessThan, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnLessThan_clicked );
130 connect( btnGreaterThan, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnGreaterThan_clicked );
131 connect( btnIn, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnIn_clicked );
132 connect( btnNotIn, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnNotIn_clicked );
133 connect( btnLessEqual, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnLessEqual_clicked );
134 connect( btnGreaterEqual, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnGreaterEqual_clicked );
135 connect( btnNotEqual, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnNotEqual_clicked );
136 connect( btnAnd, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnAnd_clicked );
137 connect( btnOr, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnOr_clicked );
138
139 QPushButton *pbn = new QPushButton( tr( "&Test" ) );
140 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
141 connect( pbn, &QAbstractButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::test );
142
143 pbn = new QPushButton( tr( "&Clear" ) );
144 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
145 connect( pbn, &QAbstractButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::clear );
146
147 mTxtSql->setText( mInitialText );
148}
149
150void QgsProcessingPointCloudExpressionDialog::setExpression( const QString &text )
151{
152 mTxtSql->setText( text );
153}
154
155QString QgsProcessingPointCloudExpressionDialog::expression()
156{
157 return mTxtSql->text();
158}
159
160void QgsProcessingPointCloudExpressionDialog::populateAttributes()
161{
162 if ( !mLayer )
163 {
164 return;
165 }
166
167 const QgsFields &fields = mLayer->dataProvider()->attributes().toFields();
168 mTxtSql->setFields( fields );
169 for ( int idx = 0; idx < fields.count(); ++idx )
170 {
171 QStandardItem *myItem = new QStandardItem( fields.at( idx ).displayNameWithAlias() );
172 mModelAttributes->insertRow( mModelAttributes->rowCount(), myItem );
173 }
174}
175
176void QgsProcessingPointCloudExpressionDialog::lstAttributes_currentChanged( const QModelIndex &current, const QModelIndex &previous )
177{
178 Q_UNUSED( previous )
179
180 mModelValues->clear();
181 const QString attribute = current.data().toString();
182 if ( attribute.compare( QLatin1String( "Classification" ), Qt::CaseInsensitive ) == 0 )
183 {
184 const QMap<int, QString> codes = QgsPointCloudDataProvider::translatedLasClassificationCodes();
185 for ( int i = 0; i <= 18; ++i )
186 {
187 QStandardItem *item = new QStandardItem( QString( "%1: %2" ).arg( i ).arg( codes.value( i ) ) );
188 item->setData( i, Qt::UserRole );
189 mModelValues->insertRow( mModelValues->rowCount(), item );
190 }
191 }
192 else
193 {
194 const QgsPointCloudStatistics stats = mLayer->statistics();
195 double value = stats.minimum( attribute );
196 QString valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
197 QStandardItem *item = new QStandardItem( tr( "Minimum: %1" ).arg( valueString ) );
198 item->setData( value, Qt::UserRole );
199 mModelValues->insertRow( mModelValues->rowCount(), item );
200
201 value = stats.maximum( attribute );
202 valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
203 item = new QStandardItem( tr( "Maximum: %1" ).arg( valueString ) );
204 item->setData( value, Qt::UserRole );
205 mModelValues->insertRow( mModelValues->rowCount(), item );
206
207 value = stats.mean( attribute );
208 valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
209 item = new QStandardItem( tr( "Mean: %1" ).arg( valueString ) );
210 item->setData( value, Qt::UserRole );
211 mModelValues->insertRow( mModelValues->rowCount(), item );
212
213 value = stats.stDev( attribute );
214 valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
215 item = new QStandardItem( tr( "StdDev: %1" ).arg( valueString ) );
216 item->setData( value, Qt::UserRole );
217 mModelValues->insertRow( mModelValues->rowCount(), item );
218 }
219}
220
221void QgsProcessingPointCloudExpressionDialog::lstAttributes_doubleClicked( const QModelIndex &index )
222{
223 mTxtSql->insertText( QStringLiteral( "%1 " ).arg( mModelAttributes->data( index ).toString() ) );
224 mTxtSql->setFocus();
225}
226
227void QgsProcessingPointCloudExpressionDialog::lstValues_doubleClicked( const QModelIndex &index )
228{
229 mTxtSql->insertText( QStringLiteral( "%1 " ).arg( mModelValues->data( index, Qt::UserRole ).toString() ) );
230 mTxtSql->setFocus();
231}
232
233void QgsProcessingPointCloudExpressionDialog::btnEqual_clicked()
234{
235 mTxtSql->insertText( QStringLiteral( "= " ) );
236 mTxtSql->setFocus();
237}
238
239void QgsProcessingPointCloudExpressionDialog::btnLessThan_clicked()
240{
241 mTxtSql->insertText( QStringLiteral( "< " ) );
242 mTxtSql->setFocus();
243}
244
245void QgsProcessingPointCloudExpressionDialog::btnGreaterThan_clicked()
246{
247 mTxtSql->insertText( QStringLiteral( "> " ) );
248 mTxtSql->setFocus();
249}
250
251void QgsProcessingPointCloudExpressionDialog::btnIn_clicked()
252{
253 mTxtSql->insertText( QStringLiteral( "IN () " ) );
254 int i, j;
255 mTxtSql->getCursorPosition( &i, &j );
256 mTxtSql->setCursorPosition( i, j - 2 );
257 mTxtSql->setFocus();
258}
259
260void QgsProcessingPointCloudExpressionDialog::btnNotIn_clicked()
261{
262 mTxtSql->insertText( QStringLiteral( "NOT IN () " ) );
263 int i, j;
264 mTxtSql->getCursorPosition( &i, &j );
265 mTxtSql->setCursorPosition( i, j - 2 );
266 mTxtSql->setFocus();
267}
268
269void QgsProcessingPointCloudExpressionDialog::btnLessEqual_clicked()
270{
271 mTxtSql->insertText( QStringLiteral( "<= " ) );
272 mTxtSql->setFocus();
273}
274
275void QgsProcessingPointCloudExpressionDialog::btnGreaterEqual_clicked()
276{
277 mTxtSql->insertText( QStringLiteral( ">= " ) );
278 mTxtSql->setFocus();
279}
280
281void QgsProcessingPointCloudExpressionDialog::btnNotEqual_clicked()
282{
283 mTxtSql->insertText( QStringLiteral( "!= " ) );
284 mTxtSql->setFocus();
285}
286
287void QgsProcessingPointCloudExpressionDialog::btnAnd_clicked()
288{
289 mTxtSql->insertText( QStringLiteral( "AND " ) );
290 mTxtSql->setFocus();
291}
292
293void QgsProcessingPointCloudExpressionDialog::btnOr_clicked()
294{
295 mTxtSql->insertText( QStringLiteral( "OR " ) );
296 mTxtSql->setFocus();
297}
298
299void QgsProcessingPointCloudExpressionDialog::test()
300{
301 QgsPointCloudExpression expression( mTxtSql->text() );
302
303 if ( !expression.isValid() && !mTxtSql->text().isEmpty() )
304 {
305 QMessageBox::warning( this, tr( "Query Result" ), tr( "An error occurred while parsing the expression:\n%1" ).arg( expression.parserErrorString() ) );
306 }
307 else
308 {
309 const QSet<QString> attributes = expression.referencedAttributes();
310 int offset;
311 for ( const auto &attribute : attributes )
312 {
313 if ( mLayer && mLayer->dataProvider() && !mLayer->dataProvider()->attributes().find( attribute, offset ) )
314 {
315 QMessageBox::warning( this, tr( "Query Result" ), tr( "\"%1\" not recognized as an available attribute." ).arg( attribute ) );
316 return;
317 }
318 }
319 QMessageBox::information( this, tr( "Query Result" ), tr( "The expression was successfully parsed." ) );
320 }
321}
322
323void QgsProcessingPointCloudExpressionDialog::clear()
324{
325 mTxtSql->clear();
326}
327
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
QString displayNameWithAlias() const
Returns the name to use when displaying this field and adds the alias in parenthesis if it is defined...
Definition qgsfield.cpp:105
Container of fields for a vector layer.
Definition qgsfields.h:46
int count
Definition qgsfields.h:50
void clear()
Removes all fields.
Definition qgsfields.cpp:61
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
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:221
static QMap< int, QString > translatedLasClassificationCodes()
Returns the map of LAS classification code to translated string value, corresponding to the ASPRS Sta...
Represents a map layer supporting display of point clouds.
Used to store statistics of a point cloud dataset.
double maximum(const QString &attribute) const
Returns the maximum value for the attribute attribute If no matching statistic is available then NaN ...
double stDev(const QString &attribute) const
Returns the standard deviation value for the attribute attribute If no matching statistic is availabl...
double mean(const QString &attribute) const
Returns the mean value for the attribute attribute If no matching statistic is available then NaN wil...
double minimum(const QString &attribute) const
Returns the minimum value for the attribute attribute If no matching statistic is available then NaN ...