20#include <QRegularExpression> 
   33  : QDialog( parent, fl )
 
   39    mSelectedCrs = layer->
crs();
 
   40    mLayerExtent = layer->
extent();
 
 
   45void QgsPointCloudLayerSaveAsDialog::setup()
 
   50  connect( mFormatComboBox, 
static_cast<void ( QComboBox::* )( 
int )
>( &QComboBox::currentIndexChanged ), 
this, &QgsPointCloudLayerSaveAsDialog::mFormatComboBox_currentIndexChanged );
 
   52  connect( mSelectAllAttributes, &QPushButton::clicked, 
this, &QgsPointCloudLayerSaveAsDialog::mSelectAllAttributes_clicked );
 
   53  connect( mDeselectAllAttributes, &QPushButton::clicked, 
this, &QgsPointCloudLayerSaveAsDialog::mDeselectAllAttributes_clicked );
 
   55  connect( mFilterGeometryGroupBox, &QgsCollapsibleGroupBox::toggled, 
this, &QgsPointCloudLayerSaveAsDialog::mFilterGeometryGroupBoxCheckToggled );
 
   56  connect( mMinimumZSpinBox, 
static_cast < void ( 
QgsDoubleSpinBox::* )( 
double ) 
> ( &QgsDoubleSpinBox::valueChanged ), 
this, &QgsPointCloudLayerSaveAsDialog::mMinimumZSpinBoxValueChanged );
 
   57  connect( mMaximumZSpinBox, 
static_cast < void ( 
QgsDoubleSpinBox::* )( 
double ) 
> ( &QgsDoubleSpinBox::valueChanged ), 
this, &QgsPointCloudLayerSaveAsDialog::mMaximumZSpinBoxValueChanged );
 
   60  mHelpButtonBox->setVisible( 
false );
 
   61  mButtonBox->addButton( QDialogButtonBox::Help );
 
   62  connect( mButtonBox, &QDialogButtonBox::helpRequested, 
this, &QgsPointCloudLayerSaveAsDialog::showHelp );
 
   64  connect( mHelpButtonBox, &QDialogButtonBox::helpRequested, 
this, &QgsPointCloudLayerSaveAsDialog::showHelp );
 
   66  connect( mButtonBox, &QDialogButtonBox::accepted, 
this, &QgsPointCloudLayerSaveAsDialog::accept );
 
   67  connect( mButtonBox, &QDialogButtonBox::rejected, 
this, &QgsPointCloudLayerSaveAsDialog::reject );
 
   69  mFormatComboBox->blockSignals( 
true );
 
   71  for ( 
const auto &format : supportedFormats )
 
   72    mFormatComboBox->addItem( getTranslatedNameForFormat( format ), static_cast< int >( format ) );
 
   75  const int defaultFormat = settings.
value( QStringLiteral( 
"UI/lastPointCloudFormat" ), 0 ).toInt();
 
   76  mFormatComboBox->setCurrentIndex( mFormatComboBox->findData( defaultFormat ) );
 
   77  mFormatComboBox->blockSignals( 
false );
 
   78  mFormatComboBox_currentIndexChanged( 0 );
 
   80  mCrsSelector->setCrs( mSelectedCrs );
 
   81  mCrsSelector->setLayerCrs( mSelectedCrs );
 
   82  mCrsSelector->setMessage( tr( 
"Select the coordinate reference system for the vector file. " 
   83                                "The data points will be transformed from the layer coordinate reference system." ) );
 
   90    QStringList availableAttributes;
 
   94      if ( attribute.compare( QLatin1String( 
"X" ), Qt::CaseInsensitive ) &&
 
   95           attribute.compare( QLatin1String( 
"Y" ), Qt::CaseInsensitive ) &&
 
   96           attribute.compare( QLatin1String( 
"Z" ), Qt::CaseInsensitive ) )
 
   98        availableAttributes.append( attribute );
 
  102    mAttributeTable->setRowCount( availableAttributes.count() );
 
  103    QStringList horizontalHeaders = QStringList() << tr( 
"Attribute" );
 
  104    mAttributeTable->setColumnCount( horizontalHeaders.size() );
 
  105    mAttributeTable->setHorizontalHeaderLabels( horizontalHeaders );
 
  107    for ( 
int i = 0; i < availableAttributes.count(); ++i )
 
  109      QTableWidgetItem *item = 
