QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgsnewgeopackagelayerdialog.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsnewgeopackagelayerdialog.cpp
3
4 -------------------
5 begin : April 2016
6 copyright : (C) 2016 by Even Rouault
7 email : even.rouault at spatialys.com
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 ***************************************************************************/
18
19
21
22#include <cpl_error.h>
23#include <cpl_string.h>
24#include <gdal_version.h>
25#include <ogr_api.h>
26#include <ogr_srs_api.h>
27
28#include "qgis.h"
29#include "qgsapplication.h"
31#include "qgsgui.h"
32#include "qgshelp.h"
33#include "qgsiconutils.h"
34#include "qgsogrutils.h"
35#include "qgsproject.h"
37#include "qgssettings.h"
38#include "qgsvariantutils.h"
39#include "qgsvectorlayer.h"
40
41#include <QCompleter>
42#include <QFileDialog>
43#include <QLineEdit>
44#include <QMessageBox>
45#include <QPushButton>
46
47#include "moc_qgsnewgeopackagelayerdialog.cpp"
48
49#define DEFAULT_OGR_FID_COLUMN_TITLE "fid" // default value from OGR
50
52 : QDialog( parent, fl )
53{
54 setupUi( this );
55 setObjectName( QStringLiteral( "QgsNewGeoPackageLayerDialog" ) );
57
58 connect( mAddAttributeButton, &QToolButton::clicked, this, &QgsNewGeoPackageLayerDialog::mAddAttributeButton_clicked );
59 connect( mRemoveAttributeButton, &QToolButton::clicked, this, &QgsNewGeoPackageLayerDialog::mRemoveAttributeButton_clicked );
60 connect( mFieldTypeBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsNewGeoPackageLayerDialog::mFieldTypeBox_currentIndexChanged );
61 connect( mGeometryTypeBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsNewGeoPackageLayerDialog::mGeometryTypeBox_currentIndexChanged );
62 connect( mTableNameEdit, &QLineEdit::textChanged, this, &QgsNewGeoPackageLayerDialog::mTableNameEdit_textChanged );
63 connect( mTableNameEdit, &QLineEdit::textEdited, this, &QgsNewGeoPackageLayerDialog::mTableNameEdit_textEdited );
64 connect( mLayerIdentifierEdit, &QLineEdit::textEdited, this, &QgsNewGeoPackageLayerDialog::mLayerIdentifierEdit_textEdited );
65 connect( buttonBox, &QDialogButtonBox::accepted, this, &QgsNewGeoPackageLayerDialog::buttonBox_accepted );
66 connect( buttonBox, &QDialogButtonBox::rejected, this, &QgsNewGeoPackageLayerDialog::buttonBox_rejected );
67 connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsNewGeoPackageLayerDialog::showHelp );
68 connect( mButtonUp, &QToolButton::clicked, this, &QgsNewGeoPackageLayerDialog::moveFieldsUp );
69 connect( mButtonDown, &QToolButton::clicked, this, &QgsNewGeoPackageLayerDialog::moveFieldsDown );
70
71 mAddAttributeButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionNewAttribute.svg" ) ) );
72 mRemoveAttributeButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteAttribute.svg" ) ) );
73
74 const auto addGeomItem = [this]( OGRwkbGeometryType ogrGeomType ) {
75 const Qgis::WkbType qgsType = QgsOgrUtils::ogrGeometryTypeToQgsWkbType( ogrGeomType );
76 mGeometryTypeBox->addItem( QgsIconUtils::iconForWkbType( qgsType ), QgsWkbTypes::translatedDisplayString( qgsType ), ogrGeomType );
77 };
78
79 addGeomItem( wkbNone );
80 addGeomItem( wkbPoint );
81 addGeomItem( wkbLineString );
82 addGeomItem( wkbPolygon );
83 addGeomItem( wkbMultiPoint );
84 addGeomItem( wkbMultiLineString );
85 addGeomItem( wkbMultiPolygon );
86
87#if 0
88 // QGIS always create CompoundCurve and there's no real interest of having just CircularString. CompoundCurve are more useful
89 addGeomItem( wkbCircularString );
90#endif
91 addGeomItem( wkbCompoundCurve );
92 addGeomItem( wkbCurvePolygon );
93 addGeomItem( wkbMultiCurve );
94 addGeomItem( wkbMultiSurface );
95 mGeometryTypeBox->setCurrentIndex( -1 );
96
97 mGeometryWithZCheckBox->setEnabled( false );
98 mGeometryWithMCheckBox->setEnabled( false );
99 mGeometryColumnEdit->setEnabled( false );
100 mGeometryColumnEdit->setText( QStringLiteral( "geometry" ) );
101 mFeatureIdColumnEdit->setPlaceholderText( QStringLiteral( DEFAULT_OGR_FID_COLUMN_TITLE ) );
102 mCheckBoxCreateSpatialIndex->setEnabled( false );
103 mCrsSelector->setEnabled( false );
104 mCrsSelector->setShowAccuracyWarnings( true );
105
106 mFieldTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QString ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QString ), "text" );
107 mFieldTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::Int ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::Int ), "integer" );
108 mFieldTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::LongLong ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::LongLong ), "integer64" );
109 mFieldTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::Double ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::Double ), "real" );
110 mFieldTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QDate ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QDate ), "date" );
111 mFieldTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QDateTime ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QDateTime ), "datetime" );
112 mFieldTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::Bool ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::Bool ), "bool" );
113 mFieldTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QByteArray ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QByteArray ), "binary" );
114 mFieldTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QVariantMap ), tr( "JSON" ), "json" );
115
116 mOkButton = buttonBox->button( QDialogButtonBox::Ok );
117 mOkButton->setEnabled( false );
118
119 connect( mFieldNameEdit, &QLineEdit::textChanged, this, &QgsNewGeoPackageLayerDialog::fieldNameChanged );
120 connect( mAttributeView, &QTreeWidget::itemSelectionChanged, this, &QgsNewGeoPackageLayerDialog::selectionChanged );
121 connect( mTableNameEdit, &QLineEdit::textChanged, this, &QgsNewGeoPackageLayerDialog::checkOk );
122 connect( mGeometryTypeBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsNewGeoPackageLayerDialog::checkOk );
123
124 mAddAttributeButton->setEnabled( false );
125 mRemoveAttributeButton->setEnabled( false );
126 mButtonUp->setEnabled( false );
127 mButtonDown->setEnabled( false );
128
129 mCheckBoxCreateSpatialIndex->setChecked( true );
130
131 const QgsSettings settings;
132 mFileName->setStorageMode( QgsFileWidget::SaveFile );
133 mFileName->setFilter( tr( "GeoPackage" ) + " (*.gpkg)" );
134 mFileName->setDialogTitle( tr( "Select Existing or Create a New GeoPackage Database File…" ) );
135 mFileName->setDefaultRoot( settings.value( QStringLiteral( "UI/lastVectorFileFilterDir" ), QDir::homePath() ).toString() );
136 mFileName->setConfirmOverwrite( false );
137 connect( mFileName, &QgsFileWidget::fileChanged, this, [this]( const QString &filePath ) {
138 QgsSettings settings;
139 const QFileInfo tmplFileInfo( filePath );
140 settings.setValue( QStringLiteral( "UI/lastVectorFileFilterDir" ), tmplFileInfo.absolutePath() );
141 if ( !filePath.isEmpty() && !mTableNameEdited )
142 {
143 const QFileInfo fileInfo( filePath );
144 mTableNameEdit->setText( fileInfo.baseName() );
145 }
146 checkOk();
147 } );
148
149 QgsProviderConnectionModel *ogrProviderModel = new QgsProviderConnectionModel( QStringLiteral( "ogr" ), this );
150
151 QCompleter *completer = new QCompleter( this );
152 completer->setModel( ogrProviderModel );
153 completer->setCompletionRole( static_cast<int>( QgsProviderConnectionModel::CustomRole::Uri ) );
154 completer->setCompletionMode( QCompleter::PopupCompletion );
155 completer->setFilterMode( Qt::MatchContains );
156 mFileName->lineEdit()->setCompleter( completer );
157}
158
160{
161 mCrsSelector->setCrs( crs );
162}
163
165{
166 mFileName->setReadOnly( true );
167}
168
169void QgsNewGeoPackageLayerDialog::mFieldTypeBox_currentIndexChanged( int )
170{
171 const QString myType = mFieldTypeBox->currentData( Qt::UserRole ).toString();
172 mFieldLengthEdit->setEnabled( myType == QLatin1String( "text" ) );
173 if ( myType != QLatin1String( "text" ) )
174 mFieldLengthEdit->clear();
175}
176
177
178void QgsNewGeoPackageLayerDialog::mGeometryTypeBox_currentIndexChanged( int )
179{
180 const OGRwkbGeometryType geomType = static_cast<OGRwkbGeometryType>( mGeometryTypeBox->currentData( Qt::UserRole ).toInt() );
181 const bool isSpatial = geomType != wkbNone;
182 mGeometryWithZCheckBox->setEnabled( isSpatial );
183 mGeometryWithMCheckBox->setEnabled( isSpatial );
184 mGeometryColumnEdit->setEnabled( isSpatial );
185 mCheckBoxCreateSpatialIndex->setEnabled( isSpatial );
186 mCrsSelector->setEnabled( isSpatial );
187}
188
189void QgsNewGeoPackageLayerDialog::mTableNameEdit_textChanged( const QString &text )
190{
191 mTableNameEdited = !text.isEmpty();
192 if ( !text.isEmpty() && !mLayerIdentifierEdited )
193 {
194 mLayerIdentifierEdit->setText( text );
195 }
196}
197
198void QgsNewGeoPackageLayerDialog::mTableNameEdit_textEdited( const QString &text )
199{
200 // Remember if the user explicitly defined a name
201 mTableNameEdited = !text.isEmpty();
202}
203
204void QgsNewGeoPackageLayerDialog::mLayerIdentifierEdit_textEdited( const QString &text )
205{
206 // Remember if the user explicitly defined a name
207 mLayerIdentifierEdited = !text.isEmpty();
208}
209
210void QgsNewGeoPackageLayerDialog::checkOk()
211{
212 const bool ok = !mFileName->filePath().isEmpty() && !mTableNameEdit->text().isEmpty() && mGeometryTypeBox->currentIndex() != -1;
213
214 mOkButton->setEnabled( ok );
215}
216
217void QgsNewGeoPackageLayerDialog::mAddAttributeButton_clicked()
218{
219 if ( !mFieldNameEdit->text().isEmpty() )
220 {
221 const QString myName = mFieldNameEdit->text();
222 const QString featureId = mFeatureIdColumnEdit->text().isEmpty() ? QStringLiteral( DEFAULT_OGR_FID_COLUMN_TITLE ) : mFeatureIdColumnEdit->text();
223 if ( myName.compare( featureId, Qt::CaseInsensitive ) == 0 )
224 {
225 QMessageBox::critical( this, tr( "Add Field" ), tr( "The field cannot have the same name as the feature identifier." ) );
226 return;
227 }
228
229 //use userrole to avoid translated type string
230 const QString myType = mFieldTypeBox->currentData( Qt::UserRole ).toString();
231 const QString length = mFieldLengthEdit->text();
232 mAttributeView->addTopLevelItem( new QTreeWidgetItem( QStringList() << myName << myType << length ) );
233
234 checkOk();
235
236 mFieldNameEdit->clear();
237
238 if ( !mFieldNameEdit->hasFocus() )
239 {
240 mFieldNameEdit->setFocus();
241 }
242 }
243}
244
245void QgsNewGeoPackageLayerDialog::mRemoveAttributeButton_clicked()
246{
247 delete mAttributeView->currentItem();
248
249 checkOk();
250}
251
252void QgsNewGeoPackageLayerDialog::fieldNameChanged( const QString &name )
253{
254 mAddAttributeButton->setDisabled( name.isEmpty() || !mAttributeView->findItems( name, Qt::MatchExactly ).isEmpty() );
255}
256
257void QgsNewGeoPackageLayerDialog::selectionChanged()
258{
259 mRemoveAttributeButton->setDisabled( mAttributeView->selectedItems().isEmpty() );
260 mButtonUp->setDisabled( mAttributeView->selectedItems().isEmpty() );
261 mButtonDown->setDisabled( mAttributeView->selectedItems().isEmpty() );
262}
263
264void QgsNewGeoPackageLayerDialog::buttonBox_accepted()
265{
266 if ( apply() )
267 accept();
268}
269
270void QgsNewGeoPackageLayerDialog::buttonBox_rejected()
271{
272 reject();
273}
274
275void QgsNewGeoPackageLayerDialog::moveFieldsUp()
276{
277 int currentRow = mAttributeView->currentIndex().row();
278 if ( currentRow == 0 )
279 return;
280
281 mAttributeView->insertTopLevelItem( currentRow - 1, mAttributeView->takeTopLevelItem( currentRow ) );
282 mAttributeView->setCurrentIndex( mAttributeView->model()->index( currentRow - 1, 0 ) );
283}
284
285void QgsNewGeoPackageLayerDialog::moveFieldsDown()
286{
287 int currentRow = mAttributeView->currentIndex().row();
288 if ( currentRow == mAttributeView->topLevelItemCount() - 1 )
289 return;
290
291 mAttributeView->insertTopLevelItem( currentRow + 1, mAttributeView->takeTopLevelItem( currentRow ) );
292 mAttributeView->setCurrentIndex( mAttributeView->model()->index( currentRow + 1, 0 ) );
293}
294
295bool QgsNewGeoPackageLayerDialog::apply()
296{
297 if ( !mFieldNameEdit->text().trimmed().isEmpty() )
298 {
299 const QString currentFieldName = mFieldNameEdit->text();
300 bool currentFound = false;
301 QTreeWidgetItemIterator it( mAttributeView );
302 while ( *it )
303 {
304 QTreeWidgetItem *item = *it;
305 if ( item->text( 0 ) == currentFieldName )
306 {
307 currentFound = true;
308 break;
309 }
310 ++it;
311 }
312
313 if ( !currentFound )
314 {
315 if ( QMessageBox::question( this, windowTitle(), tr( "The field “%1” has not been added to the fields list. Are you sure you want to proceed and discard this field?" ).arg( currentFieldName ), QMessageBox::Ok | QMessageBox::Cancel ) != QMessageBox::Ok )
316 {
317 return false;
318 }
319 }
320 }
321
322 QString fileName( mFileName->filePath() );
323 if ( !fileName.endsWith( QLatin1String( ".gpkg" ), Qt::CaseInsensitive ) )
324 fileName += QLatin1String( ".gpkg" );
325
326 bool createNewDb = false;
327
328 if ( QFile::exists( fileName ) )
329 {
330 bool overwrite = false;
331
332 switch ( mBehavior )
333 {
334 case Prompt:
335 {
336 QMessageBox msgBox;
337 msgBox.setIcon( QMessageBox::Question );
338 msgBox.setWindowTitle( tr( "New GeoPackage Layer" ) );
339 msgBox.setText( tr( "The File already exists. Do you want to overwrite the existing file with a new database or add a new layer to it?" ) );
340 QPushButton *overwriteButton = msgBox.addButton( tr( "Overwrite" ), QMessageBox::ActionRole );
341 QPushButton *addNewLayerButton = msgBox.addButton( tr( "Add New Layer" ), QMessageBox::ActionRole );
342 msgBox.setStandardButtons( QMessageBox::Cancel );
343 msgBox.setDefaultButton( addNewLayerButton );
344 bool cancel = false;
345 if ( property( "hideDialogs" ).toBool() )
346 {
347 overwrite = property( "question_existing_db_answer_overwrite" ).toBool();
348 if ( !overwrite )
349 cancel = !property( "question_existing_db_answer_add_new_layer" ).toBool();
350 }
351 else
352 {
353 const int ret = msgBox.exec();
354 if ( ret == QMessageBox::Cancel )
355 cancel = true;
356 if ( msgBox.clickedButton() == overwriteButton )
357 overwrite = true;
358 }
359 if ( cancel )
360 {
361 return false;
362 }
363 break;
364 }
365
366 case Overwrite:
367 overwrite = true;
368 break;
369
370 case AddNewLayer:
371 overwrite = false;
372 break;
373 }
374
375 if ( overwrite )
376 {
377 QFile( fileName ).remove();
378 createNewDb = true;
379 }
380 }
381 else
382 {
383 createNewDb = true;
384 }
385
386 OGRSFDriverH hGpkgDriver = OGRGetDriverByName( "GPKG" );
387 if ( !hGpkgDriver )
388 {
389 if ( !property( "hideDialogs" ).toBool() )
390 QMessageBox::critical( this, tr( "New GeoPackage Layer" ), tr( "Layer creation failed. GeoPackage driver not found." ) );
391 return false;
392 }
393
395 if ( createNewDb )
396 {
397 hDS.reset( OGR_Dr_CreateDataSource( hGpkgDriver, fileName.toUtf8().constData(), nullptr ) );
398 if ( !hDS )
399 {
400 const QString msg( tr( "Creation of database failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
401 if ( !property( "hideDialogs" ).toBool() )
402 QMessageBox::critical( this, tr( "New GeoPackage Layer" ), msg );
403 return false;
404 }
405 }
406 else
407 {
408 OGRSFDriverH hDriver = nullptr;
409 hDS.reset( OGROpen( fileName.toUtf8().constData(), true, &hDriver ) );
410 if ( !hDS )
411 {
412 const QString msg( tr( "Opening of database failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
413 if ( !property( "hideDialogs" ).toBool() )
414 QMessageBox::critical( this, tr( "New GeoPackage Layer" ), msg );
415 return false;
416 }
417 if ( hDriver != hGpkgDriver )
418 {
419 const QString msg( tr( "Opening of file succeeded, but this is not a GeoPackage database." ) );
420 if ( !property( "hideDialogs" ).toBool() )
421 QMessageBox::critical( this, tr( "New GeoPackage Layer" ), msg );
422 return false;
423 }
424 }
425
426 const QString tableName( mTableNameEdit->text() );
427
428 bool overwriteTable = false;
429 if ( OGR_DS_GetLayerByName( hDS.get(), tableName.toUtf8().constData() ) )
430 {
431 if ( property( "hideDialogs" ).toBool() )
432 {
433 overwriteTable = property( "question_existing_layer_answer_overwrite" ).toBool();
434 }
435 else if ( QMessageBox::question( this, tr( "New GeoPackage Layer" ), tr( "A table with the same name already exists. Do you want to overwrite it?" ), QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) == QMessageBox::Yes )
436 {
437 overwriteTable = true;
438 }
439
440 if ( !overwriteTable )
441 {
442 return false;
443 }
444 }
445
446 const QString layerIdentifier( mLayerIdentifierEdit->text() );
447 const QString layerDescription( mLayerDescriptionEdit->text() );
448
449 OGRwkbGeometryType wkbType = static_cast<OGRwkbGeometryType>( mGeometryTypeBox->currentData( Qt::UserRole ).toInt() );
450
451 // z-coordinate & m-value.
452 if ( mGeometryWithZCheckBox->isChecked() )
453 wkbType = OGR_GT_SetZ( wkbType );
454
455 if ( mGeometryWithMCheckBox->isChecked() )
456 wkbType = OGR_GT_SetM( wkbType );
457
458 OGRSpatialReferenceH hSRS = nullptr;
459 // consider spatial reference system of the layer
460 const QgsCoordinateReferenceSystem srs = mCrsSelector->crs();
461 if ( wkbType != wkbNone && srs.isValid() )
462 {
464 }
465
466 // Set options
467 char **options = nullptr;
468
469 if ( overwriteTable )
470 options = CSLSetNameValue( options, "OVERWRITE", "YES" );
471 if ( !layerIdentifier.isEmpty() )
472 options = CSLSetNameValue( options, "IDENTIFIER", layerIdentifier.toUtf8().constData() );
473 if ( !layerDescription.isEmpty() )
474 options = CSLSetNameValue( options, "DESCRIPTION", layerDescription.toUtf8().constData() );
475
476 const QString featureId( mFeatureIdColumnEdit->text() );
477 if ( !featureId.isEmpty() )
478 options = CSLSetNameValue( options, "FID", featureId.toUtf8().constData() );
479
480 const QString geometryColumn( mGeometryColumnEdit->text() );
481 if ( wkbType != wkbNone && !geometryColumn.isEmpty() )
482 options = CSLSetNameValue( options, "GEOMETRY_COLUMN", geometryColumn.toUtf8().constData() );
483
484 if ( wkbType != wkbNone )
485 options = CSLSetNameValue( options, "SPATIAL_INDEX", mCheckBoxCreateSpatialIndex->isChecked() ? "YES" : "NO" );
486
487 OGRLayerH hLayer = OGR_DS_CreateLayer( hDS.get(), tableName.toUtf8().constData(), hSRS, wkbType, options );
488 CSLDestroy( options );
489 if ( hSRS )
490 OSRRelease( hSRS );
491 if ( !hLayer )
492 {
493 const QString msg( tr( "Creation of layer failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
494 if ( !property( "hideDialogs" ).toBool() )
495 QMessageBox::critical( this, tr( "New GeoPackage Layer" ), msg );
496 return false;
497 }
498
499 QTreeWidgetItemIterator it( mAttributeView );
500 while ( *it )
501 {
502 const QString fieldName( ( *it )->text( 0 ) );
503 const QString fieldType( ( *it )->text( 1 ) );
504 const QString fieldWidth( ( *it )->text( 2 ) );
505
506 OGRFieldType ogrType( OFTString );
507 OGRFieldSubType ogrSubType = OFSTNone;
508 if ( fieldType == QLatin1String( "text" ) )
509 ogrType = OFTString;
510 else if ( fieldType == QLatin1String( "integer" ) )
511 ogrType = OFTInteger;
512 else if ( fieldType == QLatin1String( "integer64" ) )
513 ogrType = OFTInteger64;
514 else if ( fieldType == QLatin1String( "real" ) )
515 ogrType = OFTReal;
516 else if ( fieldType == QLatin1String( "date" ) )
517 ogrType = OFTDate;
518 else if ( fieldType == QLatin1String( "datetime" ) )
519 ogrType = OFTDateTime;
520 else if ( fieldType == QLatin1String( "bool" ) )
521 {
522 ogrType = OFTInteger;
523 ogrSubType = OFSTBoolean;
524 }
525 else if ( fieldType == QLatin1String( "binary" ) )
526 ogrType = OFTBinary;
527 else if ( fieldType == QLatin1String( "json" ) )
528 {
529 ogrType = OFTString;
530 ogrSubType = OFSTJSON;
531 }
532
533 const int ogrWidth = fieldWidth.toInt();
534
535 const gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( fieldName.toUtf8().constData(), ogrType ) );
536 if ( ogrSubType != OFSTNone )
537 OGR_Fld_SetSubType( fld.get(), ogrSubType );
538
539 if ( ogrType != OFTBinary )
540 OGR_Fld_SetWidth( fld.get(), ogrWidth );
541
542 if ( OGR_L_CreateField( hLayer, fld.get(), true ) != OGRERR_NONE )
543 {
544 if ( !property( "hideDialogs" ).toBool() )
545 {
546 QMessageBox::critical( this, tr( "New GeoPackage Layer" ), tr( "Creation of field %1 failed (OGR error: %2)" ).arg( fieldName, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
547 }
548 return false;
549 }
550
551 ++it;
552 }
553
554 // In GDAL >= 2.0, the driver implements a deferred creation strategy, so
555 // issue a command that will force table creation
556 CPLErrorReset();
557 OGR_L_ResetReading( hLayer );
558 if ( CPLGetLastErrorType() != CE_None )
559 {
560 const QString msg( tr( "Creation of layer failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
561 if ( !property( "hideDialogs" ).toBool() )
562 QMessageBox::critical( this, tr( "New GeoPackage Layer" ), msg );
563 return false;
564 }
565 hDS.reset();
566
567 const QString uri( QStringLiteral( "%1|layername=%2" ).arg( fileName, tableName ) );
568 const QString userVisiblelayerName( layerIdentifier.isEmpty() ? tableName : layerIdentifier );
569 const QgsVectorLayer::LayerOptions layerOptions { QgsProject::instance()->transformContext() };
570 auto layer = std::make_unique<QgsVectorLayer>( uri, userVisiblelayerName, QStringLiteral( "ogr" ), layerOptions );
571 if ( layer->isValid() )
572 {
573 if ( mAddToProject )
574 {
575 // register this layer with the central layers registry
576 QList<QgsMapLayer *> myList;
577 myList << layer.release();
578 //addMapLayers returns a list of all successfully added layers
579 //so we compare that to our original list.
580 if ( myList == QgsProject::instance()->addMapLayers( myList ) )
581 return true;
582 }
583 else
584 {
585 return true;
586 }
587 }
588 else
589 {
590 if ( !property( "hideDialogs" ).toBool() )
591 QMessageBox::critical( this, tr( "New GeoPackage Layer" ), tr( "%1 is an invalid layer and cannot be loaded." ).arg( tableName ) );
592 }
593
594 return false;
595}
596
598{
599 mBehavior = behavior;
600}
601
603{
604 mAddToProject = addToProject;
605}
606
607void QgsNewGeoPackageLayerDialog::showHelp()
608{
609 QgsHelp::openHelp( QStringLiteral( "managing_data_source/create_layers.html#creating-a-new-geopackage-layer" ) );
610}
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:277
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
static QIcon iconForFieldType(QMetaType::Type type, QMetaType::Type subType=QMetaType::Type::UnknownType, const QString &typeString=QString())
Returns an icon corresponding to a field type.
@ SaveFile
Select a single new or pre-existing file.
void fileChanged(const QString &path)
Emitted whenever the current file or directory path is changed.
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:221
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:38
static QIcon iconForWkbType(Qgis::WkbType type)
Returns the icon for a vector layer whose geometry type is provided.
OverwriteBehavior
Behavior to use when an existing geopackage already exists.
@ AddNewLayer
Keep existing contents and add new layer.
@ Overwrite
Overwrite whole geopackage.
void setAddToProject(bool addToProject)
Sets whether a newly created layer should automatically be added to the current project.
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the crs value for the new layer in the dialog.
void lockDatabasePath()
Sets the database path widgets to a locked and read-only mode.
QgsNewGeoPackageLayerDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
Constructor.
void setOverwriteBehavior(OverwriteBehavior behavior)
Sets the behavior to use when a path to an existing geopackage file is used.
static Qgis::WkbType ogrGeometryTypeToQgsWkbType(OGRwkbGeometryType ogrGeomType)
Converts a OGRwkbGeometryType to QgsWkbTypes::Type.
static OGRSpatialReferenceH crsToOGRSpatialReference(const QgsCoordinateReferenceSystem &crs)
Returns a OGRSpatialReferenceH corresponding to the specified crs object.
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsCoordinateTransformContext transformContext
Definition qgsproject.h:116
A model containing registered connection names for a specific data provider.
Stores settings for use within QGIS.
Definition qgssettings.h:65
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 QString typeToDisplayString(QMetaType::Type type, QMetaType::Type subType=QMetaType::Type::UnknownType)
Returns a user-friendly translated string representing a QVariant type.
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...
std::unique_ptr< std::remove_pointer< OGRDataSourceH >::type, OGRDataSourceDeleter > ogr_datasource_unique_ptr
Scoped OGR data source.
std::unique_ptr< std::remove_pointer< OGRFieldDefnH >::type, OGRFldDeleter > ogr_field_def_unique_ptr
Scoped OGR field definition.
#define DEFAULT_OGR_FID_COLUMN_TITLE