QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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(
181 "Select the coordinate reference system for the vector file. "
182 "The data points will be transformed from the layer coordinate reference system."
183 ) );
184
185 mEncodingComboBox->setCurrentIndex( idx );
186 mFormatComboBox_currentIndexChanged( mFormatComboBox->currentIndex() );
187
188 //symbology export combo box
189 mSymbologyExportComboBox->addItem( tr( "No Symbology" ), QVariant::fromValue( Qgis::FeatureSymbologyExport::NoSymbology ) );
190 mSymbologyExportComboBox->addItem( tr( "Feature Symbology" ), QVariant::fromValue( Qgis::FeatureSymbologyExport::PerFeature ) );
191 mSymbologyExportComboBox->addItem( tr( "Symbol Layer Symbology" ), QVariant::fromValue( Qgis::FeatureSymbologyExport::PerSymbolLayer ) );
192 mSymbologyExportComboBox_currentIndexChanged( mSymbologyExportComboBox->currentText() );
193
194 // extent group box
195 mExtentGroupBox->setOutputCrs( mSelectedCrs );
196 mExtentGroupBox->setOriginalExtent( mLayerExtent, mSelectedCrs );
197 mExtentGroupBox->setOutputExtentFromOriginal();
198 mExtentGroupBox->setCheckable( true );
199 mExtentGroupBox->setChecked( false );
200 mExtentGroupBox->setCollapsed( true );
201
202 mFilename->setStorageMode( QgsFileWidget::SaveFile );
203 mFilename->setDialogTitle( tr( "Save Layer As" ) );
204 mFilename->setDefaultRoot( settings.value( u"UI/lastVectorFileFilterDir"_s, QDir::homePath() ).toString() );
205 mFilename->setConfirmOverwrite( false );
206 connect( mFilename, &QgsFileWidget::fileChanged, this, [this]( const QString &filePath ) {
207 QgsSettings settings;
208 QFileInfo tmplFileInfo( filePath );
209 settings.setValue( u"UI/lastVectorFileFilterDir"_s, tmplFileInfo.absolutePath() );
210
211 const QFileInfo fileInfo( filePath );
212 const QString suggestedLayerName = QgsMapLayerUtils::launderLayerName( fileInfo.completeBaseName() );
213 if ( mDefaultOutputLayerNameFromInputLayerName.isEmpty() )
214 leLayername->setDefaultValue( suggestedLayerName );
215
216 // if no layer name set, then automatically match the output layer name to the file name
217 if ( leLayername->text().isEmpty() && !filePath.isEmpty() && leLayername->isEnabled() )
218 {
219 leLayername->setText( suggestedLayerName );
220 }
221 mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( !filePath.isEmpty() );
222 } );
223
224 try
225 {
226 const QgsDatumEnsemble ensemble = mSelectedCrs.datumEnsemble();
227 if ( ensemble.isValid() )
228 {
229 mCrsSelector->setSourceEnsemble( ensemble.name() );
230 }
231 }
232 catch ( QgsNotSupportedException & )
233 {}
234
235 mCrsSelector->setShowAccuracyWarnings( true );
236}
237
238QList<QPair<QLabel *, QWidget *>> QgsVectorLayerSaveAsDialog::createControls( const QMap<QString, QgsVectorFileWriter::Option *> &options )
239{
240 QList<QPair<QLabel *, QWidget *>> controls;
241 QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
242
243 for ( it = options.constBegin(); it != options.constEnd(); ++it )
244 {
245 QgsVectorFileWriter::Option *option = it.value();
246 QWidget *control = nullptr;
247 switch ( option->type )
248 {
250 {
251 QgsVectorFileWriter::IntOption *opt = dynamic_cast<QgsVectorFileWriter::IntOption *>( option );
252 if ( opt )
253 {
254 QSpinBox *sb = new QSpinBox();
255 sb->setObjectName( it.key() );
256 sb->setMaximum( std::numeric_limits<int>::max() ); // the default is 99
257 sb->setValue( opt->defaultValue );
258 control = sb;
259 }
260 break;
261 }
262
264 {
265 QgsVectorFileWriter::SetOption *opt = dynamic_cast<QgsVectorFileWriter::SetOption *>( option );
266 if ( opt )
267 {
268 QComboBox *cb = new QComboBox();
269 cb->setObjectName( it.key() );
270 for ( const QString &val : std::as_const( opt->values ) )
271 {
272 cb->addItem( val, val );
273 }
274 if ( opt->allowNone )
275 cb->addItem( tr( "<Default>" ), QgsVariantUtils::createNullVariant( QMetaType::Type::QString ) );
276 int idx = cb->findText( opt->defaultValue );
277 if ( idx == -1 )
278 idx = cb->findData( QgsVariantUtils::createNullVariant( QMetaType::Type::QString ) );
279 cb->setCurrentIndex( idx );
280 control = cb;
281 }
282 break;
283 }
284
286 {
287 QgsVectorFileWriter::StringOption *opt = dynamic_cast<QgsVectorFileWriter::StringOption *>( option );
288 if ( opt )
289 {
290 QLineEdit *le = new QLineEdit( opt->defaultValue );
291 le->setObjectName( it.key() );
292 control = le;
293 }
294 break;
295 }
296
298 control = nullptr;
299 break;
300 }
301
302 if ( control )
303 {
304 QLabel *label = new QLabel( it.key() );
305
306 // Pack the tooltip in some html element, so it gets linebreaks.
307 label->setToolTip( u"<p>%1</p>"_s.arg( option->docString.toHtmlEscaped() ) );
308 control->setToolTip( u"<p>%1</p>"_s.arg( option->docString.toHtmlEscaped() ) );
309
310 controls << QPair<QLabel *, QWidget *>( label, control );
311 }
312 }
313
314 return controls;
315}
316
318{
319#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 9, 0 )
320 if ( format() == "OpenFileGDB"_L1 )
321 {
322 // The OpenFileGDB driver supports 64-bit integer fields starting with GDAL 3.9,
323 // if selecting the TARGET_ARCGIS_VERSION=ARCGIS_PRO_3_2_OR_LATER option
324 bool targetAll = true;
325 for ( const QString &layerOption : layerOptions() )
326 {
327 if ( layerOption == "TARGET_ARCGIS_VERSION=ARCGIS_PRO_3_2_OR_LATER"_L1 )
328 {
329 targetAll = false;
330 }
331 }
332 if ( targetAll )
333 {
334 const QgsAttributeList attributesSelected = selectedAttributes();
335 for ( int i = 0; i < attributesSelected.size(); ++i )
336 {
337 QgsField fld = mLayer->fields().at( attributesSelected.at( i ) );
338 if ( fld.type() == QMetaType::Type::LongLong )
339 {
340 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?" ) )
341 != QMessageBox::Yes )
342 {
343 return;
344 }
345 break;
346 }
347 }
348 }
349 }
350 else if ( format() == "FileGDB"_L1 )
351 {
352 // The FileGDB driver based on the ESRI SDK doesn't support 64-bit integers
353 const QgsAttributeList attributesSelected = selectedAttributes();
354 for ( int i = 0; i < attributesSelected.size(); ++i )
355 {
356 QgsField fld = mLayer->fields().at( attributesSelected.at( i ) );
357 if ( fld.type() == QMetaType::Type::LongLong )
358 {
359 if ( QMessageBox::question(
360 this,
361 tr( "Save Vector Layer As" ),
362 tr(
363 "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 "
364 "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?"
365 )
366 .arg( tr( "ESRI File Geodatabase" ) )
367 )
368 != QMessageBox::Yes )
369 {
370 return;
371 }
372 break;
373 }
374 }
375 }
376#endif
377
378 if ( QFile::exists( fileName() ) )
379 {
382 QMessageBox msgBox;
383 msgBox.setIcon( QMessageBox::Question );
384 msgBox.setWindowTitle( tr( "Save Vector Layer As" ) );
385 QPushButton *overwriteFileButton = msgBox.addButton( tr( "Overwrite File" ), QMessageBox::ActionRole );
386 QPushButton *overwriteLayerButton = msgBox.addButton( tr( "Overwrite Layer" ), QMessageBox::ActionRole );
387 QPushButton *appendToLayerButton = msgBox.addButton( tr( "Append to Layer" ), QMessageBox::ActionRole );
388 msgBox.setStandardButtons( QMessageBox::Cancel );
389 msgBox.setDefaultButton( QMessageBox::Cancel );
390 overwriteFileButton->hide();
391 overwriteLayerButton->hide();
392 appendToLayerButton->hide();
393 if ( layerExists )
394 {
396 {
397 msgBox.setText( tr( "The layer already exists. Do you want to overwrite the whole file or overwrite the layer?" ) );
398 overwriteFileButton->setVisible( true );
399 overwriteLayerButton->setVisible( true );
400 }
402 {
403 msgBox.setText( tr( "The file already exists. Do you want to overwrite it?" ) );
404 overwriteFileButton->setVisible( true );
405 }
407 {
408 msgBox.setText( tr( "The layer already exists. Do you want to overwrite the whole file, overwrite the layer or append features to the layer?" ) );
409 appendToLayerButton->setVisible( true );
410 overwriteFileButton->setVisible( true );
411 overwriteLayerButton->setVisible( true );
412 }
413 else
414 {
415 msgBox.setText( tr( "The layer already exists. Do you want to overwrite the whole file or append features to the layer?" ) );
416 appendToLayerButton->setVisible( true );
417 overwriteFileButton->setVisible( true );
418 }
419
420 int ret = msgBox.exec();
421 if ( ret == QMessageBox::Cancel )
422 return;
423 if ( msgBox.clickedButton() == overwriteFileButton )
424 mActionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteFile;
425 else if ( msgBox.clickedButton() == overwriteLayerButton )
426 mActionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteLayer;
427 else if ( msgBox.clickedButton() == appendToLayerButton )
428 mActionOnExistingFile = QgsVectorFileWriter::AppendToLayerNoNewFields;
429 }
430 else // !layerExists
431 {
433 {
434 mActionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteLayer;
435 }
436 else
437 {
438 // should not reach here, layer does not exist and cannot add new layer
439 if ( QMessageBox::question( this, tr( "Save Vector Layer As" ), tr( "The file already exists. Do you want to overwrite it?" ) ) != QMessageBox::Yes )
440 {
441 return;
442 }
443 mActionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteFile;
444 }
445 }
446 }
447
448 if ( mActionOnExistingFile == QgsVectorFileWriter::AppendToLayerNoNewFields )
449 {
451 {
452 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 )
453 {
454 mActionOnExistingFile = QgsVectorFileWriter::AppendToLayerAddFields;
455 }
456 }
457 }
458 else if ( mActionOnExistingFile == QgsVectorFileWriter::CreateOrOverwriteFile && QFile::exists( fileName() ) )
459 {
460 const QList<QgsProviderSublayerDetails> sublayers = QgsProviderRegistry::instance()->querySublayers( fileName() );
461 QStringList layerList;
462 layerList.reserve( sublayers.size() );
463 for ( const QgsProviderSublayerDetails &sublayer : sublayers )
464 {
465 layerList.append( sublayer.name() );
466 }
467 if ( layerList.length() > 1 )
468 {
469 layerList.sort( Qt::CaseInsensitive );
470 QMessageBox msgBox;
471 msgBox.setIcon( QMessageBox::Warning );
472 msgBox.setWindowTitle( tr( "Overwrite File" ) );
473 msgBox.setText( tr( "This file contains %1 layers that will be lost!\n" ).arg( QLocale().toString( layerList.length() ) ) );
474 msgBox.setDetailedText( tr( "The following layers will be permanently lost:\n\n%1" ).arg( layerList.join( "\n" ) ) );
475 msgBox.setStandardButtons( QMessageBox::Ok | QMessageBox::Cancel );
476 if ( msgBox.exec() == QMessageBox::Cancel )
477 return;
478 }
479 }
480
481 QgsSettings settings;
482 settings.setValue( u"UI/lastVectorFileFilterDir"_s, QFileInfo( fileName() ).absolutePath() );
483 settings.setValue( u"UI/lastVectorFormat"_s, format() );
484 settings.setValue( u"UI/encoding"_s, encoding() );
485 QDialog::accept();
486}
487
488void QgsVectorLayerSaveAsDialog::mFormatComboBox_currentIndexChanged( int idx )
489{
490 Q_UNUSED( idx )
491
492 mFilename->setEnabled( true );
493 QString filter = QgsVectorFileWriter::filterForDriver( format() );
494 // A bit of hack to solve https://github.com/qgis/QGIS/issues/54566
495 // to be able to select an existing File Geodatabase, we add in the filter
496 // the "gdb" file that is found in all File Geodatabase .gdb directory
497 // to allow the user to select it. We need to detect this particular case
498 // in QgsFileWidget::openFileDialog() to remove this gdb file from the
499 // selected filename
500 if ( format() == "OpenFileGDB"_L1 || format() == "FileGDB"_L1 )
501 filter = u"%1 (*.gdb *.GDB gdb)"_s.arg( tr( "ESRI File Geodatabase" ) );
502 mFilename->setFilter( filter );
503
504 // if output filename already defined we need to replace old suffix
505 // to avoid double extensions like .gpkg.shp
506 if ( !mFilename->filePath().isEmpty() )
507 {
508 const thread_local QRegularExpression rx( "\\.(.*?)[\\s]" );
509 const QString ext = rx.match( filter ).captured( 1 );
510 if ( !ext.isEmpty() )
511 {
512 QFileInfo fi( mFilename->filePath() );
513 mFilename->setFilePath( u"%1/%2.%3"_s.arg( fi.path(), fi.baseName(), ext ) );
514 }
515 }
516
517 bool selectAllFields = true;
518
519 // Is it a format for which fields that have attached widgets of types
520 // ValueMap, ValueRelation, etc. should be by default exported with their displayed
521 // values
522 bool isFormatForFieldsAsDisplayedValues = false;
523
524 const QString sFormat( format() );
525 if ( sFormat == "DXF"_L1 || sFormat == "DGN"_L1 )
526 {
527 mAttributesSelection->setVisible( false );
528 selectAllFields = false;
529 }
530 else
531 {
532 if ( mOptions & Option::Fields )
533 {
534 mAttributesSelection->setVisible( true );
535 isFormatForFieldsAsDisplayedValues = ( sFormat == "CSV"_L1 || sFormat == "XLS"_L1 || sFormat == "XLSX"_L1 || sFormat == "ODS"_L1 );
536 }
537 }
538
539 // Show symbology options only for some formats
540 if ( QgsVectorFileWriter::supportsFeatureStyles( sFormat ) && ( mOptions & Option::Symbology ) )
541 {
542 mSymbologyExportLabel->setVisible( true );
543 mSymbologyExportComboBox->setVisible( true );
544 mScaleLabel->setVisible( true );
545 mScaleWidget->setVisible( true );
546 }
547 else
548 {
549 mSymbologyExportLabel->hide();
550 mSymbologyExportComboBox->hide();
551 mScaleLabel->hide();
552 mScaleWidget->hide();
553 }
554
555 leLayername->setEnabled(
556 sFormat == "KML"_L1 || sFormat == "GPKG"_L1 || sFormat == "XLSX"_L1 || sFormat == "ODS"_L1 || sFormat == "FileGDB"_L1 || sFormat == "OpenFileGDB"_L1 || sFormat == "SQLite"_L1 || sFormat == "SpatiaLite"_L1
557 );
558
559 if ( sFormat == "XLSX"_L1 )
560 leLayername->setMaxLength( 31 );
561 else if ( leLayername->isEnabled() )
562 leLayername->setMaxLength( 32767 ); // default length
563
564 if ( !leLayername->isEnabled() )
565 leLayername->setText( QString() );
566 else if ( leLayername->text().isEmpty() )
567 {
568 QString layerName = mDefaultOutputLayerNameFromInputLayerName;
569 if ( layerName.isEmpty() && !mFilename->filePath().isEmpty() )
570 {
571 layerName = QFileInfo( mFilename->filePath() ).baseName();
572 leLayername->setDefaultValue( layerName );
573 }
574 if ( layerName.isEmpty() )
575 layerName = tr( "new_layer" );
576 leLayername->setText( layerName );
577 }
578
579 if ( mLayer )
580 {
581 // save fields state: if it is checked and should be exported as displayed value
582 const bool isPreviousFormatForFieldsAsDisplayedValues = ( mPreviousFormat == "CSV"_L1 || mPreviousFormat == "XLS"_L1 || mPreviousFormat == "XLSX"_L1 || mPreviousFormat == "ODS"_L1 );
583 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
584 {
585 QTableWidgetItem *nameItem = mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) );
586 if ( !nameItem )
587 {
588 continue;
589 }
590
591 const QString fieldName = nameItem->text();
592 const bool exportField = ( nameItem->checkState() == Qt::Checked );
593
594 std::optional<bool> exportAsValue = std::nullopt;
595 if ( isPreviousFormatForFieldsAsDisplayedValues )
596 {
597 QTableWidgetItem *valueItem = mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) );
598 if ( valueItem && ( valueItem->flags() & Qt::ItemIsUserCheckable ) )
599 {
600 exportAsValue = ( valueItem->checkState() == Qt::Checked );
601 }
602 }
603 else
604 {
605 exportAsValue = mFieldsState[fieldName].second;
606 }
607
608 mFieldsState[fieldName] = { exportField, exportAsValue };
609 }
610
611 mPreviousFormat = sFormat;
612
613 mAttributeTable->setRowCount( mLayer->fields().count() );
614
615 QStringList horizontalHeaders = QStringList() << tr( "Name" ) << tr( "Export name" ) << tr( "Type" ) << tr( "Replace with displayed values" );
616 mAttributeTable->setColumnCount( static_cast<int>( horizontalHeaders.size() ) );
617 mAttributeTable->setHorizontalHeaderLabels( horizontalHeaders );
618
619 bool foundFieldThatCanBeExportedAsDisplayedValue = false;
620 for ( int i = 0; i < mLayer->fields().size(); ++i )
621 {
622 const QgsEditorWidgetSetup setup = QgsGui::editorWidgetRegistry()->findBest( mLayer, mLayer->fields()[i].name() );
623 if ( setup.type() != "TextEdit"_L1 && QgsGui::editorWidgetRegistry()->factory( setup.type() ) )
624 {
625 foundFieldThatCanBeExportedAsDisplayedValue = true;
626 break;
627 }
628 }
629 mAttributeTable->setColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ), !foundFieldThatCanBeExportedAsDisplayedValue );
630
631 bool allChecked = true;
632 bool allUnchecked = true;
633 bool anyEnabled = false;
634
635 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
636 {
637 for ( int i = 0; i < mLayer->fields().size(); ++i )
638 {
639 QgsField fld = mLayer->fields().at( i );
640 Qt::ItemFlags flags = mLayer->providerType() != "oracle"_L1 || !fld.typeName().contains( "SDO_GEOMETRY"_L1 ) ? Qt::ItemIsEnabled : Qt::NoItemFlags;
641 QTableWidgetItem *item = nullptr;
642 const QString fieldName = fld.name();
643 const bool exportField = mFieldsState.contains( fieldName ) ? mFieldsState[fieldName].first : selectAllFields;
644 item = new QTableWidgetItem( fieldName );
645 item->setFlags( flags | Qt::ItemIsUserCheckable );
646 item->setCheckState( ( exportField ) ? Qt::Checked : Qt::Unchecked );
647 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::Name ), item );
648
649 item = new QTableWidgetItem( fieldName );
650 item->setFlags( flags | Qt::ItemIsEditable );
651 item->setData( Qt::UserRole, fld.displayName() );
652 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::ExportName ), item );
653
654 item = new QTableWidgetItem( fld.typeName() );
655 item->setFlags( flags );
656 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::Type ), item );
657
658 if ( foundFieldThatCanBeExportedAsDisplayedValue )
659 {
660 const QgsEditorWidgetSetup setup = QgsGui::editorWidgetRegistry()->findBest( mLayer, mLayer->fields()[i].name() );
661 QgsEditorWidgetFactory *factory = nullptr;
662 const QString widgetId( setup.type() );
663 if ( flags == Qt::ItemIsEnabled && widgetId != "TextEdit"_L1 && ( factory = QgsGui::editorWidgetRegistry()->factory( widgetId ) ) )
664 {
665 item = new QTableWidgetItem( tr( "Use %1" ).arg( factory->name() ) );
666 bool exportAsValue;
667 if ( mFieldsState.contains( fieldName ) && mFieldsState[fieldName].second.has_value() )
668 {
669 exportAsValue = mFieldsState[fieldName].second.value();
670 }
671 else
672 {
673 exportAsValue
674 = ( exportField && isFormatForFieldsAsDisplayedValues && ( widgetId == "ValueMap"_L1 || widgetId == "ValueRelation"_L1 || widgetId == "CheckBox"_L1 || widgetId == "RelationReference"_L1 ) );
675 }
676 item->setFlags( ( exportField ) ? ( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable ) : Qt::ItemIsUserCheckable );
677 item->setCheckState( exportAsValue ? Qt::Checked : Qt::Unchecked );
678 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ), item );
679
680 // collect information for setting mReplaceRawFieldValues state
681 if ( exportField )
682 {
683 anyEnabled = true;
684 if ( exportAsValue )
685 allUnchecked = false;
686 else
687 allChecked = false;
688 }
689 }
690 else
691 {
692 item = new QTableWidgetItem();
693 item->setFlags( Qt::NoItemFlags );
694 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ), item );
695 }
696 }
697 }
698 }
699
700 Qt::CheckState replaceRawState;
701 if ( !anyEnabled || allUnchecked )
702 replaceRawState = Qt::Unchecked;
703 else if ( allChecked )
704 replaceRawState = Qt::Checked;
705 else
706 replaceRawState = Qt::PartiallyChecked;
707
708 whileBlocking( mReplaceRawFieldValues )->setCheckState( replaceRawState );
709 mReplaceRawFieldValues->setEnabled( selectAllFields && anyEnabled );
710 mReplaceRawFieldValues->setVisible( foundFieldThatCanBeExportedAsDisplayedValue );
711
712 mAttributeTable->resizeColumnsToContents();
713 }
714
715 QgsVectorFileWriter::MetaData driverMetaData;
716
717 while ( mDatasourceOptionsGroupBox->layout()->count() )
718 {
719 QLayoutItem *item = mDatasourceOptionsGroupBox->layout()->takeAt( 0 );
720 delete item->widget();
721 delete item;
722 }
723
724 while ( mLayerOptionsGroupBox->layout()->count() )
725 {
726 QLayoutItem *item = mLayerOptionsGroupBox->layout()->takeAt( 0 );
727 delete item->widget();
728 delete item;
729 }
730
731 typedef QPair<QLabel *, QWidget *> LabelControlPair;
732
733 if ( QgsVectorFileWriter::driverMetadata( format(), driverMetaData ) )
734 {
735 if ( !driverMetaData.driverOptions.empty() )
736 {
737 mDatasourceOptionsGroupBox->setVisible( true );
738 QList<QPair<QLabel *, QWidget *>> controls = createControls( driverMetaData.driverOptions );
739
740 QFormLayout *datasourceLayout = dynamic_cast<QFormLayout *>( mDatasourceOptionsGroupBox->layout() );
741
742 const auto constControls = controls;
743 for ( LabelControlPair control : constControls )
744 {
745 datasourceLayout->addRow( control.first, control.second );
746 }
747 }
748 else
749 {
750 mDatasourceOptionsGroupBox->setVisible( false );
751 }
752
753 if ( !driverMetaData.layerOptions.empty() )
754 {
755 mLayerOptionsGroupBox->setVisible( true );
756 QList<QPair<QLabel *, QWidget *>> controls = createControls( driverMetaData.layerOptions );
757
758 QFormLayout *layerOptionsLayout = dynamic_cast<QFormLayout *>( mLayerOptionsGroupBox->layout() );
759
760 const auto constControls = controls;
761 for ( LabelControlPair control : constControls )
762 {
763 layerOptionsLayout->addRow( control.first, control.second );
764 }
765 }
766 else
767 {
768 mLayerOptionsGroupBox->setVisible( false );
769 }
770
771 if ( driverMetaData.compulsoryEncoding.isEmpty() )
772 {
773 mEncodingComboBox->setEnabled( true );
774 }
775 else
776 {
777 int idx = mEncodingComboBox->findText( driverMetaData.compulsoryEncoding );
778 if ( idx >= 0 )
779 {
780 mEncodingComboBox->setCurrentIndex( idx );
781 mEncodingComboBox->setDisabled( true );
782 }
783 else
784 {
785 mEncodingComboBox->setEnabled( true );
786 }
787 }
788 }
789 else
790 {
791 mEncodingComboBox->setEnabled( true );
792 }
793
794 GDALDriverH hDriver = GDALGetDriverByName( format().toUtf8().constData() );
795 if ( hDriver )
796 {
797 const bool canReopen = GDALGetMetadataItem( hDriver, GDAL_DCAP_OPEN, nullptr );
798 if ( mAddToCanvas->isEnabled() && !canReopen )
799 {
800 mAddToCanvasStateOnOpenCompatibleDriver = mAddToCanvas->isChecked();
801 mAddToCanvas->setChecked( false );
802 mAddToCanvas->setEnabled( false );
803 }
804 else if ( !mAddToCanvas->isEnabled() && canReopen )
805 {
806 mAddToCanvas->setChecked( mAddToCanvasStateOnOpenCompatibleDriver );
807 mAddToCanvas->setEnabled( true );
808 }
809 }
810}
811
812void QgsVectorLayerSaveAsDialog::mUseAliasesForExportedName_stateChanged( int state )
813{
814 const QSignalBlocker signalBlocker( mAttributeTable );
815
816 switch ( state )
817 {
818 case Qt::Unchecked:
819 {
820 // Check for modified entries
821 bool modifiedEntries = false;
822 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
823 {
824 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->text() != mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->data( Qt::UserRole ).toString() )
825 {
826 modifiedEntries = true;
827 break;
828 }
829 }
830
831 if ( modifiedEntries )
832 {
833 if ( QMessageBox::question( this, tr( "Modified names" ), tr( "Some names were modified and will be overridden. Do you want to continue?" ) ) == QMessageBox::No )
834 {
835 whileBlocking( mUseAliasesForExportedName )->setCheckState( Qt::PartiallyChecked );
836 return;
837 }
838 }
839
840 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
841 {
842 mUseAliasesForExportedName->setTristate( false );
843 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->setText( mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->text() );
844 }
845 }
846 break;
847 case Qt::Checked:
848 {
849 // Check for modified entries
850 bool modifiedEntries = false;
851 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
852 {
853 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->text() != mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->text() )
854 modifiedEntries = true;
855 }
856
857 if ( modifiedEntries )
858 {
859 if ( QMessageBox::question( this, tr( "Modified names" ), tr( "Some names were modified and will be overridden. Do you want to continue?" ) ) == QMessageBox::No )
860 {
861 whileBlocking( mUseAliasesForExportedName )->setCheckState( Qt::PartiallyChecked );
862 return;
863 }
864 }
865
866 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
867 {
868 mUseAliasesForExportedName->setTristate( false );
869 const QString alias = mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->data( Qt::UserRole ).toString();
870 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->setText( alias );
871 }
872 }
873 break;
874 case Qt::PartiallyChecked:
875 // Do nothing
876 break;
877 }
878}
879
880void QgsVectorLayerSaveAsDialog::mReplaceRawFieldValues_stateChanged( int )
881{
882 if ( mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) )
883 return;
884
885 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
886 const QSignalBlocker signalBlockerReplaceRawFieldValues( mReplaceRawFieldValues );
887
888 if ( mReplaceRawFieldValues->checkState() != Qt::PartiallyChecked )
889 {
890 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
891 {
892 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->checkState() == Qt::Checked
893 && mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )
894 && mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsEnabled )
895 {
896 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setCheckState( mReplaceRawFieldValues->checkState() );
897 }
898 }
899 }
900 mReplaceRawFieldValues->setTristate( false );
901}
902
903void QgsVectorLayerSaveAsDialog::mAttributeTable_itemChanged( QTableWidgetItem *item )
904{
905 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
906 const QSignalBlocker signalBlockerReplaceRawFieldValues( mReplaceRawFieldValues );
907
908 int row = item->row();
909 int column = item->column();
910
911 switch ( static_cast<ColumnIndex>( column ) )
912 {
913 case ColumnIndex::Name:
914 {
915 if ( mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )
916 || !mAttributeTable->item( row, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )
917 || !( mAttributeTable->item( row, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsUserCheckable ) )
918 return;
919
920 if ( mAttributeTable->item( row, column )->checkState() == Qt::Unchecked )
921 {
922 mAttributeTable->item( row, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setCheckState( Qt::Unchecked );
923 mAttributeTable->item( row, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setFlags( Qt::ItemIsUserCheckable );
924 bool checkBoxEnabled = false;
925 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
926 {
927 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )
928 && mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsEnabled )
929 {
930 checkBoxEnabled = true;
931 break;
932 }
933 }
934 mReplaceRawFieldValues->setEnabled( checkBoxEnabled );
935 if ( !checkBoxEnabled )
936 mReplaceRawFieldValues->setCheckState( Qt::Unchecked );
937 }
938 else if ( mAttributeTable->item( row, column )->checkState() == Qt::Checked )
939 {
940 mAttributeTable->item( row, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setFlags( Qt::ItemIsUserCheckable | Qt::ItemIsEnabled );
941 mReplaceRawFieldValues->setEnabled( true );
942 }
943 }
944 break;
945 case ColumnIndex::ExportName:
946 {
947 // Check empty export name
948 if ( item->text().isEmpty() )
949 {
950 QMessageBox::warning( this, tr( "Empty export name" ), tr( "Empty export name are not allowed." ) );
951 return;
952 }
953
954 // Rename eventually duplicated names
955 QStringList names = attributesExportNames();
956 while ( names.count( item->text() ) > 1 )
957 item->setText( QString( "%1_2" ).arg( item->text() ) );
958
959 mUseAliasesForExportedName->setCheckState( Qt::PartiallyChecked );
960 }
961 break;
962 case ColumnIndex::Type:
963 // Nothing to do
964 break;
965 case ColumnIndex::ExportAsDisplayedValue:
966 {
967 if ( mAttributeTable->item( row, column )->flags() & Qt::ItemIsUserCheckable )
968 {
969 bool allChecked = true;
970 bool allUnchecked = true;
971 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
972 {
973 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )
974 && mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsEnabled )
975 {
976 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->checkState() == Qt::Unchecked )
977 allChecked = false;
978 else
979 allUnchecked = false;
980 }
981 }
982 mReplaceRawFieldValues->setCheckState( ( !allChecked && !allUnchecked ) ? Qt::PartiallyChecked : ( allChecked ) ? Qt::Checked : Qt::Unchecked );
983 }
984 }
985 break;
986 }
987}
988
989void QgsVectorLayerSaveAsDialog::mCrsSelector_crsChanged( const QgsCoordinateReferenceSystem &crs )
990{
991 mSelectedCrs = crs;
992 mExtentGroupBox->setOutputCrs( mSelectedCrs );
993}
994
996{
997 return mFilename->filePath();
998}
999
1001{
1002 return leLayername->text();
1003}
1004
1006{
1007 return mEncodingComboBox->currentText();
1008}
1009
1011{
1012 return mFormatComboBox->currentData().toString();
1013}
1014
1016{
1017 return mSelectedCrs;
1018}
1019
1021{
1022 QStringList options;
1023
1024 QgsVectorFileWriter::MetaData driverMetaData;
1025
1026 if ( QgsVectorFileWriter::driverMetadata( format(), driverMetaData ) )
1027 {
1028 QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
1029
1030 for ( it = driverMetaData.driverOptions.constBegin(); it != driverMetaData.driverOptions.constEnd(); ++it )
1031 {
1032 switch ( it.value()->type )
1033 {
1035 {
1037 QSpinBox *sb = mDatasourceOptionsGroupBox->findChild<QSpinBox *>( it.key() );
1038 if ( opt && sb && sb->value() != opt->defaultValue )
1039 options << u"%1=%2"_s.arg( it.key() ).arg( sb->value() );
1040 break;
1041 }
1042
1044 {
1046 QComboBox *cb = mDatasourceOptionsGroupBox->findChild<QComboBox *>( it.key() );
1047 if ( opt && cb && cb->itemData( cb->currentIndex() ) != opt->defaultValue )
1048 options << u"%1=%2"_s.arg( it.key(), cb->currentText() );
1049 break;
1050 }
1051
1053 {
1055 QLineEdit *le = mDatasourceOptionsGroupBox->findChild<QLineEdit *>( it.key() );
1056 if ( opt && le && le->text() != opt->defaultValue )
1057 options << u"%1=%2"_s.arg( it.key(), le->text() );
1058 break;
1059 }
1060
1062 {
1063 QgsVectorFileWriter::HiddenOption *opt = dynamic_cast<QgsVectorFileWriter::HiddenOption *>( it.value() );
1064 if ( opt && !opt->mValue.isEmpty() )
1065 options << u"%1=%2"_s.arg( it.key(), opt->mValue );
1066 break;
1067 }
1068 }
1069 }
1070 }
1071
1072 QString plainText = mOgrDatasourceOptions->toPlainText().trimmed();
1073 if ( !plainText.isEmpty() )
1074 options += plainText.split( '\n' );
1075
1076 return options;
1077}
1078
1080{
1081 QStringList options;
1082
1083 QgsVectorFileWriter::MetaData driverMetaData;
1084
1085 if ( QgsVectorFileWriter::driverMetadata( format(), driverMetaData ) )
1086 {
1087 QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
1088
1089 for ( it = driverMetaData.layerOptions.constBegin(); it != driverMetaData.layerOptions.constEnd(); ++it )
1090 {
1091 switch ( it.value()->type )
1092 {
1094 {
1095 QgsVectorFileWriter::IntOption *opt = qgis::down_cast<QgsVectorFileWriter::IntOption *>( *it );
1096 QSpinBox *sb = mLayerOptionsGroupBox->findChild<QSpinBox *>( it.key() );
1097 if ( opt && sb && sb->value() != opt->defaultValue )
1098 options << u"%1=%2"_s.arg( it.key() ).arg( sb->value() );
1099 break;
1100 }
1101
1103 {
1104 QgsVectorFileWriter::SetOption *opt = qgis::down_cast<QgsVectorFileWriter::SetOption *>( *it );
1105 QComboBox *cb = mLayerOptionsGroupBox->findChild<QComboBox *>( it.key() );
1106 if ( opt && cb && cb->itemData( cb->currentIndex() ) != opt->defaultValue )
1107 options << u"%1=%2"_s.arg( it.key(), cb->currentText() );
1108 break;
1109 }
1110
1112 {
1113 QgsVectorFileWriter::StringOption *opt = qgis::down_cast<QgsVectorFileWriter::StringOption *>( *it );
1114 QLineEdit *le = mLayerOptionsGroupBox->findChild<QLineEdit *>( it.key() );
1115 if ( opt && le && le->text() != opt->defaultValue )
1116 options << u"%1=%2"_s.arg( it.key(), le->text() );
1117 break;
1118 }
1119
1121 {
1122 QgsVectorFileWriter::HiddenOption *opt = qgis::down_cast<QgsVectorFileWriter::HiddenOption *>( it.value() );
1123 if ( !opt->mValue.isEmpty() )
1124 options << u"%1=%2"_s.arg( it.key(), opt->mValue );
1125 break;
1126 }
1127 }
1128 }
1129 }
1130
1131 QString plainText = mOgrLayerOptions->toPlainText().trimmed();
1132 if ( !plainText.isEmpty() )
1133 options += plainText.split( '\n' );
1134
1135 return options;
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 )
1145 {
1146 attributes.append( i );
1147 }
1148 }
1149
1150 return attributes;
1151}
1152
1154{
1155 QgsAttributeList attributes;
1156
1157 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1158 {
1159 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->checkState() == Qt::Checked
1160 && !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )
1161 && mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->checkState() == Qt::Checked )
1162 {
1163 attributes.append( i );
1164 }
1165 }
1166
1167 return attributes;
1168}
1169
1171{
1172 QStringList exportNames;
1173 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1174 exportNames.append( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->text() );
1175
1176 return exportNames;
1177}
1178
1180{
1181 return mAddToCanvas->isChecked();
1182}
1183
1185{
1186 mAddToCanvasStateOnOpenCompatibleDriver = enabled;
1187 if ( mAddToCanvas->isEnabled() )
1188 mAddToCanvas->setChecked( enabled );
1189}
1190
1192{
1193 return mSymbologyExportComboBox->currentData().value<Qgis::FeatureSymbologyExport>();
1194}
1195
1197{
1198 return mScaleWidget->scale();
1199}
1200
1202{
1203 mMapCanvas = canvas;
1204 mScaleWidget->setMapCanvas( canvas );
1205 mScaleWidget->setShowCurrentScaleButton( true );
1206 mExtentGroupBox->setCurrentExtent( canvas->mapSettings().visibleExtent(), canvas->mapSettings().destinationCrs() );
1207}
1208
1210{
1211 return mExtentGroupBox->isChecked();
1212}
1213
1215{
1216 return mExtentGroupBox->outputExtent();
1217}
1218
1220{
1221 mSelectedOnly->setChecked( onlySelected );
1222}
1223
1225{
1226 return mSelectedOnly->isChecked();
1227}
1228
1230{
1231 return mCheckPersistMetadata->isChecked();
1232}
1233
1235{
1236 int currentIndexData = mGeometryTypeComboBox->currentData().toInt();
1237 if ( currentIndexData == -1 )
1238 {
1239 //automatic
1241 }
1242
1243 return static_cast<Qgis::WkbType>( currentIndexData );
1244}
1245
1247{
1248 int currentIndexData = mGeometryTypeComboBox->currentData().toInt();
1249 return currentIndexData == -1;
1250}
1251
1253{
1254 return mForceMultiCheckBox->isChecked();
1255}
1256
1258{
1259 mForceMultiCheckBox->setChecked( checked );
1260}
1261
1263{
1264 return mIncludeZCheckBox->isChecked();
1265}
1266
1271
1273{
1274 mIncludeZCheckBox->setChecked( checked );
1275}
1276
1277void QgsVectorLayerSaveAsDialog::mSymbologyExportComboBox_currentIndexChanged( const QString &text )
1278{
1279 bool scaleEnabled = true;
1280 if ( text == tr( "No symbology" ) )
1281 {
1282 scaleEnabled = false;
1283 }
1284 mScaleWidget->setEnabled( scaleEnabled );
1285 mScaleLabel->setEnabled( scaleEnabled );
1286}
1287
1288void QgsVectorLayerSaveAsDialog::mGeometryTypeComboBox_currentIndexChanged( int )
1289{
1290 const int currentIndexData = mGeometryTypeComboBox->currentData().toInt();
1291 if ( currentIndexData != -1 && static_cast<Qgis::WkbType>( currentIndexData ) != Qgis::WkbType::NoGeometry )
1292 {
1293 mForceMultiCheckBox->setEnabled( true );
1294 mIncludeZCheckBox->setEnabled( true );
1295 }
1296 else
1297 {
1298 if ( static_cast<Qgis::WkbType>( currentIndexData ) == Qgis::WkbType::NoGeometry )
1299 {
1300 mForceMultiCheckBox->setEnabled( false );
1301 mForceMultiCheckBox->setChecked( false );
1302 }
1303 else
1304 {
1305 mForceMultiCheckBox->setEnabled( true );
1306 }
1307 mIncludeZCheckBox->setEnabled( false );
1308 mIncludeZCheckBox->setChecked( false );
1309 }
1310}
1311
1312void QgsVectorLayerSaveAsDialog::mSelectAllAttributes_clicked()
1313{
1314 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
1315 const QSignalBlocker signalBlockerReplaceRawFieldValues( mReplaceRawFieldValues );
1316
1317 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1318 {
1319 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->flags() & Qt::ItemIsEnabled )
1320 {
1321 if ( !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )
1322 && ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsUserCheckable ) )
1323 {
1324 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setFlags( Qt::ItemIsUserCheckable | Qt::ItemIsEnabled );
1325 }
1326 mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->setCheckState( Qt::Checked );
1327 }
1328 }
1329 if ( !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) )
1330 {
1331 mReplaceRawFieldValues->setEnabled( true );
1332 }
1333}
1334
1335void QgsVectorLayerSaveAsDialog::mDeselectAllAttributes_clicked()
1336{
1337 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
1338 const QSignalBlocker signalBlockerReplaceRawFieldValues( mReplaceRawFieldValues );
1339
1340 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1341 {
1342 mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->setCheckState( Qt::Unchecked );
1343 if ( !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )
1344 && ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsUserCheckable ) )
1345 {
1346 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setFlags( Qt::ItemIsUserCheckable );
1347 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setCheckState( Qt::Unchecked );
1348 }
1349 }
1350 if ( !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) )
1351 {
1352 mReplaceRawFieldValues->setCheckState( Qt::Unchecked );
1353 mReplaceRawFieldValues->setEnabled( false );
1354 }
1355}
1356
1357void QgsVectorLayerSaveAsDialog::showHelp()
1358{
1359 QgsHelp::openHelp( u"managing_data_source/create_layers.html#creating-new-layers-from-an-existing-layer"_s );
1360}
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,...