QGIS API Documentation 3.41.0-Master (cea29feecf2)
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#include "moc_qgsprocessingpointcloudexpressionlineedit.cpp"
20#include "qgsgui.h"
21#include "qgsapplication.h"
22#include "qgsfilterlineedit.h"
23#include "qgspointcloudlayer.h"
24#include "qgspointcloudexpression.h"
25
26#include <QHBoxLayout>
27#include <QToolButton>
28#include <QListView>
29#include <QPushButton>
30#include <QMessageBox>
31
33
34QgsProcessingPointCloudExpressionLineEdit::QgsProcessingPointCloudExpressionLineEdit( QWidget *parent )
35 : QWidget( parent )
36{
37 mLineEdit = new QgsFilterLineEdit();
38 mLineEdit->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
39
40 mButton = new QToolButton();
41 mButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
42 mButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpression.svg" ) ) );
43 connect( mButton, &QAbstractButton::clicked, this, &QgsProcessingPointCloudExpressionLineEdit::editExpression );
44
45 QHBoxLayout *layout = new QHBoxLayout();
46 layout->setContentsMargins( 0, 0, 0, 0 );
47 layout->addWidget( mLineEdit );
48 layout->addWidget( mButton );
49 setLayout( layout );
50
51 setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
52 setFocusProxy( mLineEdit );
53 connect( mLineEdit, &QLineEdit::textChanged, this, static_cast<void ( QgsProcessingPointCloudExpressionLineEdit::* )( const QString & )>( &QgsProcessingPointCloudExpressionLineEdit::expressionEdited ) );
54
55 setExpression( expression() );
56}
57
58QgsProcessingPointCloudExpressionLineEdit::~QgsProcessingPointCloudExpressionLineEdit() = default;
59
60void QgsProcessingPointCloudExpressionLineEdit::setLayer( QgsPointCloudLayer *layer )
61{
62 mLayer = layer;
63}
64
65QgsPointCloudLayer *QgsProcessingPointCloudExpressionLineEdit::layer() const
66{
67 return mLayer;
68}
69
70QString QgsProcessingPointCloudExpressionLineEdit::expression() const
71{
72 if ( mLineEdit )
73 return mLineEdit->text();
74
75 return QString();
76}
77
78void QgsProcessingPointCloudExpressionLineEdit::setExpression( const QString &newExpression )
79{
80 if ( mLineEdit )
81 mLineEdit->setText( newExpression );
82}
83
84void QgsProcessingPointCloudExpressionLineEdit::editExpression()
85{
86 const QString currentExpression = expression();
87 QgsProcessingPointCloudExpressionDialog dlg( mLayer );
88 dlg.setExpression( currentExpression );
89
90 if ( dlg.exec() )
91 {
92 const QString newExpression = dlg.expression();
93 setExpression( newExpression );
94 }
95}
96
97void QgsProcessingPointCloudExpressionLineEdit::expressionEdited()
98{
99 emit expressionChanged( expression() );
100}
101
102void QgsProcessingPointCloudExpressionLineEdit::expressionEdited( const QString &expression )
103{
104 emit expressionChanged( expression );
105}
106
107
108QgsProcessingPointCloudExpressionDialog::QgsProcessingPointCloudExpressionDialog( QgsPointCloudLayer *layer, const QString &startExpression, QWidget *parent )
109 : QDialog( parent )
110 , mLayer( layer )
111 , mInitialText( startExpression )
112{
113 setupUi( this );
115
116 mModelAttributes = new QStandardItemModel();
117 mModelValues = new QStandardItemModel();
118 lstAttributes->setModel( mModelAttributes );
119 lstValues->setModel( mModelValues );
120
121 populateAttributes();
122
123 connect( lstAttributes->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsProcessingPointCloudExpressionDialog::lstAttributes_currentChanged );
124 connect( lstAttributes, &QListView::doubleClicked, this, &QgsProcessingPointCloudExpressionDialog::lstAttributes_doubleClicked );
125 connect( lstValues, &QListView::doubleClicked, this, &QgsProcessingPointCloudExpressionDialog::lstValues_doubleClicked );
126 connect( btnEqual, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnEqual_clicked );
127 connect( btnLessThan, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnLessThan_clicked );
128 connect( btnGreaterThan, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnGreaterThan_clicked );
129 connect( btnIn, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnIn_clicked );
130 connect( btnNotIn, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnNotIn_clicked );
131 connect( btnLessEqual, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnLessEqual_clicked );
132 connect( btnGreaterEqual, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnGreaterEqual_clicked );
133 connect( btnNotEqual, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnNotEqual_clicked );
134 connect( btnAnd, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnAnd_clicked );
135 connect( btnOr, &QPushButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::btnOr_clicked );
136
137 QPushButton *pbn = new QPushButton( tr( "&Test" ) );
138 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
139 connect( pbn, &QAbstractButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::test );
140
141 pbn = new QPushButton( tr( "&Clear" ) );
142 buttonBox->addButton( pbn, QDialogButtonBox::ActionRole );
143 connect( pbn, &QAbstractButton::clicked, this, &QgsProcessingPointCloudExpressionDialog::clear );
144
145 mTxtSql->setText( mInitialText );
146}
147
148void QgsProcessingPointCloudExpressionDialog::setExpression( const QString &text )
149{
150 mTxtSql->setText( text );
151}
152
153QString QgsProcessingPointCloudExpressionDialog::expression()
154{
155 return mTxtSql->text();
156}
157
158void QgsProcessingPointCloudExpressionDialog::populateAttributes()
159{
160 if ( !mLayer )
161 {
162 return;
163 }
164
165 const QgsFields &fields = mLayer->dataProvider()->attributes().toFields();
166 mTxtSql->setFields( fields );
167 for ( int idx = 0; idx < fields.count(); ++idx )
168 {
169 QStandardItem *myItem = new QStandardItem( fields.at( idx ).displayNameWithAlias() );
170 mModelAttributes->insertRow( mModelAttributes->rowCount(), myItem );
171 }
172}
173
174void QgsProcessingPointCloudExpressionDialog::lstAttributes_currentChanged( const QModelIndex &current, const QModelIndex &previous )
175{
176 Q_UNUSED( previous )
177
178 mModelValues->clear();
179 const QString attribute = current.data().toString();
180 if ( attribute.compare( QLatin1String( "Classification" ), Qt::CaseInsensitive ) == 0 )
181 {
182 const QMap<int, QString> codes = QgsPointCloudDataProvider::translatedLasClassificationCodes();
183 for ( int i = 0; i <= 18; ++i )
184 {
185 QStandardItem *item = new QStandardItem( QString( "%1: %2" ).arg( i ).arg( codes.value( i ) ) );
186 item->setData( i, Qt::UserRole );
187 mModelValues->insertRow( mModelValues->rowCount(), item );
188 }
189 }
190 else
191 {
192 const QgsPointCloudStatistics stats = mLayer->statistics();
193 double value = stats.minimum( attribute );
194 QString valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
195 QStandardItem *item = new QStandardItem( tr( "Minimum: %1" ).arg( valueString ) );
196 item->setData( value, Qt::UserRole );
197 mModelValues->insertRow( mModelValues->rowCount(), item );
198
199 value = stats.maximum( attribute );
200 valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
201 item = new QStandardItem( tr( "Maximum: %1" ).arg( valueString ) );
202 item->setData( value, Qt::UserRole );
203 mModelValues->insertRow( mModelValues->rowCount(), item );
204
205 value = stats.mean( attribute );
206 valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
207 item = new QStandardItem( tr( "Mean: %1" ).arg( valueString ) );
208 item->setData( value, Qt::UserRole );
209 mModelValues->insertRow( mModelValues->rowCount(), item );
210
211 value = stats.stDev( attribute );
212 valueString = std::isnan( value ) ? tr( "n/a" ) : QString::number( value );
213 item = new QStandardItem( tr( "StdDev: %1" ).arg( valueString ) );
214 item->setData( value, Qt::UserRole );
215 mModelValues->insertRow( mModelValues->rowCount(), item );
216 }
217}
218
219void QgsProcessingPointCloudExpressionDialog::lstAttributes_doubleClicked( const QModelIndex &index )
220{
221 mTxtSql->insertText( QStringLiteral( "%1 " ).arg( mModelAttributes->data( index ).toString() ) );
222 mTxtSql->setFocus();
223}
224
225void QgsProcessingPointCloudExpressionDialog::lstValues_doubleClicked( const QModelIndex &index )
226{
227 mTxtSql->insertText( QStringLiteral( "%1 " ).arg( mModelValues->data( index, Qt::UserRole ).toString() ) );
228 mTxtSql->setFocus();
229}
230
231void QgsProcessingPointCloudExpressionDialog::btnEqual_clicked()
232{
233 mTxtSql->insertText( QStringLiteral( "= " ) );
234 mTxtSql->setFocus();
235}
236
237void QgsProcessingPointCloudExpressionDialog::btnLessThan_clicked()
238{
239 mTxtSql->insertText( QStringLiteral( "< " ) );
240 mTxtSql->setFocus();
241}
242
243void QgsProcessingPointCloudExpressionDialog::btnGreaterThan_clicked()
244{
245 mTxtSql->insertText( QStringLiteral( "> " ) );
246 mTxtSql->setFocus();
247}
248
249void QgsProcessingPointCloudExpressionDialog::btnIn_clicked()
250{
251 mTxtSql->insertText( QStringLiteral( "IN () " ) );
252 int i, j;
253 mTxtSql->getCursorPosition( &i, &j );
254 mTxtSql->setCursorPosition( i, j - 2 );
255 mTxtSql->setFocus();
256}
257
258void QgsProcessingPointCloudExpressionDialog::btnNotIn_clicked()
259{
260 mTxtSql->insertText( QStringLiteral( "NOT IN () " ) );
261 int i, j;
262 mTxtSql->getCursorPosition( &i, &j );
263 mTxtSql->setCursorPosition( i, j - 2 );
264 mTxtSql->setFocus();
265}
266
267void QgsProcessingPointCloudExpressionDialog::btnLessEqual_clicked()
268{
269 mTxtSql->insertText( QStringLiteral( "<= " ) );
270 mTxtSql->setFocus();
271}
272
273void QgsProcessingPointCloudExpressionDialog::btnGreaterEqual_clicked()
274{
275 mTxtSql->insertText( QStringLiteral( ">= " ) );
276 mTxtSql->setFocus();
277}
278
279void QgsProcessingPointCloudExpressionDialog::btnNotEqual_clicked()
280{
281 mTxtSql->insertText( QStringLiteral( "!= " ) );
282 mTxtSql->setFocus();
283}
284
285void QgsProcessingPointCloudExpressionDialog::btnAnd_clicked()
286{
287 mTxtSql->insertText( QStringLiteral( "AND " ) );
288 mTxtSql->setFocus();
289}
290
291void QgsProcessingPointCloudExpressionDialog::btnOr_clicked()
292{
293 mTxtSql->insertText( QStringLiteral( "OR " ) );
294 mTxtSql->setFocus();
295}
296
297void QgsProcessingPointCloudExpressionDialog::test()
298{
299 QgsPointCloudExpression expression( mTxtSql->text() );
300
301 if ( !expression.isValid() && !mTxtSql->text().isEmpty() )
302 {
303 QMessageBox::warning( this, tr( "Query Result" ), tr( "An error occurred while parsing the expression:\n%1" ).arg( expression.parserErrorString() ) );
304 }
305 else
306 {
307 const QSet<QString> attributes = expression.referencedAttributes();
308 int offset;
309 for ( const auto &attribute : attributes )
310 {
311 if ( mLayer && mLayer->dataProvider() && !mLayer->dataProvider()->attributes().find( attribute, offset ) )
312 {
313 QMessageBox::warning( this, tr( "Query Result" ), tr( "\"%1\" not recognized as an available attribute." ).arg( attribute ) );
314 return;
315 }
316 }
317 QMessageBox::information( this, tr( "Query Result" ), tr( "The expression was successfully parsed." ) );
318 }
319}
320
321void QgsProcessingPointCloudExpressionDialog::clear()
322{
323 mTxtSql->clear();
324}
325
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:103
Container of fields for a vector layer.
Definition qgsfields.h:46
int count
Definition qgsfields.h:50
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:210
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.
Class 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 ...