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