new QTableWidgetItem( availableAttributes.at( i ) );
 
  110      item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable );
 
  111      item->setCheckState( Qt::Checked );
 
  112      mAttributeTable->setItem( i, 0, item );
 
  114    mAttributeTable->resizeColumnsToContents();
 
  118  mExtentGroupBox->setOutputCrs( mSelectedCrs );
 
  119  mExtentGroupBox->setOriginalExtent( mLayerExtent, mSelectedCrs );
 
  120  mExtentGroupBox->setOutputExtentFromOriginal();
 
  121  mExtentGroupBox->setCheckable( 
true );
 
  122  mExtentGroupBox->setChecked( 
false );
 
  123  mExtentGroupBox->setCollapsed( 
true );
 
  129  mMinimumZSpinBox->setRange( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max() );
 
  130  mMaximumZSpinBox->setRange( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max() );
 
  133    mMinimumZSpinBox->setValue( mLayer->
statistics().
minimum( QStringLiteral( 
"Z" ) ) );
 
  134    mMinimumZSpinBox->setClearValue( mMinimumZSpinBox->value() );
 
  135    mMaximumZSpinBox->setValue( mLayer->
statistics().
maximum( QStringLiteral( 
"Z" ) ) );
 
  136    mMaximumZSpinBox->setClearValue( mMaximumZSpinBox->value() );
 
  140  mPointsLimitSpinBox->setMinimum( 1 );
 
  141  mPointsLimitSpinBox->setMaximum( std::numeric_limits<int>::max() );
 
  142  mPointsLimitSpinBox->setValue( 1e6 );
 
  143  mPointsLimitSpinBox->setClearValue( 1e6 );
 
  146  mFilename->setDialogTitle( tr( 
"Save Layer As" ) );
 
  147  mFilename->setDefaultRoot( settings.
value( QStringLiteral( 
"UI/lastPointCloudFileFilterDir" ), QDir::homePath() ).toString() );
 
  148  mFilename->setConfirmOverwrite( 
false );
 
  152    if ( !filePath.isEmpty() )
 
  153      mLastUsedFilename = filePath;
 
  155    const QFileInfo fileInfo( filePath );
 
  156    settings.
setValue( QStringLiteral( 
"UI/lastPointCloudFileFilterDir" ), fileInfo.absolutePath() );
 
  158    if ( mDefaultOutputLayerNameFromInputLayerName.isEmpty() )
 
  160      leLayername->setDefaultValue( suggestedLayerName );
 
  164    if ( leLayername->text().isEmpty() && !filePath.isEmpty() && leLayername->isEnabled() )
 
  166      leLayername->setText( suggestedLayerName );
 
  168    mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( !filePath.isEmpty() );
 
  176      mCrsSelector->setSourceEnsemble( ensemble.
name() );
 
  183  mCrsSelector->setShowAccuracyWarnings( 
true );
 
  190    leLayername->setDefaultValue( mDefaultOutputLayerNameFromInputLayerName );
 
  192    if ( leLayername->isEnabled() )
 
  193      leLayername->setText( mDefaultOutputLayerNameFromInputLayerName );
 
  197      !mFilename->filePath().isEmpty() );
 
  200void QgsPointCloudLayerSaveAsDialog::accept()
 
  209    msgBox.setIcon( QMessageBox::Question );
 
  210    msgBox.setWindowTitle( tr( 
"Save Point Cloud Layer As" ) );
 
  211    QPushButton *overwriteFileButton = msgBox.addButton( tr( 
"Overwrite File" ), QMessageBox::ActionRole );
 
  212    QPushButton *overwriteLayerButton = msgBox.addButton( tr( 
"Overwrite Layer" ), QMessageBox::ActionRole );
 
  213    QPushButton *appendToLayerButton = msgBox.addButton( tr( 
"Append to Layer" ), QMessageBox::ActionRole );
 
  214    msgBox.setStandardButtons( QMessageBox::Cancel );
 
  215    msgBox.setDefaultButton( QMessageBox::Cancel );
 
  216    overwriteFileButton->hide();
 
  217    overwriteLayerButton->hide();
 
  218    appendToLayerButton->hide();
 
  225        msgBox.setText( tr( 
"The layer already exists. Do you want to overwrite the whole file or overwrite the layer?" ) );
 
  226        overwriteFileButton->setVisible( 
true );
 
  227        overwriteLayerButton->setVisible( 
true );
 
  231        msgBox.setText( tr( 
"The file already exists. Do you want to overwrite it?" ) );
 
  232        overwriteFileButton->setVisible( 
true );
 
  237        msgBox.setText( tr( 
"The layer already exists. Do you want to overwrite the whole file, overwrite the layer or append features to the layer?" ) );
 
  238        appendToLayerButton->setVisible( 
true );
 
  239        overwriteFileButton->setVisible( 
true );
 
  240        overwriteLayerButton->setVisible( 
true );
 
  244        msgBox.setText( tr( 
"The layer already exists. Do you want to overwrite the whole file or append features to the layer?" ) );
 
  245        appendToLayerButton->setVisible( 
true );
 
  246        overwriteFileButton->setVisible( 
true );
 
  249      int ret = msgBox.exec();
 
  250      if ( ret == QMessageBox::Cancel )
 
  252      if ( msgBox.clickedButton() == overwriteFileButton )
 
  254      else if ( msgBox.clickedButton() == overwriteLayerButton )
 
  256      else if ( msgBox.clickedButton() == appendToLayerButton )
 
  268        if ( QMessageBox::question( 
this,
 
  269                                    tr( 
"Save Point Cloud Layer As" ),
 
  270                                    tr( 
"The file already exists. Do you want to overwrite it?" ) ) == QMessageBox::NoButton )
 
  281    QStringList layerList;
 
  282    layerList.reserve( sublayers.size() );
 
  285      layerList.append( sublayer.name() );
 
  287    if ( layerList.length() > 1 )
 
  289      layerList.sort( Qt::CaseInsensitive );
 
  291      msgBox.setIcon( QMessageBox::Warning );
 
  292      msgBox.setWindowTitle( tr( 
"Overwrite File" ) );
 
  293      msgBox.setText( tr( 
"This file contains %1 layers that will be lost!\n" ).arg( QLocale().toString( layerList.length() ) ) );
 
  294      msgBox.setDetailedText( tr( 
"The following layers will be permanently lost:\n\n%1" ).arg( layerList.join( 
"\n" ) ) );
 
  295      msgBox.setStandardButtons( QMessageBox::Ok | QMessageBox::Cancel );
 
  296      if ( msgBox.exec() == QMessageBox::Cancel )
 
  302  settings.
