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