QGIS API Documentation 3.99.0-Master (d270888f95f)
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 for ( int i = 0; i < mLayer->fields().size(); ++i )
333 {
334 QgsField fld = mLayer->fields().at( i );
335 if ( fld.type() == QMetaType::Type::LongLong )
336 {
337 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 )
338 {
339 return;
340 }
341 break;
342 }
343 }
344 }
345 }
346 else if ( format() == "FileGDB"_L1 )
347 {
348 // The FileGDB driver based on the ESRI SDK doesn't support 64-bit integers
349 for ( int i = 0; i < mLayer->fields().size(); ++i )
350 {
351 QgsField fld = mLayer->fields().at( i );
352 if ( fld.type() == QMetaType::Type::LongLong )
353 {
354 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 )
355 {
356 return;
357 }
358 break;
359 }
360 }
361 }
362#endif
363
364 if ( QFile::exists( fileName() ) )
365 {
368 QMessageBox msgBox;
369 msgBox.setIcon( QMessageBox::Question );
370 msgBox.setWindowTitle( tr( "Save Vector Layer As" ) );
371 QPushButton *overwriteFileButton = msgBox.addButton( tr( "Overwrite File" ), QMessageBox::ActionRole );
372 QPushButton *overwriteLayerButton = msgBox.addButton( tr( "Overwrite Layer" ), QMessageBox::ActionRole );
373 QPushButton *appendToLayerButton = msgBox.addButton( tr( "Append to Layer" ), QMessageBox::ActionRole );
374 msgBox.setStandardButtons( QMessageBox::Cancel );
375 msgBox.setDefaultButton( QMessageBox::Cancel );
376 overwriteFileButton->hide();
377 overwriteLayerButton->hide();
378 appendToLayerButton->hide();
379 if ( layerExists )
380 {
382 {
383 msgBox.setText( tr( "The layer already exists. Do you want to overwrite the whole file or overwrite the layer?" ) );
384 overwriteFileButton->setVisible( true );
385 overwriteLayerButton->setVisible( true );
386 }
388 {
389 msgBox.setText( tr( "The file already exists. Do you want to overwrite it?" ) );
390 overwriteFileButton->setVisible( true );
391 }
393 {
394 msgBox.setText( tr( "The layer already exists. Do you want to overwrite the whole file, overwrite the layer or append features to the layer?" ) );
395 appendToLayerButton->setVisible( true );
396 overwriteFileButton->setVisible( true );
397 overwriteLayerButton->setVisible( true );
398 }
399 else
400 {
401 msgBox.setText( tr( "The layer already exists. Do you want to overwrite the whole file or append features to the layer?" ) );
402 appendToLayerButton->setVisible( true );
403 overwriteFileButton->setVisible( true );
404 }
405
406 int ret = msgBox.exec();
407 if ( ret == QMessageBox::Cancel )
408 return;
409 if ( msgBox.clickedButton() == overwriteFileButton )
410 mActionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteFile;
411 else if ( msgBox.clickedButton() == overwriteLayerButton )
412 mActionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteLayer;
413 else if ( msgBox.clickedButton() == appendToLayerButton )
414 mActionOnExistingFile = QgsVectorFileWriter::AppendToLayerNoNewFields;
415 }
416 else // !layerExists
417 {
419 {
420 mActionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteLayer;
421 }
422 else
423 {
424 // should not reach here, layer does not exist and cannot add new layer
425 if ( QMessageBox::question( this, tr( "Save Vector Layer As" ), tr( "The file already exists. Do you want to overwrite it?" ) ) != QMessageBox::Yes )
426 {
427 return;
428 }
429 mActionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteFile;
430 }
431 }
432 }
433
434 if ( mActionOnExistingFile == QgsVectorFileWriter::AppendToLayerNoNewFields )
435 {
437 {
438 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 )
439 {
440 mActionOnExistingFile = QgsVectorFileWriter::AppendToLayerAddFields;
441 }
442 }
443 }
444 else if ( mActionOnExistingFile == QgsVectorFileWriter::CreateOrOverwriteFile && QFile::exists( fileName() ) )
445 {
446 const QList<QgsProviderSublayerDetails> sublayers = QgsProviderRegistry::instance()->querySublayers( fileName() );
447 QStringList layerList;
448 layerList.reserve( sublayers.size() );
449 for ( const QgsProviderSublayerDetails &sublayer : sublayers )
450 {
451 layerList.append( sublayer.name() );
452 }
453 if ( layerList.length() > 1 )
454 {
455 layerList.sort( Qt::CaseInsensitive );
456 QMessageBox msgBox;
457 msgBox.setIcon( QMessageBox::Warning );
458 msgBox.setWindowTitle( tr( "Overwrite File" ) );
459 msgBox.setText( tr( "This file contains %1 layers that will be lost!\n" ).arg( QLocale().toString( layerList.length() ) ) );
460 msgBox.setDetailedText( tr( "The following layers will be permanently lost:\n\n%1" ).arg( layerList.join( "\n" ) ) );
461 msgBox.setStandardButtons( QMessageBox::Ok | QMessageBox::Cancel );
462 if ( msgBox.exec() == QMessageBox::Cancel )
463 return;
464 }
465 }
466
467 QgsSettings settings;
468 settings.setValue( u"UI/lastVectorFileFilterDir"_s, QFileInfo( fileName() ).absolutePath() );
469 settings.setValue( u"UI/lastVectorFormat"_s, format() );
470 settings.setValue( u"UI/encoding"_s, encoding() );
471 QDialog::accept();
472}
473
474void QgsVectorLayerSaveAsDialog::mFormatComboBox_currentIndexChanged( int idx )
475{
476 Q_UNUSED( idx )
477
478 mFilename->setEnabled( true );
479 QString filter = QgsVectorFileWriter::filterForDriver( format() );
480 // A bit of hack to solve https://github.com/qgis/QGIS/issues/54566
481 // to be able to select an existing File Geodatabase, we add in the filter
482 // the "gdb" file that is found in all File Geodatabase .gdb directory
483 // to allow the user to select it. We need to detect this particular case
484 // in QgsFileWidget::openFileDialog() to remove this gdb file from the
485 // selected filename
486 if ( format() == "OpenFileGDB"_L1 || format() == "FileGDB"_L1 )
487 filter = u"%1 (*.gdb *.GDB gdb)"_s.arg( tr( "ESRI File Geodatabase" ) );
488 mFilename->setFilter( filter );
489
490 // if output filename already defined we need to replace old suffix
491 // to avoid double extensions like .gpkg.shp
492 if ( !mFilename->filePath().isEmpty() )
493 {
494 const thread_local QRegularExpression rx( "\\.(.*?)[\\s]" );
495 const QString ext = rx.match( filter ).captured( 1 );
496 if ( !ext.isEmpty() )
497 {
498 QFileInfo fi( mFilename->filePath() );
499 mFilename->setFilePath( u"%1/%2.%3"_s.arg( fi.path(), fi.baseName(), ext ) );
500 }
501 }
502
503 bool selectAllFields = true;
504
505 // Is it a format for which fields that have attached widgets of types
506 // ValueMap, ValueRelation, etc. should be by default exported with their displayed
507 // values
508 bool isFormatForFieldsAsDisplayedValues = false;
509
510 const QString sFormat( format() );
511 if ( sFormat == "DXF"_L1 || sFormat == "DGN"_L1 )
512 {
513 mAttributesSelection->setVisible( false );
514 selectAllFields = false;
515 }
516 else
517 {
518 if ( mOptions & Option::Fields )
519 {
520 mAttributesSelection->setVisible( true );
521 isFormatForFieldsAsDisplayedValues = ( sFormat == "CSV"_L1 || sFormat == "XLS"_L1 || sFormat == "XLSX"_L1 || sFormat == "ODS"_L1 );
522 }
523 }
524
525 // Show symbology options only for some formats
526 if ( QgsVectorFileWriter::supportsFeatureStyles( sFormat ) && ( mOptions & Option::Symbology ) )
527 {
528 mSymbologyExportLabel->setVisible( true );
529 mSymbologyExportComboBox->setVisible( true );
530 mScaleLabel->setVisible( true );
531 mScaleWidget->setVisible( true );
532 }
533 else
534 {
535 mSymbologyExportLabel->hide();
536 mSymbologyExportComboBox->hide();
537 mScaleLabel->hide();
538 mScaleWidget->hide();
539 }
540
541 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 );
542
543 if ( sFormat == "XLSX"_L1 )
544 leLayername->setMaxLength( 31 );
545 else if ( leLayername->isEnabled() )
546 leLayername->setMaxLength( 32767 ); // default length
547
548 if ( !leLayername->isEnabled() )
549 leLayername->setText( QString() );
550 else if ( leLayername->text().isEmpty() )
551 {
552 QString layerName = mDefaultOutputLayerNameFromInputLayerName;
553 if ( layerName.isEmpty() && !mFilename->filePath().isEmpty() )
554 {
555 layerName = QFileInfo( mFilename->filePath() ).baseName();
556 leLayername->setDefaultValue( layerName );
557 }
558 if ( layerName.isEmpty() )
559 layerName = tr( "new_layer" );
560 leLayername->setText( layerName );
561 }
562
563 if ( mLayer )
564 {
565 mAttributeTable->setRowCount( mLayer->fields().count() );
566
567 QStringList horizontalHeaders = QStringList() << tr( "Name" ) << tr( "Export name" ) << tr( "Type" ) << tr( "Replace with displayed values" );
568 mAttributeTable->setColumnCount( horizontalHeaders.size() );
569 mAttributeTable->setHorizontalHeaderLabels( horizontalHeaders );
570
571 bool foundFieldThatCanBeExportedAsDisplayedValue = false;
572 for ( int i = 0; i < mLayer->fields().size(); ++i )
573 {
574 const QgsEditorWidgetSetup setup = QgsGui::editorWidgetRegistry()->findBest( mLayer, mLayer->fields()[i].name() );
575 if ( setup.type() != "TextEdit"_L1 && QgsGui::editorWidgetRegistry()->factory( setup.type() ) )
576 {
577 foundFieldThatCanBeExportedAsDisplayedValue = true;
578 break;
579 }
580 }
581 mAttributeTable->setColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ), !foundFieldThatCanBeExportedAsDisplayedValue );
582
583 bool checkReplaceRawFieldValues = selectAllFields && isFormatForFieldsAsDisplayedValues;
584 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
585 {
586 for ( int i = 0; i < mLayer->fields().size(); ++i )
587 {
588 QgsField fld = mLayer->fields().at( i );
589 Qt::ItemFlags flags = mLayer->providerType() != "oracle"_L1 || !fld.typeName().contains( "SDO_GEOMETRY"_L1 ) ? Qt::ItemIsEnabled : Qt::NoItemFlags;
590 QTableWidgetItem *item = nullptr;
591 item = new QTableWidgetItem( fld.name() );
592 item->setFlags( flags | Qt::ItemIsUserCheckable );
593 item->setCheckState( ( selectAllFields ) ? Qt::Checked : Qt::Unchecked );
594 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::Name ), item );
595
596 item = new QTableWidgetItem( fld.name() );
597 item->setFlags( flags | Qt::ItemIsEditable );
598 item->setData( Qt::UserRole, fld.displayName() );
599 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::ExportName ), item );
600
601 item = new QTableWidgetItem( fld.typeName() );
602 item->setFlags( flags );
603 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::Type ), item );
604
605 if ( foundFieldThatCanBeExportedAsDisplayedValue )
606 {
607 const QgsEditorWidgetSetup setup = QgsGui::editorWidgetRegistry()->findBest( mLayer, mLayer->fields()[i].name() );
608 QgsEditorWidgetFactory *factory = nullptr;
609 const QString widgetId( setup.type() );
610 if ( flags == Qt::ItemIsEnabled && widgetId != "TextEdit"_L1 && ( factory = QgsGui::editorWidgetRegistry()->factory( widgetId ) ) )
611 {
612 item = new QTableWidgetItem( tr( "Use %1" ).arg( factory->name() ) );
613 item->setFlags( ( selectAllFields ) ? ( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable ) : Qt::ItemIsUserCheckable );
614 const bool checkItem = ( selectAllFields && isFormatForFieldsAsDisplayedValues && ( widgetId == "ValueMap"_L1 || widgetId == "ValueRelation"_L1 || widgetId == "CheckBox"_L1 || widgetId == "RelationReference"_L1 ) );
615 checkReplaceRawFieldValues &= checkItem;
616 item->setCheckState( checkItem ? Qt::Checked : Qt::Unchecked );
617 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ), item );
618 }
619 else
620 {
621 item = new QTableWidgetItem();
622 item->setFlags( Qt::NoItemFlags );
623 mAttributeTable->setItem( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ), item );
624 }
625 }
626 }
627 }
628
629 whileBlocking( mReplaceRawFieldValues )->setChecked( checkReplaceRawFieldValues );
630 mReplaceRawFieldValues->setEnabled( selectAllFields );
631 mReplaceRawFieldValues->setVisible( foundFieldThatCanBeExportedAsDisplayedValue );
632
633 mAttributeTable->resizeColumnsToContents();
634 }
635
636 QgsVectorFileWriter::MetaData driverMetaData;
637
638 while ( mDatasourceOptionsGroupBox->layout()->count() )
639 {
640 QLayoutItem *item = mDatasourceOptionsGroupBox->layout()->takeAt( 0 );
641 delete item->widget();
642 delete item;
643 }
644
645 while ( mLayerOptionsGroupBox->layout()->count() )
646 {
647 QLayoutItem *item = mLayerOptionsGroupBox->layout()->takeAt( 0 );
648 delete item->widget();
649 delete item;
650 }
651
652 typedef QPair<QLabel *, QWidget *> LabelControlPair;
653
654 if ( QgsVectorFileWriter::driverMetadata( format(), driverMetaData ) )
655 {
656 if ( !driverMetaData.driverOptions.empty() )
657 {
658 mDatasourceOptionsGroupBox->setVisible( true );
659 QList<QPair<QLabel *, QWidget *>> controls = createControls( driverMetaData.driverOptions );
660
661 QFormLayout *datasourceLayout = dynamic_cast<QFormLayout *>( mDatasourceOptionsGroupBox->layout() );
662
663 const auto constControls = controls;
664 for ( LabelControlPair control : constControls )
665 {
666 datasourceLayout->addRow( control.first, control.second );
667 }
668 }
669 else
670 {
671 mDatasourceOptionsGroupBox->setVisible( false );
672 }
673
674 if ( !driverMetaData.layerOptions.empty() )
675 {
676 mLayerOptionsGroupBox->setVisible( true );
677 QList<QPair<QLabel *, QWidget *>> controls = createControls( driverMetaData.layerOptions );
678
679 QFormLayout *layerOptionsLayout = dynamic_cast<QFormLayout *>( mLayerOptionsGroupBox->layout() );
680
681 const auto constControls = controls;
682 for ( LabelControlPair control : constControls )
683 {
684 layerOptionsLayout->addRow( control.first, control.second );
685 }
686 }
687 else
688 {
689 mLayerOptionsGroupBox->setVisible( false );
690 }
691
692 if ( driverMetaData.compulsoryEncoding.isEmpty() )
693 {
694 mEncodingComboBox->setEnabled( true );
695 }
696 else
697 {
698 int idx = mEncodingComboBox->findText( driverMetaData.compulsoryEncoding );
699 if ( idx >= 0 )
700 {
701 mEncodingComboBox->setCurrentIndex( idx );
702 mEncodingComboBox->setDisabled( true );
703 }
704 else
705 {
706 mEncodingComboBox->setEnabled( true );
707 }
708 }
709 }
710 else
711 {
712 mEncodingComboBox->setEnabled( true );
713 }
714
715 GDALDriverH hDriver = GDALGetDriverByName( format().toUtf8().constData() );
716 if ( hDriver )
717 {
718 const bool canReopen = GDALGetMetadataItem( hDriver, GDAL_DCAP_OPEN, nullptr );
719 if ( mAddToCanvas->isEnabled() && !canReopen )
720 {
721 mAddToCanvasStateOnOpenCompatibleDriver = mAddToCanvas->isChecked();
722 mAddToCanvas->setChecked( false );
723 mAddToCanvas->setEnabled( false );
724 }
725 else if ( !mAddToCanvas->isEnabled() && canReopen )
726 {
727 mAddToCanvas->setChecked( mAddToCanvasStateOnOpenCompatibleDriver );
728 mAddToCanvas->setEnabled( true );
729 }
730 }
731}
732
733void QgsVectorLayerSaveAsDialog::mUseAliasesForExportedName_stateChanged( int state )
734{
735 const QSignalBlocker signalBlocker( mAttributeTable );
736
737 switch ( state )
738 {
739 case Qt::Unchecked:
740 {
741 // Check for modified entries
742 bool modifiedEntries = false;
743 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
744 {
745 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->text()
746 != mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->data( Qt::UserRole ).toString() )
747 {
748 modifiedEntries = true;
749 break;
750 }
751 }
752
753 if ( modifiedEntries )
754 {
755 if ( QMessageBox::question( this, tr( "Modified names" ), tr( "Some names were modified and will be overridden. Do you want to continue?" ) )
756 == QMessageBox::No )
757 {
758 whileBlocking( mUseAliasesForExportedName )->setCheckState( Qt::PartiallyChecked );
759 return;
760 }
761 }
762
763 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
764 {
765 mUseAliasesForExportedName->setTristate( false );
766 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->setText( mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->text() );
767 }
768 }
769 break;
770 case Qt::Checked:
771 {
772 // Check for modified entries
773 bool modifiedEntries = false;
774 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
775 {
776 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->text()
777 != mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->text() )
778 modifiedEntries = true;
779 }
780
781 if ( modifiedEntries )
782 {
783 if ( QMessageBox::question( this, tr( "Modified names" ), tr( "Some names were modified and will be overridden. Do you want to continue?" ) )
784 == QMessageBox::No )
785 {
786 whileBlocking( mUseAliasesForExportedName )->setCheckState( Qt::PartiallyChecked );
787 return;
788 }
789 }
790
791 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
792 {
793 mUseAliasesForExportedName->setTristate( false );
794 const QString alias = mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->data( Qt::UserRole ).toString();
795 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->setText( alias );
796 }
797 }
798 break;
799 case Qt::PartiallyChecked:
800 // Do nothing
801 break;
802 }
803}
804
805void QgsVectorLayerSaveAsDialog::mReplaceRawFieldValues_stateChanged( int )
806{
807 if ( mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) )
808 return;
809
810 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
811 const QSignalBlocker signalBlockerReplaceRawFieldValues( mReplaceRawFieldValues );
812
813 if ( mReplaceRawFieldValues->checkState() != Qt::PartiallyChecked )
814 {
815 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
816 {
817 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 )
818 {
819 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setCheckState( mReplaceRawFieldValues->checkState() );
820 }
821 }
822 }
823 mReplaceRawFieldValues->setTristate( false );
824}
825
826void QgsVectorLayerSaveAsDialog::mAttributeTable_itemChanged( QTableWidgetItem *item )
827{
828 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
829 const QSignalBlocker signalBlockerReplaceRawFieldValues( mReplaceRawFieldValues );
830
831 int row = item->row();
832 int column = item->column();
833
834 switch ( static_cast<ColumnIndex>( column ) )
835 {
836 case ColumnIndex::Name:
837 {
838 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 ) )
839 return;
840
841 if ( mAttributeTable->item( row, column )->checkState() == Qt::Unchecked )
842 {
843 mAttributeTable->item( row, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setCheckState( Qt::Unchecked );
844 mAttributeTable->item( row, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setFlags( Qt::ItemIsUserCheckable );
845 bool checkBoxEnabled = false;
846 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
847 {
848 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) && mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsEnabled )
849 {
850 checkBoxEnabled = true;
851 break;
852 }
853 }
854 mReplaceRawFieldValues->setEnabled( checkBoxEnabled );
855 if ( !checkBoxEnabled )
856 mReplaceRawFieldValues->setCheckState( Qt::Unchecked );
857 }
858 else if ( mAttributeTable->item( row, column )->checkState() == Qt::Checked )
859 {
860 mAttributeTable->item( row, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setFlags( Qt::ItemIsUserCheckable | Qt::ItemIsEnabled );
861 mReplaceRawFieldValues->setEnabled( true );
862 }
863 }
864 break;
865 case ColumnIndex::ExportName:
866 {
867 // Check empty export name
868 if ( item->text().isEmpty() )
869 {
870 QMessageBox::warning( this, tr( "Empty export name" ), tr( "Empty export name are not allowed." ) );
871 return;
872 }
873
874 // Rename eventually duplicated names
875 QStringList names = attributesExportNames();
876 while ( names.count( item->text() ) > 1 )
877 item->setText( QString( "%1_2" ).arg( item->text() ) );
878
879 mUseAliasesForExportedName->setCheckState( Qt::PartiallyChecked );
880 }
881 break;
882 case ColumnIndex::Type:
883 // Nothing to do
884 break;
885 case ColumnIndex::ExportAsDisplayedValue:
886 {
887 if ( mAttributeTable->item( row, column )->flags() & Qt::ItemIsUserCheckable )
888 {
889 bool allChecked = true;
890 bool allUnchecked = true;
891 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
892 {
893 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) && mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsEnabled )
894 {
895 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->checkState() == Qt::Unchecked )
896 allChecked = false;
897 else
898 allUnchecked = false;
899 }
900 }
901 mReplaceRawFieldValues->setCheckState( ( !allChecked && !allUnchecked ) ? Qt::PartiallyChecked : ( allChecked ) ? Qt::Checked
902 : Qt::Unchecked );
903 }
904 }
905 break;
906 }
907}
908
909void QgsVectorLayerSaveAsDialog::mCrsSelector_crsChanged( const QgsCoordinateReferenceSystem &crs )
910{
911 mSelectedCrs = crs;
912 mExtentGroupBox->setOutputCrs( mSelectedCrs );
913}
914
916{
917 return mFilename->filePath();
918}
919
921{
922 return leLayername->text();
923}
924
926{
927 return mEncodingComboBox->currentText();
928}
929
931{
932 return mFormatComboBox->currentData().toString();
933}
934
936{
937 return mSelectedCrs;
938}
939
941{
942 QStringList options;
943
944 QgsVectorFileWriter::MetaData driverMetaData;
945
946 if ( QgsVectorFileWriter::driverMetadata( format(), driverMetaData ) )
947 {
948 QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
949
950 for ( it = driverMetaData.driverOptions.constBegin(); it != driverMetaData.driverOptions.constEnd(); ++it )
951 {
952 switch ( it.value()->type )
953 {
955 {
957 QSpinBox *sb = mDatasourceOptionsGroupBox->findChild<QSpinBox *>( it.key() );
958 if ( opt && sb && sb->value() != opt->defaultValue )
959 options << u"%1=%2"_s.arg( it.key() ).arg( sb->value() );
960 break;
961 }
962
964 {
966 QComboBox *cb = mDatasourceOptionsGroupBox->findChild<QComboBox *>( it.key() );
967 if ( opt && cb && cb->itemData( cb->currentIndex() ) != opt->defaultValue )
968 options << u"%1=%2"_s.arg( it.key(), cb->currentText() );
969 break;
970 }
971
973 {
975 QLineEdit *le = mDatasourceOptionsGroupBox->findChild<QLineEdit *>( it.key() );
976 if ( opt && le && le->text() != opt->defaultValue )
977 options << u"%1=%2"_s.arg( it.key(), le->text() );
978 break;
979 }
980
982 {
983 QgsVectorFileWriter::HiddenOption *opt = dynamic_cast<QgsVectorFileWriter::HiddenOption *>( it.value() );
984 if ( opt && !opt->mValue.isEmpty() )
985 options << u"%1=%2"_s.arg( it.key(), opt->mValue );
986 break;
987 }
988 }
989 }
990 }
991
992 QString plainText = mOgrDatasourceOptions->toPlainText().trimmed();
993 if ( !plainText.isEmpty() )
994 options += plainText.split( '\n' );
995
996 return options;
997}
998
1000{
1001 QStringList options;
1002
1003 QgsVectorFileWriter::MetaData driverMetaData;
1004
1005 if ( QgsVectorFileWriter::driverMetadata( format(), driverMetaData ) )
1006 {
1007 QMap<QString, QgsVectorFileWriter::Option *>::ConstIterator it;
1008
1009 for ( it = driverMetaData.layerOptions.constBegin(); it != driverMetaData.layerOptions.constEnd(); ++it )
1010 {
1011 switch ( it.value()->type )
1012 {
1014 {
1015 QgsVectorFileWriter::IntOption *opt = qgis::down_cast<QgsVectorFileWriter::IntOption *>( *it );
1016 QSpinBox *sb = mLayerOptionsGroupBox->findChild<QSpinBox *>( it.key() );
1017 if ( opt && sb && sb->value() != opt->defaultValue )
1018 options << u"%1=%2"_s.arg( it.key() ).arg( sb->value() );
1019 break;
1020 }
1021
1023 {
1024 QgsVectorFileWriter::SetOption *opt = qgis::down_cast<QgsVectorFileWriter::SetOption *>( *it );
1025 QComboBox *cb = mLayerOptionsGroupBox->findChild<QComboBox *>( it.key() );
1026 if ( opt && cb && cb->itemData( cb->currentIndex() ) != opt->defaultValue )
1027 options << u"%1=%2"_s.arg( it.key(), cb->currentText() );
1028 break;
1029 }
1030
1032 {
1033 QgsVectorFileWriter::StringOption *opt = qgis::down_cast<QgsVectorFileWriter::StringOption *>( *it );
1034 QLineEdit *le = mLayerOptionsGroupBox->findChild<QLineEdit *>( it.key() );
1035 if ( opt && le && le->text() != opt->defaultValue )
1036 options << u"%1=%2"_s.arg( it.key(), le->text() );
1037 break;
1038 }
1039
1041 {
1042 QgsVectorFileWriter::HiddenOption *opt = qgis::down_cast<QgsVectorFileWriter::HiddenOption *>( it.value() );
1043 if ( !opt->mValue.isEmpty() )
1044 options << u"%1=%2"_s.arg( it.key(), opt->mValue );
1045 break;
1046 }
1047 }
1048 }
1049 }
1050
1051 QString plainText = mOgrLayerOptions->toPlainText().trimmed();
1052 if ( !plainText.isEmpty() )
1053 options += plainText.split( '\n' );
1054
1055 return options;
1056}
1057
1059{
1060 QgsAttributeList attributes;
1061
1062 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1063 {
1064 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->checkState() == Qt::Checked )
1065 {
1066 attributes.append( i );
1067 }
1068 }
1069
1070 return attributes;
1071}
1072
1074{
1075 QgsAttributeList attributes;
1076
1077 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1078 {
1079 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 )
1080 {
1081 attributes.append( i );
1082 }
1083 }
1084
1085 return attributes;
1086}
1087
1089{
1090 QStringList exportNames;
1091 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1092 exportNames.append( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportName ) )->text() );
1093
1094 return exportNames;
1095}
1096
1098{
1099 return mAddToCanvas->isChecked();
1100}
1101
1103{
1104 mAddToCanvasStateOnOpenCompatibleDriver = enabled;
1105 if ( mAddToCanvas->isEnabled() )
1106 mAddToCanvas->setChecked( enabled );
1107}
1108
1110{
1111 return mSymbologyExportComboBox->currentData().value<Qgis::FeatureSymbologyExport>();
1112}
1113
1115{
1116 return mScaleWidget->scale();
1117}
1118
1120{
1121 mMapCanvas = canvas;
1122 mScaleWidget->setMapCanvas( canvas );
1123 mScaleWidget->setShowCurrentScaleButton( true );
1124 mExtentGroupBox->setCurrentExtent( canvas->mapSettings().visibleExtent(), canvas->mapSettings().destinationCrs() );
1125}
1126
1128{
1129 return mExtentGroupBox->isChecked();
1130}
1131
1133{
1134 return mExtentGroupBox->outputExtent();
1135}
1136
1138{
1139 mSelectedOnly->setChecked( onlySelected );
1140}
1141
1143{
1144 return mSelectedOnly->isChecked();
1145}
1146
1148{
1149 return mCheckPersistMetadata->isChecked();
1150}
1151
1153{
1154 int currentIndexData = mGeometryTypeComboBox->currentData().toInt();
1155 if ( currentIndexData == -1 )
1156 {
1157 //automatic
1159 }
1160
1161 return static_cast<Qgis::WkbType>( currentIndexData );
1162}
1163
1165{
1166 int currentIndexData = mGeometryTypeComboBox->currentData().toInt();
1167 return currentIndexData == -1;
1168}
1169
1171{
1172 return mForceMultiCheckBox->isChecked();
1173}
1174
1176{
1177 mForceMultiCheckBox->setChecked( checked );
1178}
1179
1181{
1182 return mIncludeZCheckBox->isChecked();
1183}
1184
1189
1191{
1192 mIncludeZCheckBox->setChecked( checked );
1193}
1194
1195void QgsVectorLayerSaveAsDialog::mSymbologyExportComboBox_currentIndexChanged( const QString &text )
1196{
1197 bool scaleEnabled = true;
1198 if ( text == tr( "No symbology" ) )
1199 {
1200 scaleEnabled = false;
1201 }
1202 mScaleWidget->setEnabled( scaleEnabled );
1203 mScaleLabel->setEnabled( scaleEnabled );
1204}
1205
1206void QgsVectorLayerSaveAsDialog::mGeometryTypeComboBox_currentIndexChanged( int )
1207{
1208 const int currentIndexData = mGeometryTypeComboBox->currentData().toInt();
1209 if ( currentIndexData != -1 && static_cast<Qgis::WkbType>( currentIndexData ) != Qgis::WkbType::NoGeometry )
1210 {
1211 mForceMultiCheckBox->setEnabled( true );
1212 mIncludeZCheckBox->setEnabled( true );
1213 }
1214 else
1215 {
1216 if ( static_cast<Qgis::WkbType>( currentIndexData ) == Qgis::WkbType::NoGeometry )
1217 {
1218 mForceMultiCheckBox->setEnabled( false );
1219 mForceMultiCheckBox->setChecked( false );
1220 }
1221 else
1222 {
1223 mForceMultiCheckBox->setEnabled( true );
1224 }
1225 mIncludeZCheckBox->setEnabled( false );
1226 mIncludeZCheckBox->setChecked( false );
1227 }
1228}
1229
1230void QgsVectorLayerSaveAsDialog::mSelectAllAttributes_clicked()
1231{
1232 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
1233 const QSignalBlocker signalBlockerReplaceRawFieldValues( mReplaceRawFieldValues );
1234
1235 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1236 {
1237 if ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->flags() & Qt::ItemIsEnabled )
1238 {
1239 if ( !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) && ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsUserCheckable ) )
1240 {
1241 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setFlags( Qt::ItemIsUserCheckable | Qt::ItemIsEnabled );
1242 }
1243 mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->setCheckState( Qt::Checked );
1244 }
1245 }
1246 if ( !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) )
1247 {
1248 mReplaceRawFieldValues->setEnabled( true );
1249 }
1250}
1251
1252void QgsVectorLayerSaveAsDialog::mDeselectAllAttributes_clicked()
1253{
1254 const QSignalBlocker signalBlockerAttributeTable( mAttributeTable );
1255 const QSignalBlocker signalBlockerReplaceRawFieldValues( mReplaceRawFieldValues );
1256
1257 for ( int i = 0; i < mAttributeTable->rowCount(); i++ )
1258 {
1259 mAttributeTable->item( i, static_cast<int>( ColumnIndex::Name ) )->setCheckState( Qt::Unchecked );
1260 if ( !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) && ( mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->flags() & Qt::ItemIsUserCheckable ) )
1261 {
1262 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setFlags( Qt::ItemIsUserCheckable );
1263 mAttributeTable->item( i, static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) )->setCheckState( Qt::Unchecked );
1264 }
1265 }
1266 if ( !mAttributeTable->isColumnHidden( static_cast<int>( ColumnIndex::ExportAsDisplayedValue ) ) )
1267 {
1268 mReplaceRawFieldValues->setCheckState( Qt::Unchecked );
1269 mReplaceRawFieldValues->setEnabled( false );
1270 }
1271}
1272
1273void QgsVectorLayerSaveAsDialog::showHelp()
1274{
1275 QgsHelp::openHelp( u"managing_data_source/create_layers.html#creating-new-layers-from-an-existing-layer"_s );
1276}
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:280
@ Point
Point.
Definition qgis.h:282
@ LineString
LineString.
Definition qgis.h:283
@ Polygon
Polygon.
Definition qgis.h:284
@ NoGeometry
No geometry.
Definition qgis.h:298
@ Unknown
Unknown.
Definition qgis.h:281
@ GeometryCollection
GeometryCollection.
Definition qgis.h:289
FeatureSymbologyExport
Options for exporting features considering their symbology.
Definition qgis.h:5823
@ PerFeature
Keeps the number of features and export symbology per feature.
Definition qgis.h:5825
@ PerSymbolLayer
Exports one feature per symbol layer (considering symbol levels).
Definition qgis.h:5826
@ NoSymbology
Export only data.
Definition qgis.h:5824
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:6804
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,...