20#include <QRegularExpression>
23#include "moc_qgspointcloudlayersaveasdialog.cpp"
34 : QDialog( parent, fl )
40 mSelectedCrs = layer->
crs();
41 mLayerExtent = layer->
extent();
46void QgsPointCloudLayerSaveAsDialog::setup()
51 connect( mFormatComboBox,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, &QgsPointCloudLayerSaveAsDialog::mFormatComboBox_currentIndexChanged );
53 connect( mSelectAllAttributes, &QPushButton::clicked,
this, &QgsPointCloudLayerSaveAsDialog::mSelectAllAttributes_clicked );
54 connect( mDeselectAllAttributes, &QPushButton::clicked,
this, &QgsPointCloudLayerSaveAsDialog::mDeselectAllAttributes_clicked );
56 connect( mFilterGeometryGroupBox, &QgsCollapsibleGroupBox::toggled,
this, &QgsPointCloudLayerSaveAsDialog::mFilterGeometryGroupBoxCheckToggled );
57 connect( mMinimumZSpinBox,
static_cast<void (
QgsDoubleSpinBox::* )(
double )
>( &QgsDoubleSpinBox::valueChanged ),
this, &QgsPointCloudLayerSaveAsDialog::mMinimumZSpinBoxValueChanged );
58 connect( mMaximumZSpinBox,
static_cast<void (
QgsDoubleSpinBox::* )(
double )
>( &QgsDoubleSpinBox::valueChanged ),
this, &QgsPointCloudLayerSaveAsDialog::mMaximumZSpinBoxValueChanged );
61 mHelpButtonBox->setVisible(
false );
62 mButtonBox->addButton( QDialogButtonBox::Help );
63 connect( mButtonBox, &QDialogButtonBox::helpRequested,
this, &QgsPointCloudLayerSaveAsDialog::showHelp );
65 connect( mHelpButtonBox, &QDialogButtonBox::helpRequested,
this, &QgsPointCloudLayerSaveAsDialog::showHelp );
67 connect( mButtonBox, &QDialogButtonBox::accepted,
this, &QgsPointCloudLayerSaveAsDialog::accept );
68 connect( mButtonBox, &QDialogButtonBox::rejected,
this, &QgsPointCloudLayerSaveAsDialog::reject );
70 mFormatComboBox->blockSignals(
true );
72 for (
const auto &format : supportedFormats )
73 mFormatComboBox->addItem( getTranslatedNameForFormat( format ), static_cast<int>( format ) );
76 const int defaultFormat = settings.
value( QStringLiteral(
"UI/lastPointCloudFormat" ), 0 ).toInt();
77 mFormatComboBox->setCurrentIndex( mFormatComboBox->findData( defaultFormat ) );
78 mFormatComboBox->blockSignals(
false );
79 mFormatComboBox_currentIndexChanged( 0 );
81 mCrsSelector->setCrs( mSelectedCrs );
82 mCrsSelector->setLayerCrs( mSelectedCrs );
83 mCrsSelector->setMessage( tr(
"Select the coordinate reference system for the vector file. "
84 "The data points will be transformed from the layer coordinate reference system." ) );
91 QStringList availableAttributes;
95 if ( attribute.compare( QLatin1String(
"X" ), Qt::CaseInsensitive ) && attribute.compare( QLatin1String(
"Y" ), Qt::CaseInsensitive ) && attribute.compare( QLatin1String(
"Z" ), Qt::CaseInsensitive ) )
97 availableAttributes.append( attribute );
101 mAttributeTable->setRowCount( availableAttributes.count() );
102 QStringList horizontalHeaders = QStringList() << tr(
"Attribute" );
103 mAttributeTable->setColumnCount( horizontalHeaders.size() );
104 mAttributeTable->setHorizontalHeaderLabels( horizontalHeaders );
106 for (
int i = 0; i < availableAttributes.count(); ++i )
108 QTableWidgetItem *item =
new QTableWidgetItem( availableAttributes.at( i ) );
109 item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable );
110 item->setCheckState( Qt::Checked );
111 mAttributeTable->setItem( i, 0, item );
113 mAttributeTable->resizeColumnsToContents();
117 mExtentGroupBox->setOutputCrs( mSelectedCrs );
118 mExtentGroupBox->setOriginalExtent( mLayerExtent, mSelectedCrs );
119 mExtentGroupBox->setOutputExtentFromOriginal();
120 mExtentGroupBox->setCheckable(
true );
121 mExtentGroupBox->setChecked(
false );
122 mExtentGroupBox->setCollapsed(
true );
128 mMinimumZSpinBox->setRange( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max() );
129 mMaximumZSpinBox->setRange( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max() );
132 mMinimumZSpinBox->setValue( mLayer->
statistics().
minimum( QStringLiteral(
"Z" ) ) );
133 mMinimumZSpinBox->setClearValue( mMinimumZSpinBox->value() );
134 mMaximumZSpinBox->setValue( mLayer->
statistics().
maximum( QStringLiteral(
"Z" ) ) );
135 mMaximumZSpinBox->setClearValue( mMaximumZSpinBox->value() );
139 mPointsLimitSpinBox->setMinimum( 1 );
140 mPointsLimitSpinBox->setMaximum( std::numeric_limits<int>::max() );
141 mPointsLimitSpinBox->setValue( 1e6 );
142 mPointsLimitSpinBox->setClearValue( 1e6 );
145 mFilename->setDialogTitle( tr(
"Save Layer As" ) );
146 mFilename->setDefaultRoot( settings.
value( QStringLiteral(
"UI/lastPointCloudFileFilterDir" ), QDir::homePath() ).toString() );
147 mFilename->setConfirmOverwrite(
false );
150 if ( !filePath.isEmpty() )
151 mLastUsedFilename = filePath;
153 const QFileInfo fileInfo( filePath );
154 settings.
setValue( QStringLiteral(
"UI/lastPointCloudFileFilterDir" ), fileInfo.absolutePath() );
156 if ( mDefaultOutputLayerNameFromInputLayerName.isEmpty() )
158 leLayername->setDefaultValue( suggestedLayerName );
162 if ( leLayername->text().isEmpty() && !filePath.isEmpty() && leLayername->isEnabled() )
164 leLayername->setText( suggestedLayerName );
166 mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( !filePath.isEmpty() );
174 mCrsSelector->setSourceEnsemble( ensemble.
name() );
181 mCrsSelector->setShowAccuracyWarnings(
true );
188 leLayername->setDefaultValue( mDefaultOutputLayerNameFromInputLayerName );
190 if ( leLayername->isEnabled() )
191 leLayername->setText( mDefaultOutputLayerNameFromInputLayerName );
197void QgsPointCloudLayerSaveAsDialog::accept()
204 msgBox.setIcon( QMessageBox::Question );
205 msgBox.setWindowTitle( tr(
"Save Point Cloud Layer As" ) );
206 QPushButton *overwriteFileButton = msgBox.addButton( tr(
"Overwrite File" ), QMessageBox::ActionRole );
207 QPushButton *overwriteLayerButton = msgBox.addButton( tr(
"Overwrite Layer" ), QMessageBox::ActionRole );
208 QPushButton *appendToLayerButton = msgBox.addButton( tr(
"Append to Layer" ), QMessageBox::ActionRole );
209 msgBox.setStandardButtons( QMessageBox::Cancel );
210 msgBox.setDefaultButton( QMessageBox::Cancel );
211 overwriteFileButton->hide();
212 overwriteLayerButton->hide();
213 appendToLayerButton->hide();
218 msgBox.setText( tr(
"The layer already exists. Do you want to overwrite the whole file or overwrite the layer?" ) );
219 overwriteFileButton->setVisible(
true );
220 overwriteLayerButton->setVisible(
true );
224 msgBox.setText( tr(
"The file already exists. Do you want to overwrite it?" ) );
225 overwriteFileButton->setVisible(
true );
229 msgBox.setText( tr(
"The layer already exists. Do you want to overwrite the whole file, overwrite the layer or append features to the layer?" ) );
230 appendToLayerButton->setVisible(
true );
231 overwriteFileButton->setVisible(
true );
232 overwriteLayerButton->setVisible(
true );
236 msgBox.setText( tr(
"The layer already exists. Do you want to overwrite the whole file or append features to the layer?" ) );
237 appendToLayerButton->setVisible(
true );
238 overwriteFileButton->setVisible(
true );
241 int ret = msgBox.exec();
242 if ( ret == QMessageBox::Cancel )
244 if ( msgBox.clickedButton() == overwriteFileButton )
246 else if ( msgBox.clickedButton() == overwriteLayerButton )
248 else if ( msgBox.clickedButton() == appendToLayerButton )
260 if ( QMessageBox::question(
this, tr(
"Save Point Cloud Layer As" ), tr(
"The file already exists. Do you want to overwrite it?" ) ) == QMessageBox::NoButton )
271 QStringList layerList;
272 layerList.reserve( sublayers.size() );
275 layerList.append( sublayer.name() );
277 if ( layerList.length() > 1 )
279 layerList.sort( Qt::CaseInsensitive );
281 msgBox.setIcon( QMessageBox::Warning );
282 msgBox.setWindowTitle( tr(
"Overwrite File" ) );
283 msgBox.setText( tr(
"This file contains %1 layers that will be lost!\n" ).arg( QLocale().toString( layerList.length() ) ) );
284 msgBox.setDetailedText( tr(
"The following layers will be permanently lost:\n\n%1" ).arg( layerList.join(
"\n" ) ) );
285 msgBox.setStandardButtons( QMessageBox::Ok | QMessageBox::Cancel );
286 if ( msgBox.exec() == QMessageBox::Cancel )
292 settings.
setValue( QStringLiteral(
"UI/lastPointCloudFileFilterDir" ), QFileInfo(
filename() ).absolutePath() );
293 settings.
setValue( QStringLiteral(
"UI/lastPointCloudFormat" ),
static_cast<int>(
exportFormat() ) );
297void QgsPointCloudLayerSaveAsDialog::mFormatComboBox_currentIndexChanged(
int idx )
309 mAttributesSelection->setEnabled(
true );
314 mAttributesSelection->setEnabled(
false );
322 leLayername->setEnabled(
true );
329 leLayername->setEnabled(
false );
336 mWasAddToCanvasForced = !mAddToCanvas->isChecked();
337 mAddToCanvas->setEnabled(
false );
338 mAddToCanvas->setChecked(
true );
339 mFilename->setEnabled(
false );
347 mAddToCanvas->setEnabled(
true );
348 if ( mWasAddToCanvasForced )
350 mAddToCanvas->setChecked( !mAddToCanvas->isChecked() );
351 mWasAddToCanvasForced =
false;
353 mFilename->setEnabled(
true );
357 if ( mFilename->isEnabled() )
359 mFilename->setFilter( getFilterForFormat( format ) );
363 if ( !mLastUsedFilename.isEmpty() )
365 const thread_local QRegularExpression rx(
"\\.(.*?)[\\s]" );
367 ext = rx.match( getFilterForFormat( format ) ).captured( 1 );
368 if ( !ext.isEmpty() )
370 QFileInfo fi( mLastUsedFilename );
371 mFilename->setFilePath( QStringLiteral(
"%1/%2.%3" ).arg( fi.path(), fi.baseName(), ext ) );
376 if ( !mFilename->isEnabled() )
377 mFilename->setFilePath( QString() );
379 if ( !leLayername->isEnabled() )
381 leLayername->setText( QString() );
383 else if ( leLayername->text().isEmpty() )
385 QString layerName = mDefaultOutputLayerNameFromInputLayerName;
386 if ( layerName.isEmpty() && !mFilename->filePath().isEmpty() )
388 layerName = QFileInfo( mFilename->filePath() ).baseName();
389 leLayername->setDefaultValue( layerName );
391 if ( layerName.isEmpty() )
393 layerName = tr(
"new_layer" );
395 leLayername->setText( layerName );
401void QgsPointCloudLayerSaveAsDialog::mFilterGeometryGroupBoxCheckToggled(
bool checked )
404 mFilterGeometryLayerChanged( mFilterGeometryLayerComboBox->currentLayer() );
407void QgsPointCloudLayerSaveAsDialog::mFilterGeometryLayerChanged(
QgsMapLayer *layer )
410 mSelectedFeaturesCheckBox->setChecked(
false );
414void QgsPointCloudLayerSaveAsDialog::mMinimumZSpinBoxValueChanged(
const double value )
416 mMaximumZSpinBox->setMinimum( value );
419void QgsPointCloudLayerSaveAsDialog::mMaximumZSpinBoxValueChanged(
const double value )
421 mMinimumZSpinBox->setMaximum( value );
427 mExtentGroupBox->setOutputCrs( mSelectedCrs );
432 return mFilename->filePath();
437 return leLayername->text();
454 for (
int i = 0; i < mAttributeTable->rowCount(); i++ )
456 if ( mAttributeTable->item( i, 0 )->checkState() == Qt::Checked )
458 attributes.append( mAttributeTable->item( i, 0 )->text() );
467 return mAddToCanvas->isChecked();
472 mAddToCanvas->setChecked( enabled );
483 return mExtentGroupBox->isChecked();
488 return mExtentGroupBox->outputExtent();
493 return mFilterGeometryGroupBox->isChecked() && mFilterGeometryLayerComboBox->count() > 0;
498 return mFilterGeometryLayerComboBox->currentLayer();
503 return hasFilterLayer() && mSelectedFeaturesCheckBox->isChecked();
508 return mAttributesSelection->isChecked() && mAttributesSelection->isEnabled();
513 return mZRangeGroupBox->isChecked();
518 return QgsDoubleRange( mMinimumZSpinBox->value(), mMaximumZSpinBox->value() );
523 return mPointsLimitGroupBox->isChecked();
528 return mPointsLimitSpinBox->value();
533 return mActionOnExistingFile;
536void QgsPointCloudLayerSaveAsDialog::mSelectAllAttributes_clicked()
538 for (
int i = 0; i < mAttributeTable->rowCount(); i++ )
540 mAttributeTable->item( i, 0 )->setCheckState( Qt::Checked );
544void QgsPointCloudLayerSaveAsDialog::mDeselectAllAttributes_clicked()
547 for (
int i = 0; i < mAttributeTable->rowCount(); i++ )
549 mAttributeTable->item( i, 0 )->setCheckState( Qt::Unchecked );
554void QgsPointCloudLayerSaveAsDialog::showHelp()
556 QgsHelp::openHelp( QStringLiteral(
"managing_data_source/create_layers.html#creating-new-layers-from-an-existing-layer" ) );
564 return QStringLiteral(
"LAZ point cloud (*.laz *.LAZ);;LAS point cloud (*.las *.LAS)" );
566 return QStringLiteral(
"GeoPackage (*.gpkg *.GPKG)" );
568 return QStringLiteral(
"AutoCAD DXF (*.dxf *.dxf)" );
570 return QStringLiteral(
"ESRI Shapefile (*.shp *.SHP)" );
572 return QStringLiteral(
"Comma separated values (*.csv *.CSV)" );
584 return tr(
"Temporary Scratch Layer" );
586 return tr(
"GeoPackage" );
588 return tr(
"AutoCAD DXF" );
590 return tr(
"ESRI Shapefile" );
592 return tr(
"LAS/LAZ point cloud" );
594 return tr(
"Comma separated values" );
This class represents a coordinate reference system (CRS).
QgsDatumEnsemble datumEnsemble() const
Attempts to retrieve datum ensemble details from the CRS.
Contains information about a datum ensemble.
bool isValid() const
Returns true if the datum ensemble is a valid object, or false if it is a null/invalid object.
QString name() const
Display name of datum ensemble.
QgsRange which stores a range of double values.
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
@ ClearToDefault
Reset value to default value (see defaultValue() )
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...
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Map canvas is a class for displaying all GIS data types on a canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
void layerChanged(QgsMapLayer *layer)
Emitted whenever the currently selected layer changes.
static QString launderLayerName(const QString &name)
Launders a layer's name, converting it into a format which is general suitable for file names or data...
Base class for all map layer types.
QgsCoordinateReferenceSystem crs
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
Custom exception class which is raised when an operation is not supported.
const QgsPointCloudAttribute & at(int index) const
Returns the attribute at the specified index.
QString name() const
Returns name of the attribute.
ExportFormat
Supported export formats for point clouds.
@ Csv
Comma separated values.
@ Las
LAS/LAZ point cloud.
static QList< ExportFormat > supportedFormats()
Gets a list of the supported export formats.
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas to associate with the dialog.
QgsPointCloudLayerSaveAsDialog(QgsPointCloudLayer *layer, QWidget *parent=nullptr, Qt::WindowFlags fl=Qt::WindowFlags())
Construct a new QgsPointCloudLayerSaveAsDialog.
QString filename() const
Returns the target filename.
bool hasPointsLimit() const
Determines if limiting the number of exported points is enabled.
bool hasFilterLayer() const
Determines if points will be spatially filtered by a layer's features.
QgsRectangle filterExtent() const
Determines the extent to be exported.
bool hasZRange() const
Determines if filtering by Z values is activated.
QgsCoordinateReferenceSystem crsObject() const
Returns the CRS chosen for export.
bool hasAttributes() const
Determines if attributes will be exported as fields.
QgsDoubleRange zRange() const
Determines the Z range of points to be exported.
QgsPointCloudLayerExporter::ExportFormat exportFormat() const
The format in which the export should be written.
bool hasFilterExtent() const
Determines if filtering the export by an extent is activated.
int pointsLimit() const
Determines the limit to the total number of points.
bool filterLayerSelectedOnly() const
Determines if only the selected features from the filterLayer will be used for spatial filtering.
QString layername() const
Returns the target layer name.
void setAddToCanvas(bool checked)
Sets whether the "add to canvas" checkbox should be checked.
bool addToCanvas() const
Returns true if the "add to canvas" checkbox is checked.
QgsMapLayer * filterLayer() const
Returns the layer responsible for spatially filtering points.
QStringList attributes() const
Returns a list of attributes which are selected for saving.
QgsVectorFileWriter::ActionOnExistingFile creationActionOnExistingFile() const
Returns creation action.
Represents a map layer supporting display of point clouds.
QgsRectangle extent() const override
Returns the extent of the layer.
const QgsPointCloudStatistics statistics() const
Returns the object containing statistics.
QgsPointCloudAttributeCollection attributes() const
Returns the attributes available from the layer.
double maximum(const QString &attribute) const
Returns the maximum value for the attribute attribute If no matching statistic is available then NaN ...
double minimum(const QString &attribute) const
Returns the minimum value for the attribute attribute If no matching statistic is available then NaN ...
QList< QgsProviderSublayerDetails > querySublayers(const QString &uri, Qgis::SublayerQueryFlags flags=Qgis::SublayerQueryFlags(), QgsFeedback *feedback=nullptr) const
Queries the specified uri and returns a list of any valid sublayers found in the dataset which can be...
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
Contains details about a sub layer available from a dataset.
A rectangle specified with double values.
This class is a composition of two QSettings instances:
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.
A convenience class for writing vector layers to disk based formats (e.g.
@ CanAppendToExistingLayer
Flag to indicate that new features can be added to an existing layer.
@ CanAddNewLayer
Flag to indicate that a new layer can be added to the dataset.
@ CanDeleteLayer
Flag to indicate that an existing layer can be deleted.
static QgsVectorFileWriter::EditionCapabilities editionCapabilities(const QString &datasetName)
Returns edition capabilities for an existing dataset name.
QFlags< EditionCapability > EditionCapabilities
Combination of CanAddNewLayer, CanAppendToExistingLayer, CanAddNewFieldsToExistingLayer or CanDeleteL...
static bool targetLayerExists(const QString &datasetName, const QString &layerName)
Returns whether the target layer already exists.
ActionOnExistingFile
Enumeration to describe how to handle existing files.
@ CreateOrOverwriteLayer
Create or overwrite layer.
@ CreateOrOverwriteFile
Create or overwrite file.
@ AppendToLayerNoNewFields
Append features to existing layer, but do not create new fields.
Represents a vector layer which manages a vector based data sets.
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
const QgsCoordinateReferenceSystem & crs