QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
Loading...
Searching...
No Matches
qgsvectorlayersaveasdialog.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvectorlayersaveasdialog.h
3 Dialog to select destination, type and crs for ogr layers
4 -------------------
5 begin : Mon Mar 22 2010
6 copyright : (C) 2010 by Juergen E. Fischer
7 email : jef at norbit dot de
8 ***************************************************************************/
9
10/***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
19
20#include <gdal.h>
21#include <limits>
22#include <optional>
23
25#include "qgsdatums.h"
28#include "qgsgui.h"
29#include "qgshelp.h"
30#include "qgsiconutils.h"
31#include "qgslogger.h"
32#include "qgsmapcanvas.h"
33#include "qgsmaplayerutils.h"
34#include "qgsproviderregistry.h"
36#include "qgssettings.h"
38
39#include <QFileDialog>
40#include <QMessageBox>
41#include <QRegularExpression>
42#include <QSpinBox>
43#include <QString>
44#include <QTextCodec>
45
46#include "moc_qgsvectorlayersaveasdialog.cpp"
47
48using namespace Qt::StringLiterals;
49
50QgsVectorLayerSaveAsDialog::QgsVectorLayerSaveAsDialog( long srsid, QWidget *parent, Qt::WindowFlags fl )
51 : QDialog( parent, fl )
52 , mSelectedCrs( QgsCoordinateReferenceSystem::fromSrsId( srsid ) )
53 , mActionOnExistingFile( QgsVectorFileWriter::CreateOrOverwriteFile )
54{
55 setup();
56}
57
59 : QDialog( parent, fl )
60 , mLayer( layer )
61 , mActionOnExistingFile( QgsVectorFileWriter::CreateOrOverwriteFile )
62 , mOptions( options )
63{
64 if ( layer )
65 {
66 mSelectedCrs = layer->crs();
67 mLayerExtent = layer->extent();
68 }
69 setup();
70
71 if ( layer )
72 {
73 mDefaultOutputLayerNameFromInputLayerName = QgsMapLayerUtils::launderLayerName( layer->name() );
74 leLayername->setDefaultValue( mDefaultOutputLayerNameFromInputLayerName );
75 leLayername->setClearMode( QgsFilterLineEdit::ClearToDefault );
76 if ( leLayername->isEnabled() )
77 leLayername->setText( mDefaultOutputLayerNameFromInputLayerName );
78 }
79
80 if ( !( mOptions & Option::Symbology ) )
81 {
82 mSymbologyExportLabel->hide();
83 mSymbologyExportComboBox->hide();
84 mScaleLabel->hide();
85 mScaleWidget->hide();
86 }
87
88 if ( !( mOptions & Option::DestinationCrs ) )
89 {
90 mCrsLabel->hide();
91 mCrsSelector->hide();
92 }
93 if ( !( mOptions & Option::Fields ) )
94 mAttributesSelection->hide();
95
96 if ( !( mOptions & Option::SelectedOnly ) )
97 mSelectedOnly->hide();
98
99 if ( !( mOptions & Option::AddToCanvas ) )
100 mAddToCanvas->hide();
101
102 if ( !( mOptions & Option::GeometryType ) )
103 mGeometryGroupBox->hide();
104
105 if ( !( mOptions & Option::Extent ) )
106 mExtentGroupBox->hide();
107
108 if ( !( mOptions & Option::Metadata ) )
109 {
110 mCheckPersistMetadata->setChecked( false );
111 mCheckPersistMetadata->hide();
112 }
113
114 mSelectedOnly->setEnabled( layer && layer->selectedFeatureCount() != 0 );
115 mButtonBox->button( QDialogButtonBox::Ok )->setDisabled( true );
116}
117
118void QgsVectorLayerSaveAsDialog::setup()
119{
120 setupUi( this );
122
123 connect( mFormatComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsVectorLayerSaveAsDialog::mFormatComboBox_currentIndexChanged );
124 connect( mCrsSelector, &QgsProjectionSelectionWidget::crsChanged, this, &QgsVectorLayerSaveAsDialog::mCrsSelector_crsChanged );
125 connect( mSymbologyExportComboBox, &QComboBox::currentTextChanged, this, &QgsVectorLayerSaveAsDialog::mSymbologyExportComboBox_currentIndexChanged );
126 connect( mGeometryTypeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsVectorLayerSaveAsDialog::mGeometryTypeComboBox_currentIndexChanged );
127 connect( mSelectAllAttributes, &QPushButton::clicked, this, &QgsVectorLayerSaveAsDialog::mSelectAllAttributes_clicked );
128 connect( mDeselectAllAttributes, &QPushButton::clicked, this, &QgsVectorLayerSaveAsDialog::mDeselectAllAttributes_clicked );
129 connect( mUseAliasesForExportedName, &QCheckBox::stateChanged, this, &QgsVectorLayerSaveAsDialog::mUseAliasesForExportedName_stateChanged );
130 connect( mReplaceRawFieldValues, &QCheckBox::stateChanged, this, &QgsVectorLayerSaveAsDialog::mReplaceRawFieldValues_stateChanged );
131 connect( mAttributeTable, &QTableWidget::itemChanged, this, &QgsVectorLayerSaveAsDialog::mAttributeTable_itemChanged );
132
133#ifdef Q_OS_WIN
134 mHelpButtonBox->setVisible( false );
135 mButtonBox->addButton( QDialogButtonBox::Help );
136 connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsVectorLayerSaveAsDialog::showHelp );
137#else
138 connect( mHelpButtonBox, &QDialogButtonBox::helpRequested, this, &QgsVectorLayerSaveAsDialog::showHelp );
139#endif
140 connect( mButtonBox, &QDialogButtonBox::accepted, this, &QgsVectorLayerSaveAsDialog::accept );
141 connect( mButtonBox, &QDialogButtonBox::rejected, this, &QgsVectorLayerSaveAsDialog::reject );
142
143 const QList<QgsVectorFileWriter::DriverDetails> drivers = QgsVectorFileWriter::ogrDriverList();
144 mFormatComboBox->blockSignals( true );
145 for ( const QgsVectorFileWriter::DriverDetails &driver : drivers )
146 {
147 mFormatComboBox->addItem( driver.longName, driver.driverName );
148 }
149
150 QgsSettings settings;
151 QString format = settings.value( u"UI/lastVectorFormat"_s, "GPKG" ).toString();
152 mFormatComboBox->setCurrentIndex( mFormatComboBox->findData( format ) );
153 mFormatComboBox->blockSignals( false );
154
155 const auto addGeomItem = [this]( Qgis::WkbType type ) {
156 mGeometryTypeComboBox->addItem( QgsIconUtils::iconForWkbType( type ), QgsWkbTypes::translatedDisplayString( type ), static_cast<quint32>( type ) );
157 };
158
159 //add geometry types to combobox
160 mGeometryTypeComboBox->addItem( tr( "Automatic" ), -1 );
161 addGeomItem( Qgis::WkbType::Point );
162 addGeomItem( Qgis::WkbType::LineString );
163 addGeomItem( Qgis::WkbType::Polygon );
164 mGeometryTypeComboBox->addItem( QgsWkbTypes::translatedDisplayString( Qgis::WkbType::GeometryCollection ), static_cast<quint32>( Qgis::WkbType::GeometryCollection ) );
165 addGeomItem( Qgis::WkbType::NoGeometry );
166 mGeometryTypeComboBox->setCurrentIndex( mGeometryTypeComboBox->findData( -1 ) );
167
168 mEncodingComboBox->addItems( QgsVectorDataProvider::availableEncodings() );
169
170 QString enc = settings.value( u"UI/encoding"_s, "System" ).toString();
171 int idx = mEncodingComboBox->findText( enc );
172 if ( idx < 0 )
173 {
174 mEncodingComboBox->insertItem( 0, enc );
175 idx = 0;
176 }
177
178 mCrsSelector->setCrs( mSelectedCrs );
179 mCrsSelector->setLayerCrs( mSelectedCrs );
180 mCrsSelector->setMessage( tr( "Select the coordinate reference system for the vector file. "
181 "The data points will be transformed from the layer coordinate reference system." ) );
182
183 mEncodingComboBox->setCurrentIndex( idx );
184 mFormatComboBox_currentIndexChanged( mFormatComboBox->currentIndex() );
185
186 //symbology export combo box
187 mSymbologyExportComboBox->addItem( tr( "No Symbology" ), QVariant::fromValue( Qgis::FeatureSymbologyExport::NoSymbology ) );
188 mSymbologyExportComboBox->addItem( tr( "Feature Symbology" ), QVariant::fromValue( Qgis::FeatureSymbologyExport::PerFeature ) );
189 mSymbologyExportComboBox->addItem( tr( "Symbol Layer Symbology" ), QVariant::fromValue( Qgis::FeatureSymbologyExport::PerSymbolLayer ) );
190 mSymbologyExportComboBox_currentIndexChanged( mSymbologyExportComboBox->currentText() );
191
192 // extent group box
193 mExtentGroupBox->setOutputCrs( mSelectedCrs );
194 mExtentGroupBox->setOriginalExtent( mLayerExtent, mSelectedCrs );
195 mExtentGroupBox->setOutputExtentFromOriginal();
196 mExtentGroupBox->setCheckable( true );
197 mExtentGroupBox->setChecked( false );
198 mExtentGroupBox->setCollapsed( true );
199
200 mFilename->setStorageMode( QgsFileWidget::SaveFile );
201 mFilename->setDialogTitle( tr( "Save Layer As" ) );
202 mFilename->setDefaultRoot( settings.value( u"UI/lastVectorFileFilterDir"_s, QDir::homePath() ).toString() );
203 mFilename->setConfirmOverwrite( false );
204 connect( mFilename, &QgsFileWidget::fileChanged, this, [this]( const QString &filePath ) {
205 QgsSettings settings;
206 QFileInfo tmplFileInfo( filePath );
207 settings.setValue( u"UI/lastVectorFileFilterDir"_s, tmplFileInfo.absolutePath() );
208
209 const QFileInfo fileInfo( filePath );
210 const QString suggestedLayerName = QgsMapLayerUtils::launderLayerName( fileInfo.completeBaseName() );
211 if ( mDefaultOutputLayerNameFromInputLayerName.isEmpty() )
212 leLayername->setDefaultValue( suggestedLayerName );
213
214 // if no layer name set, then automatically match the output layer name to the file name
215 if ( leLayername->text().isEmpty() && !filePath.isEmpty() && leLayername->isEnabled() )
216 {
217 leLayername->setText( suggestedLayerName );
218 }
219 mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( !filePath.isEmpty() );
220 } );
221
222 try
223 {
224 const QgsDatumEnsemble ensemble = mSelectedCrs.datumEnsemble();
225 if ( ensemble.isValid() )
226 {
227 mCrsSelector->setSourceEnsemble( ensemble.name() );
228 }
229 }
230 catch ( QgsNotSupportedException & )
231 {
232 }
233
234 mCrsSelector->setShowAccuracyWarnings( true );
235}
236
237QList<QPair<QLabel *, QWidget *>> QgsVectorLayerSaveAsDialog::createControls( const QMap<QString, QgsVectorFileWriter::Option *> &options )
238{
239 QList<QPair<QLabel *, QWidget *>> controls;
240 QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
241
242 for ( it = options.constBegin(); it != options.constEnd(); ++it )
243 {
244 QgsVectorFileWriter::Option *option = it.value();
245 QWidget *control = nullptr;
246 switch ( option->type )
247 {
249 {
250 QgsVectorFileWriter::IntOption *opt = dynamic_cast<QgsVectorFileWriter::IntOption *>( option );
251 if ( opt )
252 {
253 QSpinBox *sb = new QSpinBox();
254 sb->setObjectName( it.key() );
255 sb->setMaximum( std::numeric_limits<int>::max() ); // the default is 99
256 sb->setValue( opt->defaultValue );
257 control = sb;
258 }
259 break;
260 }
261
263 {
264 QgsVectorFileWriter::SetOption *opt = dynamic_cast<QgsVectorFileWriter::SetOption *>( option );
265 if ( opt )
266 {
267 QComboBox *cb = new QComboBox();
268 cb->setObjectName( it.key() );
269 for ( const QString &val : std::as_const( opt->values ) )
270 {
271 cb->addItem( val, val );
272 }
273 if ( opt->allowNone )
274 cb->addItem( tr( "<Default>" ), QgsVariantUtils::createNullVariant( QMetaType::Type::QString ) );
275 int idx = cb->findText( opt->defaultValue );
276 if ( idx == -1 )
277 idx = cb->findData( QgsVariantUtils::createNullVariant( QMetaType::Type::QString ) );
278 cb->setCurrentIndex( idx );
279 control = cb;
280 }
281 break;
282 }
283
285 {
286 QgsVectorFileWriter::StringOption *opt = dynamic_cast<QgsVectorFileWriter::StringOption *>( option );
287 if ( opt )
288 {
289 QLineEdit *le = new QLineEdit( opt->defaultValue );
290 le->setObjectName( it.key() );
291 control = le;
292 }
293 break;
294 }
295
297 control = nullptr;
298 break;
299 }
300
301 if ( control )
302 {
303 QLabel *label = new QLabel( it.key() );
304
305 // Pack the tooltip in some html element, so it gets linebreaks.
306 label->setToolTip( u"<p>%1</p>"_s.arg( option->docString.toHtmlEscaped() ) );
307 control->setToolTip( u"<p>%1</p>"_s.arg( option->docString.toHtmlEscaped() ) );
308
309 controls << QPair<QLabel *, QWidget *>( label, control );
310 }
311 }
312
313 return controls;
314}
315
317{
318#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 9, 0 )
319 if ( format() == "OpenFileGDB"_L1 )
320 {
321 // The OpenFileGDB driver supports 64-bit integer fields starting with GDAL 3.9,
322 // if selecting the TARGET_ARCGIS_VERSION=ARCGIS_PRO_3_2_OR_LATER option
323 bool targetAll = true;
324 for ( const QString &layerOption : layerOptions() )
325 {
326 if ( layerOption == "TARGET_ARCGIS_VERSION=ARCGIS_PRO_3_2_OR_LATER"_L1 )
327 {
328 targetAll = false;
329 }
330 }
331 if ( targetAll )
332 {
333 const QgsAttributeList attributesSelected = selectedAttributes();
334 for ( int i = 0; i < attributesSelected.size(); ++i )
335 {
336 QgsField fld = mLayer->fields().at( attributesSelected.at( i ) );
337 if ( fld.type() == QMetaType::Type::LongLong )
338 {
339 if ( QMessageBox::question( this, tr( "Save Vector Layer As" ), tr( "The layer contains at least one 64-bit integer field, which, with the current settings, can only be exported as a Real field. It could be exported as a 64-bit integer field if the TARGET_ARCGIS_VERSION layer option is set to ARCGIS_PRO_3_2_OR_LATER. Do you want to continue and export it as a Real field?" ) ) != QMessageBox::Yes )
340 {
341 return;
342 }
343 break;
344 }
345 }
346 }
347 }
348 else if ( format() == "FileGDB"_L1 )
349 {
350 // The FileGDB driver based on the ESRI SDK doesn't support 64-bit integers
351 const QgsAttributeList attributesSelected = selectedAttributes();
352 for ( int i = 0; i < attributesSelected.size(); ++i )
353 {
354 QgsField fld = mLayer->fields().at( attributesSelected.at( i ) );
355 if ( fld.type() == QMetaType::Type::LongLong )
356 {
357 if ( QMessageBox::question( this, tr( "Save Vector Layer As" ), tr( "The layer contains at least one 64-bit integer field, which cannot be exported as such when using this output driver. 64-bit integer fields could be supported by selecting the %1 format and setting its TARGET_ARCGIS_VERSION layer option to ARCGIS_PRO_3_2_OR_LATER. Do you want to continue and export it as a Real field?" ).arg( tr( "ESRI File Geodatabase" ) ) ) != QMessageBox::Yes )
358 {
359 return;
360 }
361 break;
362 }
363 }
364 }
365#endif
366
367 if ( QFile::exists( fileName() ) )
368 {
371 QMessageBox msgBox;
372 msgBox.setIcon( QMessageBox::Question );
373 msgBox.setWindowTitle( tr( "Save Vector Layer As" ) );
374 QPushButton *overwriteFileButton = msgBox.addButton( tr( "Overwrite File" ), QMessageBox::ActionRole );
375 QPushButton *overwriteLayerButton = msgBox.addButton( tr( "Overwrite Layer" ), QMessageBox::ActionRole );
376 QPushButton *appendToLayerButton = msgBox.addButton( tr( "Append to Layer" ), QMessageBox::ActionRole );
377 msgBox.setStandardButtons( QMessageBox::Cancel );
378 msgBox.setDefaultButton( QMessageBox::Cancel );
379 overwriteFileButton->hide();
380 overwriteLayerButton->hide();
381 appendToLayerButton->hide();
382 if ( layerExists )
383 {
385 {
386 msgBox.setText( tr( "The layer already exists. Do you want to overwrite the whole file or overwrite the layer?" ) );
387 overwriteFileButton->setVisible( true );
388 overwriteLayerButton->setVisible( true );
389 }
391 {
392 msgBox.setText( tr( "The file already exists. Do you want to overwrite it?" ) );
393 overwriteFileButton->setVisible( true );
394 }
396 {
397 msgBox.setText( tr( "The layer already exists. Do you want to overwrite the whole file, overwrite the layer or append features to the layer?" ) );
398 appendToLayerButton->setVisible( true );
399 overwriteFileButton->setVisible( true );
400 overwriteLayerButton->setVisible( true );
401 }
402 else
403 {
404 msgBox.setText( tr( "The layer already exists. Do you want to overwrite the whole file or append features to the layer?" ) );
405 appendToLayerButton->setVisible( true );
406 overwriteFileButton->setVisible( true );
407 }
408
409 int ret = msgBox.exec();
410 if ( ret == QMessageBox::Cancel )
411 return;
412 if ( msgBox.clickedButton() == overwriteFileButton )
413 mActionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteFile;
414 else if ( msgBox.clickedButton() == overwriteLayerButton )
415 mActionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteLayer;
416 else if ( msgBox.clickedButton() == appendToLayerButton )
417 mActionOnExistingFile = QgsVectorFileWriter::AppendToLayerNoNewFields;
418 }
419 else // !layerExists
420 {
422 {
423 mActionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteLayer;
424 }
425 else
426 {
427 // should not reach here, layer does not exist and cannot add new layer
428 if ( QMessageBox::question( this, tr( "Save Vector Layer As" ), tr( "The file already exists. Do you want to overwrite it?" ) ) != QMessageBox::Yes )
429 {
430 return;
431 }
432 mActionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteFile;
433 }
434 }
435 }
436
437 if ( mActionOnExistingFile == QgsVectorFileWriter::AppendToLayerNoNewFields )
438 {
440 {
441 if ( QMessageBox::question( this, tr( "Save Vector Layer As" ), tr( "The existing layer has additional fields. Do you want to add the missing fields to the layer?" ) ) == QMessageBox::Yes )
442 {
443 mActionOnExistingFile = QgsVectorFileWriter::AppendToLayerAddFields;
444 }
445 }
446 }
447 else if ( mActionOnExistingFile == QgsVectorFileWriter::CreateOrOverwriteFile && QFile::exists( fileName() ) )
448 {
449 const QList<QgsProviderSublayerDetails> sublayers = QgsProviderRegistry::instance()->querySublayers( fileName() );
450 QStringList layerList;
451 layerList.reserve( sublayers.size() );
452 for ( const QgsProviderSublayerDetails &sublayer : sublayers )
453 {
454 layerList.append( sublayer.name() );
455 }
456 if ( layerList.length() > 1 )
457 {
458 layerList.sort( Qt::CaseInsensitive );
459 QMessageBox msgBox;
460 msgBox.setIcon( QMessageBox::Warning );
461 msgBox.setWindowTitle( tr( "Overwrite File" ) );
462 msgBox.setText( tr( "This file contains %1 layers that will be lost!\n" ).arg( QLocale().toString( layerList.length() ) ) );
463 msgBox.setDetailedText( tr( "The following layers will be permanently lost:\n\n%1" ).arg( layerList.join( "\n" ) ) );
464 msgBox.setStandardButtons( QMessageBox::Ok | QMessageBox::Cancel );
465 if ( msgBox.exec() == QMessageBox::Cancel )
466 return;
467 }
468 }
469
470 QgsSettings settings;
471 settings.setValue( u"UI/lastVectorFileFilterDir"_s, QFileInfo( fileName() ).absolutePath() );
472 settings.setValue( u"UI/lastVectorFormat"_s, format() );
473 settings.setValue( u"UI/encoding"_s, encoding() );
474 QDialog::accept();
475}
476
477void QgsVectorLayerSaveAsDialog::mFormatComboBox_currentIndexChanged( int idx )
478{
479 Q_UNUSED( idx )
480
481 mFilename->setEnabled( true );
482 QString filter = QgsVectorFileWriter::filterForDriver( format() );
483 // A bit of hack to solve https://github.com/qgis/QGIS/issues/54566
484 // to be able to select an existing File Geodatabase, we add in the filter
485 // the "gdb" file that is found in all File Geodatabase .gdb directory
486 // to allow the user to select it. We need to detect this particular case
487 // in QgsFileWidget::openFileDialog() to remove this gdb file from the
488 // selected filename
489 if ( format() == "OpenFileGDB"_L1 || format() == "FileGDB"_L1 )
490 filter = u"%1 (*.gdb *.GDB gdb)"_s.arg( tr( "ESRI File Geodatabase" ) );
491 mFilename->setFilter( filter );
492
493 // if output filename already defined we need to replace old suffix
494 // to avoid double extensions like .gpkg.shp
495 if ( !mFilename->filePath().isEmpty() )
496 {
497 const thread_local QRegularExpression rx( "\\.(.*?)[\\s]" );
498 const QString ext = rx.match( filter ).captured( 1 );
499 if ( !ext.isEmpty() )
500 {
501 QFileInfo fi( mFilename->filePath() );
502 mFilename->setFilePath( u"%1/%2.%3"_s.arg( fi.path(), fi.baseName(), ext ) );
503 }
504 }
505
506 bool selectAllFields = true;
507
508 // Is it a format for which fields that have attached widgets of types
509 // ValueMap, ValueRelation, etc. should be by default exported with their displayed
510 // values
511 bool isFormatForFieldsAsDisplayedValues = false;
512
513 const QString sFormat( format() );
514 if ( sFormat == "DXF"_L1 || sFormat == "DGN"_L1 )
515 {
516 mAttributesSelection->setVisible( false );
517 selectAllFields = false;
518 }
519 else
520 {
521 if ( mOptions & Option::Fields )
522 {
523 mAttributesSelection->setVisible( true );
524 isFormatForFieldsAsDisplayedValues = ( sFormat == "CSV"_L1 || sFormat == "XLS"_L1 || sFormat == "XLSX"_L1 || sFormat == "ODS"_L1 );
525 }
526 }
527
528 // Show symbology options only for some formats
529 if ( QgsVectorFileWriter::supportsFeatureStyles( sFormat ) && ( mOptions & Option::Symbology ) )
530 {
531 mSymbologyExportLabel->setVisible( true );
532 mSymbologyExportComboBox->setVisible( true );
533 mScaleLabel->setVisible( true );
534 mScaleWidget->setVisible( true );
535 }
536 else
537 {
538 mSymbologyExportLabel->hide();
539 mSymbologyExportComboBox->hide();
540 mScaleLabel->hide();
541 mScaleWidget->hide();
542 }
543
544 leLayername->setEnabled( sFormat == "KML"_L1 || sFormat == "GPKG"_L1 || sFormat == "XLSX"_L1 || sFormat == "ODS"_L1 || sFormat == "FileGDB"_L1 || sFormat == "OpenFileGDB"_L1 || sFormat == "SQLite"_L1 || sFormat == "SpatiaLite"_L1 );
545
546 if ( sFormat == "XLSX"_L1 )
547 leLayername->setMaxLength( 31 );
548 else if ( leLayername->isEnabled() )
549 leLayername->setMaxLength( 32767 ); // default length
550
551 if ( !leLayername->isEnabled() )
552 leLayername->setText( QString() );
553 else if ( leLayername->text().isEmpty() )
554 {
555 QString layerName = mDefaultOutputLayerNameFromInputLayerName;
556 if ( layerName.isEmpty() && !mFilename->filePath().isEmpty() )
557 {
558 layerName = QFileInfo( mFilename->filePath() ).baseName();
559 leLayername->setDefaultValue( layerName );
560 }
561 if ( layerName.isEmpty() )
562 layerName = tr( "new_layer" );
563 leLayername->setText( layerName );
564 }
565
566 if ( mLayer )
567 {
568 // save fields state: if it is checked and should be exported as displayed value
569 const bool isPreviousFormatForFieldsAsDisplayedValues = ( mPreviousFormat == "CSV"_L1 || mPreviousFormat == "XLS"_L1 || mPreviousFormat == "XLSX"_L1 || mPreviousFormat == "ODS"_L1 );
570 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
571 {
572 QTableWidgetItem *nameItem = mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) );
573 if ( !nameItem )
574 {
575 continue;
576 }
577
578 const QString fieldName = nameItem->text();
579 const bool exportField = ( nameItem->checkState() == Qt::Checked );
580
581 std::optional<bool> exportAsValue = std::nullopt;
582 if ( isPreviousFormatForFieldsAsDisplayedValues )
583 {
584 QTableWidgetItem *valueItem = mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) );
585 if ( valueItem && ( valueItem->flags() & Qt::ItemIsUserCheckable ) )
586 {
587 exportAsValue = ( valueItem->checkState() == Qt::Checked );
588 }
589 }
590 else
591 {
592 exportAsValue = mFieldsState[fieldName].second;
593 }
594
595 mFieldsState[fieldName] = { exportField, exportAsValue };
596 }
597
598 mPreviousFormat = sFormat;
599
600 mAttributeTable->setRowCount( mLayer->fields().count() );
601
602 QStringList horizontalHeaders = QStringList() << tr( "Name" ) << tr( "Export name" ) << tr( "Type" ) << tr( "Replace with displayed values" );
603 mAttributeTable->setColumnCount( static_cast<int>( horizontalHeaders.size() ) );
604 mAttributeTable->setHorizontalHeaderLabels( horizontalHeaders );
605
606 bool foundFieldThatCanBeExportedAsDisplayedValue = false;
607 for ( int i = 0; i < mLayer->fields().size(); ++i )
608 {
609 const QgsEditorWidgetSetup setup = QgsGui::editorWidgetRegistry()->findBest( mLayer, mLayer->fields()[i].name() );
610 if ( setup.type() != "TextEdit"_L1 && QgsGui::editorWidgetRegistry()->factory( setup.type() ) )
611 {
612 foundFieldThatCanBeExportedAsDisplayedValue = true;
613 break;
614 }
615 }
616 mAttributeTable->setColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ), !foundFieldThatCanBeExportedAsDisplayedValue );
617
618 bool allChecked = true;
619 bool allUnchecked = true;
620 bool anyEnabled = false;
621
622 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
623 {
624 for ( int i = 0; i < mLayer->fields().size(); ++i )
625 {
626 QgsField fld = mLayer->fields().at( i );
627 Qt::ItemFlags flags = mLayer->providerType() != "oracle"_L1 || !fld.typeName().contains( "SDO_GEOMETRY"_L1 ) ? Qt::ItemIsEnabled : Qt::NoItemFlags;
628 QTableWidgetItem *item = nullptr;
629 const QString fieldName = fld.name();
630 const bool exportField = mFieldsState.contains( fieldName ) ? mFieldsState[fieldName].first : selectAllFields;
631 item = new QTableWidgetItem( fieldName );
632 item->setFlags( flags | Qt::ItemIsUserCheckable );
633 item->setCheckState( ( exportField ) ? Qt::Checked : Qt::Unchecked );
634 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::Name ), item );
635
636 item = new QTableWidgetItem( fieldName );
637 item->setFlags( flags | Qt::ItemIsEditable );
638 item->setData( Qt::UserRole, fld.displayName() );
639 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::ExportName ), item );
640
641 item = new QTableWidgetItem( fld.typeName() );
642 item->setFlags( flags );
643 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::Type ), item );
644
645 if ( foundFieldThatCanBeExportedAsDisplayedValue )
646 {
647 const QgsEditorWidgetSetup setup = QgsGui::editorWidgetRegistry()->findBest( mLayer, mLayer->fields()[i].name() );
648 QgsEditorWidgetFactory *factory = nullptr;
649 const QString widgetId( setup.type() );
650 if ( flags == Qt::ItemIsEnabled && widgetId != "TextEdit"_L1 && ( factory = QgsGui::editorWidgetRegistry()->factory( widgetId ) ) )
651 {
652 item = new QTableWidgetItem( tr( "Use %1" ).arg( factory->name() ) );
653 bool exportAsValue;
654 if ( mFieldsState.contains( fieldName ) && mFieldsState[fieldName].second.has_value() )
655 {
656 exportAsValue = mFieldsState[fieldName].second.value();
657 }
658 else
659 {
660 exportAsValue = ( exportField && isFormatForFieldsAsDisplayedValues && ( widgetId == "ValueMap"_L1 || widgetId == "ValueRelation"_L1 || widgetId == "CheckBox"_L1 || widgetId == "RelationReference"_L1 ) );
661 }
662 item->setFlags( ( exportField ) ? ( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable ) : Qt::ItemIsUserCheckable );
663 item->setCheckState( exportAsValue ? Qt::Checked : Qt::Unchecked );
664 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ), item );
665
666 // collect information for setting mReplaceRawFieldValues state
667 if ( exportField )
668 {
669 anyEnabled = true;
670 if ( exportAsValue )
671 allUnchecked = false;
672 else
673 allChecked = false;
674 }
675 }
676 else
677 {
678 item = new QTableWidgetItem();
679 item->setFlags( Qt::NoItemFlags );
680 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ), item );
681 }
682 }
683 }
684 }
685
686 Qt::CheckState replaceRawState;
687 if ( !anyEnabled || allUnchecked )
688 replaceRawState = Qt::Unchecked;
689 else if ( allChecked )
690 replaceRawState = Qt::Checked;
691 else
692 replaceRawState = Qt::PartiallyChecked;
693
694 whileBlocking( mReplaceRawFieldValues )->setCheckState( replaceRawState );
695 mReplaceRawFieldValues->setEnabled( selectAllFields && anyEnabled );
696 mReplaceRawFieldValues->setVisible( foundFieldThatCanBeExportedAsDisplayedValue );
697
698 mAttributeTable->resizeColumnsToContents();
699 }
700
701 QgsVectorFileWriter::MetaData driverMetaData;
702
703 while ( mDatasourceOptionsGroupBox->layout()->count() )
704 {
705 QLayoutItem *item = mDatasourceOptionsGroupBox->layout()->takeAt( 0 );
706 delete item->widget();
707 delete item;
708 }
709
710 while ( mLayerOptionsGroupBox->layout()->count() )
711 {
712 QLayoutItem *item = mLayerOptionsGroupBox->layout()->takeAt( 0 );
713 delete item->widget();
714 delete item;
715 }
716
717 typedef QPair<QLabel *, QWidget *> LabelControlPair;
718
719 if ( QgsVectorFileWriter::driverMetadata( format(), driverMetaData ) )
720 {
721 if ( !driverMetaData.driverOptions.empty() )
722 {
723 mDatasourceOptionsGroupBox->setVisible( true );
724 QList<QPair<QLabel *, QWidget *>> controls = createControls( driverMetaData.driverOptions );
725
726 QFormLayout *datasourceLayout = dynamic_cast<QFormLayout *>( mDatasourceOptionsGroupBox->layout() );
727
728 const auto constControls = controls;
729 for ( LabelControlPair control : constControls )
730 {
731 datasourceLayout->addRow( control.first, control.second );
732 }
733 }
734 else
735 {
736 mDatasourceOptionsGroupBox->setVisible( false );
737 }
738
739 if ( !driverMetaData.layerOptions.empty() )
740 {
741 mLayerOptionsGroupBox->setVisible( true );
742 QList<QPair<QLabel *, QWidget *>> controls = createControls( driverMetaData.layerOptions );
743
744 QFormLayout *layerOptionsLayout = dynamic_cast<QFormLayout *>( mLayerOptionsGroupBox->layout() );
745
746 const auto constControls = controls;
747 for ( LabelControlPair control : constControls )
748 {
749 layerOptionsLayout->addRow( control.first, control.second );
750 }
751 }
752 else
753 {
754 mLayerOptionsGroupBox->setVisible( false );
755 }
756
757 if ( driverMetaData.compulsoryEncoding.isEmpty() )
758 {
759 mEncodingComboBox->setEnabled( true );
760 }
761 else
762 {
763 int idx = mEncodingComboBox->findText( driverMetaData.compulsoryEncoding );
764 if ( idx >= 0 )
765 {
766 mEncodingComboBox->setCurrentIndex( idx );
767 mEncodingComboBox->setDisabled( true );
768 }
769 else
770 {
771 mEncodingComboBox->setEnabled( true );
772 }
773 }
774 }
775 else
776 {
777 mEncodingComboBox->setEnabled( true );
778 }
779
780 GDALDriverH hDriver = GDALGetDriverByName( format().toUtf8().constData() );
781 if ( hDriver )
782 {
783 const bool canReopen = GDALGetMetadataItem( hDriver, GDAL_DCAP_OPEN, nullptr );
784 if ( mAddToCanvas->isEnabled() && !canReopen )
785 {
786 mAddToCanvasStateOnOpenCompatibleDriver = mAddToCanvas->isChecked();
787 mAddToCanvas->setChecked( false );
788 mAddToCanvas->setEnabled( false );
789 }
790 else if ( !mAddToCanvas->isEnabled() && canReopen )
791 {
792 mAddToCanvas->setChecked( mAddToCanvasStateOnOpenCompatibleDriver );
793 mAddToCanvas->setEnabled( true );
794 }
795 }
796}
797
798void QgsVectorLayerSaveAsDialog::mUseAliasesForExportedName_stateChanged( int state )
799{
800 const QSignalBlocker signalBlocker( mAttributeTable );
801
802 switch ( state )
803 {
804 case Qt::Unchecked:
805 {
806 // Check for modified entries
807 bool modifiedEntries = false;
808 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
809 {
810 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->text()
811 != mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->data( Qt::UserRole ).toString() )
812 {
813 modifiedEntries = true;
814 break;
815 }
816 }
817
818 if ( modifiedEntries )
819 {
820 if ( QMessageBox::question( this, tr( "Modified names" ), tr( "Some names were modified and will be overridden. Do you want to continue?" ) )
821 == QMessageBox::No )
822 {
823 whileBlocking( mUseAliasesForExportedName )->setCheckState( Qt::PartiallyChecked );
824 return;
825 }
826 }
827
828 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
829 {
830 mUseAliasesForExportedName->setTristate( false );
831 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->setText( mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->text() );
832 }
833 }
834 break;
835 case Qt::Checked:
836 {
837 // Check for modified entries
838 bool modifiedEntries = false;
839 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
840 {
841 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->text()
842 != mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->text() )
843 modifiedEntries = true;
844 }
845
846 if ( modifiedEntries )
847 {
848 if ( QMessageBox::question( this, tr( "Modified names" ), tr( "Some names were modified and will be overridden. Do you want to continue?" ) )
849 == QMessageBox::No )
850 {
851 whileBlocking( mUseAliasesForExportedName )->setCheckState( Qt::PartiallyChecked );
852 return;
853 }
854 }
855
856 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
857 {
858 mUseAliasesForExportedName->setTristate( false );
859 const QString alias = mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->data( Qt::UserRole ).toString();
860 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->setText( alias );
861 }
862 }
863 break;
864 case Qt::PartiallyChecked:
865 // Do nothing
866 break;
867 }
868}
869
870void QgsVectorLayerSaveAsDialog::mReplaceRawFieldValues_stateChanged( int )
871{
872 if ( mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) )
873 return;
874
875 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
876 const QSignalBlocker signalBlockerReplaceRawFieldValues( mReplaceRawFieldValues );
877
878 if ( mReplaceRawFieldValues->checkState() != Qt::PartiallyChecked )
879 {
880 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
881 {
882 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->checkState() == Qt::Checked && mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) && mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsEnabled )
883 {
884 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setCheckState( mReplaceRawFieldValues->checkState() );
885 }
886 }
887 }
888 mReplaceRawFieldValues->setTristate( false );
889}
890
891void QgsVectorLayerSaveAsDialog::mAttributeTable_itemChanged( QTableWidgetItem *item )
892{
893 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
894 const QSignalBlocker signalBlockerReplaceRawFieldValues( mReplaceRawFieldValues );
895
896 int row = item->row();
897 int column = item->column();
898
899 switch ( static_cast<ColumnIndex>( column ) )
900 {
901 case ColumnIndex::Name:
902 {
903 if ( mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) || !mAttributeTable->item( row, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) || !( mAttributeTable->item( row, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsUserCheckable ) )
904 return;
905
906 if ( mAttributeTable->item( row, column )->checkState() == Qt::Unchecked )
907 {
908 mAttributeTable->item( row, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setCheckState( Qt::Unchecked );
909 mAttributeTable->item( row, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setFlags( Qt::ItemIsUserCheckable );
910 bool checkBoxEnabled = false;
911 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
912 {
913 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) && mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsEnabled )
914 {
915 checkBoxEnabled = true;
916 break;
917 }
918 }
919 mReplaceRawFieldValues->setEnabled( checkBoxEnabled );
920 if ( !checkBoxEnabled )
921 mReplaceRawFieldValues->setCheckState( Qt::Unchecked );
922 }
923 else if ( mAttributeTable->item( row, column )->checkState() == Qt::Checked )
924 {
925 mAttributeTable->item( row, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setFlags( Qt::ItemIsUserCheckable | Qt::ItemIsEnabled );
926 mReplaceRawFieldValues->setEnabled( true );
927 }
928 }
929 break;
930 case ColumnIndex::ExportName:
931 {
932 // Check empty export name
933 if ( item->text().isEmpty() )
934 {
935 QMessageBox::warning( this, tr( "Empty export name" ), tr( "Empty export name are not allowed." ) );
936 return;
937 }
938
939 // Rename eventually duplicated names
940 QStringList names = attributesExportNames();
941 while ( names.count( item->text() ) > 1 )
942 item->setText( QString( "%1_2" ).arg( item->text() ) );
943
944 mUseAliasesForExportedName->setCheckState( Qt::PartiallyChecked );
945 }
946 break;
947 case ColumnIndex::Type:
948 // Nothing to do
949 break;
950 case ColumnIndex::ExportAsDisplayedValue:
951 {
952 if ( mAttributeTable->item( row, column )->flags() & Qt::ItemIsUserCheckable )
953 {
954 bool allChecked = true;
955 bool allUnchecked = true;
956 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
957 {
958 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) && mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsEnabled )
959 {
960 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->checkState() == Qt::Unchecked )
961 allChecked = false;
962 else
963 allUnchecked = false;
964 }
965 }
966 mReplaceRawFieldValues->setCheckState( ( !allChecked && !allUnchecked ) ? Qt::PartiallyChecked : ( allChecked ) ? Qt::Checked
967 : Qt::Unchecked );
968 }
969 }
970 break;
971 }
972}
973
974void QgsVectorLayerSaveAsDialog::mCrsSelector_crsChanged( const QgsCoordinateReferenceSystem &crs )
975{
976 mSelectedCrs = crs;
977 mExtentGroupBox->setOutputCrs( mSelectedCrs );
978}
979
981{
982 return mFilename->filePath();
983}
984
986{
987 return leLayername->text();
988}
989
991{
992 return mEncodingComboBox->currentText();
993}
994
996{
997 return mFormatComboBox->currentData().toString();
998}
999
1001{
1002 return mSelectedCrs;
1003}
1004
1006{
1007 QStringList options;
1008
1009 QgsVectorFileWriter::MetaData driverMetaData;
1010
1011 if ( QgsVectorFileWriter::driverMetadata( format(), driverMetaData ) )
1012 {
1013 QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
1014
1015 for ( it = driverMetaData.driverOptions.constBegin(); it != driverMetaData.driverOptions.constEnd(); ++it )
1016 {
1017 switch ( it.value()->type )
1018 {
1020 {
1022 QSpinBox *sb = mDatasourceOptionsGroupBox->findChild<QSpinBox *>( it.key() );
1023 if ( opt && sb && sb->value() != opt->defaultValue )
1024 options << u"%1=%2"_s.arg( it.key() ).arg( sb->value() );
1025 break;
1026 }
1027
1029 {
1031 QComboBox *cb = mDatasourceOptionsGroupBox->findChild<QComboBox *>( it.key() );
1032 if ( opt && cb && cb->itemData( cb->currentIndex() ) != opt->defaultValue )
1033 options << u"%1=%2"_s.arg( it.key(), cb->currentText() );
1034 break;
1035 }
1036
1038 {
1040 QLineEdit *le = mDatasourceOptionsGroupBox->findChild<QLineEdit *>( it.key() );
1041 if ( opt && le && le->text() != opt->defaultValue )
1042 options << u"%1=%2"_s.arg( it.key(), le->text() );
1043 break;
1044 }
1045
1047 {
1048 QgsVectorFileWriter::HiddenOption *opt = dynamic_cast<QgsVectorFileWriter::HiddenOption *>( it.value() );
1049 if ( opt && !opt->mValue.isEmpty() )
1050 options << u"%1=%2"_s.arg( it.key(), opt->mValue );
1051 break;
1052 }
1053 }
1054 }
1055 }
1056
1057 QString plainText = mOgrDatasourceOptions->toPlainText().trimmed();
1058 if ( !plainText.isEmpty() )
1059 options += plainText.split( '\n' );
1060
1061 return options;
1062}
1063
1065{
1066 QStringList options;
1067
1068 QgsVectorFileWriter::MetaData driverMetaData;
1069
1070 if ( QgsVectorFileWriter::driverMetadata( format(), driverMetaData ) )
1071 {
1072 QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
1073
1074 for ( it = driverMetaData.layerOptions.constBegin(); it != driverMetaData.layerOptions.constEnd(); ++it )
1075 {
1076 switch ( it.value()->type )
1077 {
1079 {
1080 QgsVectorFileWriter::IntOption *opt = qgis::down_cast<QgsVectorFileWriter::IntOption *>( *it );
1081 QSpinBox *sb = mLayerOptionsGroupBox->findChild<QSpinBox *>( it.key() );
1082 if ( opt && sb && sb->value() != opt->defaultValue )
1083 options << u"%1=%2"_s.arg( it.key() ).arg( sb->value() );
1084 break;
1085 }
1086
1088 {
1089 QgsVectorFileWriter::SetOption *opt = qgis::down_cast<QgsVectorFileWriter::SetOption *>( *it );
1090 QComboBox *cb = mLayerOptionsGroupBox->findChild<QComboBox *>( it.key() );
1091 if ( opt && cb && cb->itemData( cb->currentIndex() ) != opt->defaultValue )
1092 options << u"%1=%2"_s.arg( it.key(), cb->currentText() );
1093 break;
1094 }
1095
1097 {
1098 QgsVectorFileWriter::StringOption *opt = qgis::down_cast<QgsVectorFileWriter::StringOption *>( *it );
1099 QLineEdit *le = mLayerOptionsGroupBox->findChild<QLineEdit *>( it.key() );
1100 if ( opt && le && le->text() != opt->defaultValue )
1101 options << u"%1=%2"_s.arg( it.key(), le->text() );
1102 break;
1103 }
1104
1106 {
1107 QgsVectorFileWriter::HiddenOption *opt = qgis::down_cast<QgsVectorFileWriter::HiddenOption *>( it.value() );
1108 if ( !opt->mValue.isEmpty() )
1109 options << u"%1=%2"_s.arg( it.key(), opt->mValue );
1110 break;
1111 }
1112 }
1113 }
1114 }
1115
1116 QString plainText = mOgrLayerOptions->toPlainText().trimmed();
1117 if ( !plainText.isEmpty() )
1118 options += plainText.split( '\n' );
1119
1120 return options;
1121}
1122
1124{
1125 QgsAttributeList attributes;
1126
1127 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1128 {
1129 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->checkState() == Qt::Checked )
1130 {
1131 attributes.append( i );
1132 }
1133 }
1134
1135 return attributes;
1136}
1137
1139{
1140 QgsAttributeList attributes;
1141
1142 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1143 {
1144 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->checkState() == Qt::Checked && !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) && mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->checkState() == Qt::Checked )
1145 {
1146 attributes.append( i );
1147 }
1148 }
1149
1150 return attributes;
1151}
1152
1154{
1155 QStringList exportNames;
1156 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1157 exportNames.append( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->text() );
1158
1159 return exportNames;
1160}
1161
1163{
1164 return mAddToCanvas->isChecked();
1165}
1166
1168{
1169 mAddToCanvasStateOnOpenCompatibleDriver = enabled;
1170 if ( mAddToCanvas->isEnabled() )
1171 mAddToCanvas->setChecked( enabled );
1172}
1173
1175{
1176 return mSymbologyExportComboBox->currentData().value<Qgis::FeatureSymbologyExport>();
1177}
1178
1180{
1181 return mScaleWidget->scale();
1182}
1183
1185{
1186 mMapCanvas = canvas;
1187 mScaleWidget->setMapCanvas( canvas );
1188 mScaleWidget->setShowCurrentScaleButton( true );
1189 mExtentGroupBox->setCurrentExtent( canvas->mapSettings().visibleExtent(), canvas->mapSettings().destinationCrs() );
1190}
1191
1193{
1194 return mExtentGroupBox->isChecked();
1195}
1196
1198{
1199 return mExtentGroupBox->outputExtent();
1200}
1201
1203{
1204 mSelectedOnly->setChecked( onlySelected );
1205}
1206
1208{
1209 return mSelectedOnly->isChecked();
1210}
1211
1213{
1214 return mCheckPersistMetadata->isChecked();
1215}
1216
1218{
1219 int currentIndexData = mGeometryTypeComboBox->currentData().toInt();
1220 if ( currentIndexData == -1 )
1221 {
1222 //automatic
1224 }
1225
1226 return static_cast<Qgis::WkbType>( currentIndexData );
1227}
1228
1230{
1231 int currentIndexData = mGeometryTypeComboBox->currentData().toInt();
1232 return currentIndexData == -1;
1233}
1234
1236{
1237 return mForceMultiCheckBox->isChecked();
1238}
1239
1241{
1242 mForceMultiCheckBox->setChecked( checked );
1243}
1244
1246{
1247 return mIncludeZCheckBox->isChecked();
1248}
1249
1254
1256{
1257 mIncludeZCheckBox->setChecked( checked );
1258}
1259
1260void QgsVectorLayerSaveAsDialog::mSymbologyExportComboBox_currentIndexChanged( const QString &text )
1261{
1262 bool scaleEnabled = true;
1263 if ( text == tr( "No symbology" ) )
1264 {
1265 scaleEnabled = false;
1266 }
1267 mScaleWidget->setEnabled( scaleEnabled );
1268 mScaleLabel->setEnabled( scaleEnabled );
1269}
1270
1271void QgsVectorLayerSaveAsDialog::mGeometryTypeComboBox_currentIndexChanged( int )
1272{
1273 const int currentIndexData = mGeometryTypeComboBox->currentData().toInt();
1274 if ( currentIndexData != -1 && static_cast<Qgis::WkbType>( currentIndexData ) != Qgis::WkbType::NoGeometry )
1275 {
1276 mForceMultiCheckBox->setEnabled( true );
1277 mIncludeZCheckBox->setEnabled( true );
1278 }
1279 else
1280 {
1281 if ( static_cast<Qgis::WkbType>( currentIndexData ) == Qgis::WkbType::NoGeometry )
1282 {
1283 mForceMultiCheckBox->setEnabled( false );
1284 mForceMultiCheckBox->setChecked( false );
1285 }
1286 else
1287 {
1288 mForceMultiCheckBox->setEnabled( true );
1289 }
1290 mIncludeZCheckBox->setEnabled( false );
1291 mIncludeZCheckBox->setChecked( false );
1292 }
1293}
1294
1295void QgsVectorLayerSaveAsDialog::mSelectAllAttributes_clicked()
1296{
1297 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
1298 const QSignalBlocker signalBlockerReplaceRawFieldValues( mReplaceRawFieldValues );
1299
1300 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1301 {
1302 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->flags() & Qt::ItemIsEnabled )
1303 {
1304 if ( !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) && ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsUserCheckable ) )
1305 {
1306 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setFlags( Qt::ItemIsUserCheckable | Qt::ItemIsEnabled );
1307 }
1308 mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->setCheckState( Qt::Checked );
1309 }
1310 }
1311 if ( !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) )
1312 {
1313 mReplaceRawFieldValues->setEnabled( true );
1314 }
1315}
1316
1317void QgsVectorLayerSaveAsDialog::mDeselectAllAttributes_clicked()
1318{
1319 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
1320 const QSignalBlocker signalBlockerReplaceRawFieldValues( mReplaceRawFieldValues );
1321
1322 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1323 {
1324 mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->setCheckState( Qt::Unchecked );
1325 if ( !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) && ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsUserCheckable ) )
1326 {
1327 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setFlags( Qt::ItemIsUserCheckable );
1328 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setCheckState( Qt::Unchecked );
1329 }
1330 }
1331 if ( !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) )
1332 {
1333 mReplaceRawFieldValues->setCheckState( Qt::Unchecked );
1334 mReplaceRawFieldValues->setEnabled( false );
1335 }
1336}
1337
1338void QgsVectorLayerSaveAsDialog::showHelp()
1339{
1340 QgsHelp::openHelp( u"managing_data_source/create_layers.html#creating-new-layers-from-an-existing-layer"_s );
1341}
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:294
@ Point
Point.
Definition qgis.h:296
@ LineString
LineString.
Definition qgis.h:297
@ Polygon
Polygon.
Definition qgis.h:298
@ NoGeometry
No geometry.
Definition qgis.h:312
@ Unknown
Unknown.
Definition qgis.h:295
@ GeometryCollection
GeometryCollection.
Definition qgis.h:303
FeatureSymbologyExport
Options for exporting features considering their symbology.
Definition qgis.h:5913
@ PerFeature
Keeps the number of features and export symbology per feature.
Definition qgis.h:5915
@ PerSymbolLayer
Exports one feature per symbol layer (considering symbol levels).
Definition qgis.h:5916
@ NoSymbology
Export only data.
Definition qgis.h:5914
Represents a coordinate reference system (CRS).
bool isValid() const
Returns true if the datum ensemble is a valid object, or false if it is a null/invalid object.
Definition qgsdatums.h:106
QString name() const
Display name of datum ensemble.
Definition qgsdatums.h:111
QString name() const
Returns the human readable identifier name of this widget type.
QgsEditorWidgetSetup findBest(const QgsVectorLayer *vl, const QString &fieldName) const
Find the best editor widget and its configuration for a given field.
QgsEditorWidgetFactory * factory(const QString &widgetId)
Gets a factory for the given widget type id.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:56
QMetaType::Type type
Definition qgsfield.h:63
QString typeName() const
Gets the field type.
Definition qgsfield.cpp:158
QString name
Definition qgsfield.h:65
QString displayName() const
Returns the name to use when displaying this field.
Definition qgsfield.cpp:96
@ SaveFile
Select a single new or pre-existing file.
void fileChanged(const QString &path)
Emitted whenever the current file or directory path is changed.
@ ClearToDefault
Reset value to default value (see defaultValue() ).
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
Definition qgsgui.cpp:109
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:224
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:41
static QIcon iconForWkbType(Qgis::WkbType type)
Returns the icon for a vector layer whose geometry type is provided.
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.
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...
QString name
Definition qgsmaplayer.h:87
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:90
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.
void crsChanged(const QgsCoordinateReferenceSystem &crs)
Emitted when the selected CRS is changed.
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.
Definition qgssettings.h:68
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.
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
static QStringList availableEncodings()
Returns a list of available encodings.
A hidden option for file writing for a particular output format.
An available option for configuring file writing for a particular output format, presenting an intege...
QgsVectorFileWriter::OptionType type
An available option for configuring file writing for a particular output format, presenting a choice ...
An available option for configuring file writing for a particular output format, presenting a freefor...
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.
static bool supportsFeatureStyles(const QString &driverName)
Returns true if the specified driverName supports feature styles.
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.
static bool driverMetadata(const QString &driverName, MetaData &driverMetadata)
static QString filterForDriver(const QString &driverName)
Creates a filter for an OGR driver key.
static bool areThereNewFieldsToCreate(const QString &datasetName, const QString &layerName, QgsVectorLayer *layer, const QgsAttributeList &attributes)
Returns whether there are among the attributes specified some that do not exist yet in the layer.
static QList< QgsVectorFileWriter::DriverDetails > ogrDriverList(VectorFormatOptions options=SortRecommended)
Returns the driver list that can be used for dialogs.
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.
@ AppendToLayerAddFields
Append features to existing layer, and create new fields if needed.
bool onlySelected() const
Returns whether only selected features will be saved.
bool forceMulti() const
Returns true if force multi geometry type is checked.
QgsAttributeList selectedAttributes() const
Returns a list of attributes which are selected for saving.
QgsRectangle filterExtent() const
Determines the extent to be exported.
QString format() const
Returns the selected format in which the export should be written.
QStringList datasourceOptions() const
Returns a list of additional data source options which are passed to OGR.
bool persistMetadata() const
Returns true if the persist metadata (copy source metadata to destination layer) option is checked.
QString encoding() const
Returns the selected encoding for the target file.
void setIncludeZ(bool checked)
Sets whether the include z dimension checkbox should be checked.
QStringList attributesExportNames() const
Returns a list of export names for attributes.
QString fileName() const
Returns the target filename.
void setOnlySelected(bool onlySelected)
Sets whether only selected features will be saved.
QString layerName() const
Returns the target layer name.
bool automaticGeometryType() const
Returns true if geometry type is set to automatic.
Q_DECL_DEPRECATED QgsVectorLayerSaveAsDialog(long srsid, QWidget *parent=nullptr, Qt::WindowFlags fl=Qt::WindowFlags())
Construct a new QgsVectorLayerSaveAsDialog.
bool includeZ() const
Returns true if include z dimension is checked.
@ DestinationCrs
Show destination CRS (reprojection) option.
@ Fields
Show field customization group.
@ SelectedOnly
Show selected features only option.
QgsCoordinateReferenceSystem crs() const
Returns the CRS chosen for export.
QStringList layerOptions() const
Returns a list of additional layer options which are passed to OGR.
void setForceMulti(bool checked)
Sets whether the force multi geometry checkbox should be checked.
QFlags< Option > Options
Available dialog options.
bool addToCanvas() const
Returns true if the "add to canvas" checkbox is checked.
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas to associate with the dialog.
Qgis::WkbType geometryType() const
Returns the selected flat geometry type for the export.
QgsVectorFileWriter::ActionOnExistingFile creationActionOnExistingFile() const
Returns the creation action.
QgsAttributeList attributesAsDisplayedValues() const
Returns selected attributes that must be exported with their displayed values instead of their raw va...
double scale() const
Returns the specified map scale.
bool hasFilterExtent() const
Determines if filtering the export by an extent is activated.
Qgis::FeatureSymbologyExport symbologyExport() const
Returns type of symbology export.
void setAddToCanvas(bool checked)
Sets whether the "add to canvas" checkbox should be checked.
Represents a vector layer which manages a vector based dataset.
int selectedFeatureCount() const
Returns the number of features that are selected in this layer.
QgsRectangle extent() const final
Returns the extent of the layer.
static Q_INVOKABLE QString translatedDisplayString(Qgis::WkbType type)
Returns a translated display string type for a WKB type, e.g., the geometry name used in WKT geometry...
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:6880
QList< int > QgsAttributeList
Definition qgsfield.h:30
Details of available driver formats.
QMap< QString, QgsVectorFileWriter::Option * > driverOptions
QMap< QString, QgsVectorFileWriter::Option * > layerOptions
QString compulsoryEncoding
Some formats require a compulsory encoding, typically UTF-8. If no compulsory encoding,...