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" );
 
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.
 
Stores settings for use within QGIS.
 
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 dataset.
 
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
 
const QgsCoordinateReferenceSystem & crs