setValue( QStringLiteral( 
"UI/lastPointCloudFileFilterDir" ), QFileInfo( 
filename() ).absolutePath() );
 
  303  settings.
setValue( QStringLiteral( 
"UI/lastPointCloudFormat" ), 
static_cast< int >( 
exportFormat() ) );
 
  307void QgsPointCloudLayerSaveAsDialog::mFormatComboBox_currentIndexChanged( 
int idx )
 
  319      mAttributesSelection->setEnabled( 
true );
 
  324      mAttributesSelection->setEnabled( 
false );
 
  332      leLayername->setEnabled( 
true );
 
  339      leLayername->setEnabled( 
false );
 
  346      mWasAddToCanvasForced = !mAddToCanvas->isChecked();
 
  347      mAddToCanvas->setEnabled( 
false );
 
  348      mAddToCanvas->setChecked( 
true );
 
  349      mFilename->setEnabled( 
false );
 
  357      mAddToCanvas->setEnabled( 
true );
 
  358      if ( mWasAddToCanvasForced )
 
  360        mAddToCanvas->setChecked( !mAddToCanvas->isChecked() );
 
  361        mWasAddToCanvasForced = 
false;
 
  363      mFilename->setEnabled( 
true );
 
  367  if ( mFilename->isEnabled() )
 
  369    mFilename->setFilter( getFilterForFormat( format ) );
 
  373    if ( !mLastUsedFilename.isEmpty() )
 
  375      const thread_local QRegularExpression rx( 
"\\.(.*?)[\\s]" );
 
  377      ext = rx.match( getFilterForFormat( format ) ).captured( 1 );
 
  378      if ( !ext.isEmpty() )
 
  380        QFileInfo fi( mLastUsedFilename );
 
  381        mFilename->setFilePath( QStringLiteral( 
"%1/%2.%3" ).arg( fi.path(), fi.baseName(), ext ) );
 
  386  if ( !mFilename->isEnabled() )
 
  387    mFilename->setFilePath( QString() );
 
  389  if ( !leLayername->isEnabled() )
 
  391    leLayername->setText( QString() );
 
  393  else if ( leLayername->text().isEmpty() )
 
  395    QString layerName = mDefaultOutputLayerNameFromInputLayerName;
 
  396    if ( layerName.isEmpty() && !mFilename->filePath().isEmpty() )
 
  398      layerName = QFileInfo( mFilename->filePath() ).baseName();
 
  399      leLayername->setDefaultValue( layerName );
 
  401    if ( layerName.isEmpty() )
 
  403      layerName = tr( 
"new_layer" );
 
  405    leLayername->setText( layerName );
 
  409      !mFilename->filePath().isEmpty() );
 
  412void QgsPointCloudLayerSaveAsDialog::mFilterGeometryGroupBoxCheckToggled( 
bool checked )
 
  415    mFilterGeometryLayerChanged( mFilterGeometryLayerComboBox->currentLayer() );
 
  418void QgsPointCloudLayerSaveAsDialog::mFilterGeometryLayerChanged( 
QgsMapLayer *layer )
 
  421  mSelectedFeaturesCheckBox->setChecked( 
false );
 
  425void QgsPointCloudLayerSaveAsDialog::mMinimumZSpinBoxValueChanged( 
const double value )
 
  427  mMaximumZSpinBox->setMinimum( value );
 
  430void QgsPointCloudLayerSaveAsDialog::mMaximumZSpinBoxValueChanged( 
const double value )
 
  432  mMinimumZSpinBox->setMaximum( value );
 
  438  mExtentGroupBox->setOutputCrs( mSelectedCrs );
 
  443  return mFilename->filePath();
 
 
  448  return leLayername->text();
 
 
  465  for ( 
int i = 0; i < mAttributeTable->rowCount(); i++ )
 
  467    if ( mAttributeTable->item( i, 0 )->checkState() == Qt::Checked )
 
  469      attributes.append( mAttributeTable->item( i, 0 )->text() );
 
 
  478  return mAddToCanvas->isChecked();
 
 
  483  mAddToCanvas->setChecked( enabled );
 
 
  494  return mExtentGroupBox->isChecked();
 
 
  499  return mExtentGroupBox->outputExtent();
 
 
  504  return mFilterGeometryGroupBox->isChecked() && mFilterGeometryLayerComboBox->count() > 0;
 
 
  509  return mFilterGeometryLayerComboBox->currentLayer();
 
 
  514  return hasFilterLayer() && mSelectedFeaturesCheckBox->isChecked();
 
 
  519  return mAttributesSelection->isChecked() && mAttributesSelection->isEnabled();
 
 
  524  return mZRangeGroupBox->isChecked();
 
 
  529  return QgsDoubleRange( mMinimumZSpinBox->value(), mMaximumZSpinBox->value() );
 
 
  534  return mPointsLimitGroupBox->isChecked();
 
 
  539  return mPointsLimitSpinBox->value();
 
 
  544  return mActionOnExistingFile;
 
 
  547void QgsPointCloudLayerSaveAsDialog::mSelectAllAttributes_clicked()
 
  549  for ( 
int i = 0; i < mAttributeTable->rowCount(); i++ )
 
  551    mAttributeTable->item( i, 0 )->setCheckState( Qt::Checked );
 
  555void QgsPointCloudLayerSaveAsDialog::mDeselectAllAttributes_clicked()
 
  558    for ( 
int i = 0; i < mAttributeTable->rowCount(); i++ )
 
  560      mAttributeTable->item( i, 0 )->setCheckState( Qt::Unchecked );
 
  565void QgsPointCloudLayerSaveAsDialog::showHelp()
 
  567  QgsHelp::openHelp( QStringLiteral( 
"managing_data_source/create_layers.html#creating-new-layers-from-an-existing-layer" ) );
 
  575      return QStringLiteral( 
"LAZ point cloud (*.laz *.LAZ);;LAS point cloud (*.las *.LAS)" );
 
  577      return QStringLiteral( 
"GeoPackage (*.gpkg *.GPKG)" );
 
  579      return QStringLiteral( 
"AutoCAD DXF (*.dxf *.dxf)" );
 
  581      return QStringLiteral( 
"ESRI Shapefile (*.shp *.SHP)" );
 
  583      return QStringLiteral( 
"Comma separated values (*.csv *.CSV)" );
 
  595      return tr( 
"Temporary Scratch Layer" );
 
  597      return tr( 
"GeoPackage" );
 
  599      return tr( 
"AutoCAD DXF" );
 
  601      return tr( 
"ESRI Shapefile" );
 
  603      return tr( 
"LAS/LAZ point cloud" );
 
  605      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