QGIS API Documentation  3.13.0-Master (b73bd58cfb)
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 "qgis.h"
23 #include "qgsapplication.h"
24 #include "qgsproviderregistry.h"
25 #include "qgsvectorlayer.h"
26 #include "qgsproject.h"
29 #include "qgslogger.h"
30 #include "qgssettings.h"
31 #include "qgshelp.h"
32 #include "qgsogrutils.h"
33 #include "qgsgui.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 
50 QgsNewGeoPackageLayerDialog::QgsNewGeoPackageLayerDialog( QWidget *parent, Qt::WindowFlags fl )
51  : QDialog( parent, fl )
52 {
53  setupUi( this );
55 
56  connect( mAddAttributeButton, &QToolButton::clicked, this, &QgsNewGeoPackageLayerDialog::mAddAttributeButton_clicked );
57  connect( mRemoveAttributeButton, &QToolButton::clicked, this, &QgsNewGeoPackageLayerDialog::mRemoveAttributeButton_clicked );
58  connect( mFieldTypeBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsNewGeoPackageLayerDialog::mFieldTypeBox_currentIndexChanged );
59  connect( mGeometryTypeBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsNewGeoPackageLayerDialog::mGeometryTypeBox_currentIndexChanged );
60  connect( mTableNameEdit, &QLineEdit::textChanged, this, &QgsNewGeoPackageLayerDialog::mTableNameEdit_textChanged );
61  connect( mTableNameEdit, &QLineEdit::textEdited, this, &QgsNewGeoPackageLayerDialog::mTableNameEdit_textEdited );
62  connect( mLayerIdentifierEdit, &QLineEdit::textEdited, this, &QgsNewGeoPackageLayerDialog::mLayerIdentifierEdit_textEdited );
63  connect( buttonBox, &QDialogButtonBox::accepted, this, &QgsNewGeoPackageLayerDialog::buttonBox_accepted );
64  connect( buttonBox, &QDialogButtonBox::rejected, this, &QgsNewGeoPackageLayerDialog::buttonBox_rejected );
65  connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsNewGeoPackageLayerDialog::showHelp );
66 
67  mAddAttributeButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionNewAttribute.svg" ) ) );
68  mRemoveAttributeButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteAttribute.svg" ) ) );
69 
70  mGeometryTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconTableLayer.svg" ) ), tr( "No geometry" ), wkbNone );
71  mGeometryTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconPointLayer.svg" ) ), tr( "Point" ), wkbPoint );
72  mGeometryTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconLineLayer.svg" ) ), tr( "Line" ), wkbLineString );
73  mGeometryTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconPolygonLayer.svg" ) ), tr( "Polygon" ), wkbPolygon );
74  mGeometryTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconPointLayer.svg" ) ), tr( "MultiPoint" ), wkbMultiPoint );
75  mGeometryTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconLineLayer.svg" ) ), tr( "MultiLine" ), wkbMultiLineString );
76  mGeometryTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconPolygonLayer.svg" ) ), tr( "MultiPolygon" ), wkbMultiPolygon );
77 
78 #if 0
79  // QGIS always create CompoundCurve and there's no real interest of having just CircularString. CompoundCurve are more useful
80  mGeometryTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconLineLayer.svg" ) ), tr( "CircularString" ), wkbCircularString );
81 #endif
82  mGeometryTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconLineLayer.svg" ) ), tr( "CompoundCurve" ), wkbCompoundCurve );
83  mGeometryTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconPolygonLayer.svg" ) ), tr( "CurvePolygon" ), wkbCurvePolygon );
84  mGeometryTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconLineLayer.svg" ) ), tr( "MultiCurve" ), wkbMultiCurve );
85  mGeometryTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconPolygonLayer.svg" ) ), tr( "MultiSurface" ), wkbMultiSurface );
86 
87  mGeometryWithZCheckBox->setEnabled( false );
88  mGeometryWithMCheckBox->setEnabled( false );
89  mGeometryColumnEdit->setEnabled( false );
90  mGeometryColumnEdit->setText( QStringLiteral( "geometry" ) );
91  mFeatureIdColumnEdit->setPlaceholderText( QStringLiteral( DEFAULT_OGR_FID_COLUMN_TITLE ) );
92  mCheckBoxCreateSpatialIndex->setEnabled( false );
93  mCrsSelector->setEnabled( false );
94 
95  mFieldTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconFieldText.svg" ) ), tr( "Text data" ), "text" );
96  mFieldTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconFieldInteger.svg" ) ), tr( "Whole number (integer)" ), "integer" );
97  mFieldTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconFieldInteger.svg" ) ), tr( "Whole number (integer 64 bit)" ), "integer64" );
98  mFieldTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconFieldFloat.svg" ) ), tr( "Decimal number (real)" ), "real" );
99  mFieldTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconFieldDate.svg" ) ), tr( "Date" ), "date" );
100  mFieldTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconFieldDateTime.svg" ) ), tr( "Date & time" ), "datetime" );
101  mFieldTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconFieldBool.svg" ) ), tr( "Boolean" ), "bool" );
102  mFieldTypeBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mIconFieldBinary.svg" ) ), tr( "Binary (BLOB)" ), "binary" );
103 
104  mOkButton = buttonBox->button( QDialogButtonBox::Ok );
105  mOkButton->setEnabled( false );
106 
107  connect( mFieldNameEdit, &QLineEdit::textChanged, this, &QgsNewGeoPackageLayerDialog::fieldNameChanged );
108  connect( mAttributeView, &QTreeWidget::itemSelectionChanged, this, &QgsNewGeoPackageLayerDialog::selectionChanged );
109  connect( mTableNameEdit, &QLineEdit::textChanged, this, &QgsNewGeoPackageLayerDialog::checkOk );
110 
111  mAddAttributeButton->setEnabled( false );
112  mRemoveAttributeButton->setEnabled( false );
113 
114  mCheckBoxCreateSpatialIndex->setChecked( true );
115 
116  QgsSettings settings;
117  mDatabase->setStorageMode( QgsFileWidget::SaveFile );
118  mDatabase->setFilter( tr( "GeoPackage" ) + " (*.gpkg)" );
119  mDatabase->setDialogTitle( tr( "Select Existing or Create a New GeoPackage Database Fileā€¦" ) );
120  mDatabase->setDefaultRoot( settings.value( QStringLiteral( "UI/lastVectorFileFilterDir" ), QDir::homePath() ).toString() );
121  mDatabase->setConfirmOverwrite( false );
122  connect( mDatabase, &QgsFileWidget::fileChanged, this, [ = ]( const QString & filePath )
123  {
124  QgsSettings settings;
125  QFileInfo tmplFileInfo( filePath );
126  settings.setValue( QStringLiteral( "UI/lastVectorFileFilterDir" ), tmplFileInfo.absolutePath() );
127  if ( !filePath.isEmpty() && !mTableNameEdited )
128  {
129  QFileInfo fileInfo( filePath );
130  mTableNameEdit->setText( fileInfo.baseName() );
131  }
132  checkOk();
133  } );
134 
135  QgsProviderConnectionModel *ogrProviderModel = new QgsProviderConnectionModel( QStringLiteral( "ogr" ), this );
136 
137  QCompleter *completer = new QCompleter( this );
138  completer->setModel( ogrProviderModel );
139  completer->setCompletionRole( QgsProviderConnectionModel::RoleUri );
140  completer->setCompletionMode( QCompleter::PopupCompletion );
141  completer->setFilterMode( Qt::MatchContains );
142  mDatabase->lineEdit()->setCompleter( completer );
143 }
144 
146 {
147  mCrsSelector->setCrs( crs );
148 }
149 
151 {
152  mDatabase->setReadOnly( true );
153 }
154 
155 void QgsNewGeoPackageLayerDialog::mFieldTypeBox_currentIndexChanged( int )
156 {
157  QString myType = mFieldTypeBox->currentData( Qt::UserRole ).toString();
158  mFieldLengthEdit->setEnabled( myType == QLatin1String( "text" ) );
159  if ( myType != QLatin1String( "text" ) )
160  mFieldLengthEdit->clear();
161 }
162 
163 
164 void QgsNewGeoPackageLayerDialog::mGeometryTypeBox_currentIndexChanged( int )
165 {
166  OGRwkbGeometryType geomType = static_cast<OGRwkbGeometryType>
167  ( mGeometryTypeBox->currentData( Qt::UserRole ).toInt() );
168  bool isSpatial = geomType != wkbNone;
169  mGeometryWithZCheckBox->setEnabled( isSpatial );
170  mGeometryWithMCheckBox->setEnabled( isSpatial );
171  mGeometryColumnEdit->setEnabled( isSpatial );
172  mCheckBoxCreateSpatialIndex->setEnabled( isSpatial );
173  mCrsSelector->setEnabled( isSpatial );
174 }
175 
176 void QgsNewGeoPackageLayerDialog::mTableNameEdit_textChanged( const QString &text )
177 {
178  mTableNameEdited = !text.isEmpty();
179  if ( !text.isEmpty() && !mLayerIdentifierEdited )
180  {
181  mLayerIdentifierEdit->setText( text );
182  }
183 }
184 
185 void QgsNewGeoPackageLayerDialog::mTableNameEdit_textEdited( const QString &text )
186 {
187  // Remember if the user explicitly defined a name
188  mTableNameEdited = !text.isEmpty();
189 }
190 
191 void QgsNewGeoPackageLayerDialog::mLayerIdentifierEdit_textEdited( const QString &text )
192 {
193  // Remember if the user explicitly defined a name
194  mLayerIdentifierEdited = !text.isEmpty();
195 }
196 
197 void QgsNewGeoPackageLayerDialog::checkOk()
198 {
199  bool ok = !mDatabase->filePath().isEmpty() &&
200  !mTableNameEdit->text().isEmpty();
201  mOkButton->setEnabled( ok );
202 }
203 
204 void QgsNewGeoPackageLayerDialog::mAddAttributeButton_clicked()
205 {
206  if ( !mFieldNameEdit->text().isEmpty() )
207  {
208  QString myName = mFieldNameEdit->text();
209  const QString featureId = mFeatureIdColumnEdit->text().isEmpty() ? QStringLiteral( DEFAULT_OGR_FID_COLUMN_TITLE ) : mFeatureIdColumnEdit->text();
210  if ( myName.compare( featureId, Qt::CaseInsensitive ) == 0 )
211  {
212  QMessageBox::critical( this, tr( "Add Field" ), tr( "The field cannot have the same name as the feature identifier." ) );
213  return;
214  }
215 
216  //use userrole to avoid translated type string
217  QString myType = mFieldTypeBox->currentData( Qt::UserRole ).toString();
218  QString length = mFieldLengthEdit->text();
219  mAttributeView->addTopLevelItem( new QTreeWidgetItem( QStringList() << myName << myType << length ) );
220 
221  checkOk();
222 
223  mFieldNameEdit->clear();
224  }
225 }
226 
227 void QgsNewGeoPackageLayerDialog::mRemoveAttributeButton_clicked()
228 {
229  delete mAttributeView->currentItem();
230 
231  checkOk();
232 }
233 
234 void QgsNewGeoPackageLayerDialog::fieldNameChanged( const QString &name )
235 {
236  mAddAttributeButton->setDisabled( name.isEmpty() || ! mAttributeView->findItems( name, Qt::MatchExactly ).isEmpty() );
237 }
238 
239 void QgsNewGeoPackageLayerDialog::selectionChanged()
240 {
241  mRemoveAttributeButton->setDisabled( mAttributeView->selectedItems().isEmpty() );
242 }
243 
244 void QgsNewGeoPackageLayerDialog::buttonBox_accepted()
245 {
246  if ( apply() )
247  accept();
248 }
249 
250 void QgsNewGeoPackageLayerDialog::buttonBox_rejected()
251 {
252  reject();
253 }
254 
255 bool QgsNewGeoPackageLayerDialog::apply()
256 {
257  QString fileName( mDatabase->filePath() );
258  if ( !fileName.endsWith( QLatin1String( ".gpkg" ), Qt::CaseInsensitive ) )
259  fileName += QLatin1String( ".gpkg" );
260 
261  bool createNewDb = false;
262 
263  if ( QFile( fileName ).exists( fileName ) )
264  {
265  bool overwrite = false;
266 
267  switch ( mBehavior )
268  {
269  case Prompt:
270  {
271  QMessageBox msgBox;
272  msgBox.setIcon( QMessageBox::Question );
273  msgBox.setWindowTitle( tr( "New GeoPackage Layer" ) );
274  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?" ) );
275  QPushButton *overwriteButton = msgBox.addButton( tr( "Overwrite" ), QMessageBox::ActionRole );
276  QPushButton *addNewLayerButton = msgBox.addButton( tr( "Add New Layer" ), QMessageBox::ActionRole );
277  msgBox.setStandardButtons( QMessageBox::Cancel );
278  msgBox.setDefaultButton( addNewLayerButton );
279  bool cancel = false;
280  if ( property( "hideDialogs" ).toBool() )
281  {
282  overwrite = property( "question_existing_db_answer_overwrite" ).toBool();
283  if ( !overwrite )
284  cancel = !property( "question_existing_db_answer_add_new_layer" ).toBool();
285  }
286  else
287  {
288  int ret = msgBox.exec();
289  if ( ret == QMessageBox::Cancel )
290  cancel = true;
291  if ( msgBox.clickedButton() == overwriteButton )
292  overwrite = true;
293  }
294  if ( cancel )
295  {
296  return false;
297  }
298  break;
299  }
300 
301  case Overwrite:
302  overwrite = true;
303  break;
304 
305  case AddNewLayer:
306  overwrite = false;
307  break;
308  }
309 
310  if ( overwrite )
311  {
312  QFile( fileName ).remove();
313  createNewDb = true;
314  }
315  }
316  else
317  {
318  createNewDb = true;
319  }
320 
321  OGRSFDriverH hGpkgDriver = OGRGetDriverByName( "GPKG" );
322  if ( !hGpkgDriver )
323  {
324  if ( !property( "hideDialogs" ).toBool() )
325  QMessageBox::critical( this, tr( "New GeoPackage Layer" ),
326  tr( "Layer creation failed. GeoPackage driver not found." ) );
327  return false;
328  }
329 
331  if ( createNewDb )
332  {
333  hDS.reset( OGR_Dr_CreateDataSource( hGpkgDriver, fileName.toUtf8().constData(), nullptr ) );
334  if ( !hDS )
335  {
336  QString msg( tr( "Creation of database failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
337  if ( !property( "hideDialogs" ).toBool() )
338  QMessageBox::critical( this, tr( "New GeoPackage Layer" ), msg );
339  return false;
340  }
341  }
342  else
343  {
344  OGRSFDriverH hDriver = nullptr;
345  hDS.reset( OGROpen( fileName.toUtf8().constData(), true, &hDriver ) );
346  if ( !hDS )
347  {
348  QString msg( tr( "Opening of database failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
349  if ( !property( "hideDialogs" ).toBool() )
350  QMessageBox::critical( this, tr( "New GeoPackage Layer" ), msg );
351  return false;
352  }
353  if ( hDriver != hGpkgDriver )
354  {
355  QString msg( tr( "Opening of file succeeded, but this is not a GeoPackage database." ) );
356  if ( !property( "hideDialogs" ).toBool() )
357  QMessageBox::critical( this, tr( "New GeoPackage Layer" ), msg );
358  return false;
359  }
360  }
361 
362  QString tableName( mTableNameEdit->text() );
363 
364  bool overwriteTable = false;
365  if ( OGR_DS_GetLayerByName( hDS.get(), tableName.toUtf8().constData() ) )
366  {
367  if ( property( "hideDialogs" ).toBool() )
368  {
369  overwriteTable = property( "question_existing_layer_answer_overwrite" ).toBool();
370  }
371  else if ( QMessageBox::question( this, tr( "New GeoPackage Layer" ),
372  tr( "A table with the same name already exists. Do you want to overwrite it?" ),
373  QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) == QMessageBox::Yes )
374  {
375  overwriteTable = true;
376  }
377 
378  if ( !overwriteTable )
379  {
380  return false;
381  }
382  }
383 
384  QString layerIdentifier( mLayerIdentifierEdit->text() );
385  QString layerDescription( mLayerDescriptionEdit->text() );
386 
387  OGRwkbGeometryType wkbType = static_cast<OGRwkbGeometryType>
388  ( mGeometryTypeBox->currentData( Qt::UserRole ).toInt() );
389 
390  // z-coordinate & m-value.
391  if ( mGeometryWithZCheckBox->isChecked() )
392  wkbType = OGR_GT_SetZ( wkbType );
393 
394  if ( mGeometryWithMCheckBox->isChecked() )
395  wkbType = OGR_GT_SetM( wkbType );
396 
397  OGRSpatialReferenceH hSRS = nullptr;
398  // consider spatial reference system of the layer
399  QgsCoordinateReferenceSystem srs = mCrsSelector->crs();
400  if ( wkbType != wkbNone && srs.isValid() )
401  {
402  QString srsWkt = srs.toWkt( QgsCoordinateReferenceSystem::WKT2_2018 );
403  hSRS = OSRNewSpatialReference( srsWkt.toLocal8Bit().data() );
404  }
405 
406  // Set options
407  char **options = nullptr;
408 
409  if ( overwriteTable )
410  options = CSLSetNameValue( options, "OVERWRITE", "YES" );
411  if ( !layerIdentifier.isEmpty() )
412  options = CSLSetNameValue( options, "IDENTIFIER", layerIdentifier.toUtf8().constData() );
413  if ( !layerDescription.isEmpty() )
414  options = CSLSetNameValue( options, "DESCRIPTION", layerDescription.toUtf8().constData() );
415 
416  QString featureId( mFeatureIdColumnEdit->text() );
417  if ( !featureId.isEmpty() )
418  options = CSLSetNameValue( options, "FID", featureId.toUtf8().constData() );
419 
420  QString geometryColumn( mGeometryColumnEdit->text() );
421  if ( wkbType != wkbNone && !geometryColumn.isEmpty() )
422  options = CSLSetNameValue( options, "GEOMETRY_COLUMN", geometryColumn.toUtf8().constData() );
423 
424  if ( wkbType != wkbNone )
425  options = CSLSetNameValue( options, "SPATIAL_INDEX", mCheckBoxCreateSpatialIndex->isChecked() ? "YES" : "NO" );
426 
427  OGRLayerH hLayer = OGR_DS_CreateLayer( hDS.get(), tableName.toUtf8().constData(), hSRS, wkbType, options );
428  CSLDestroy( options );
429  if ( hSRS )
430  OSRRelease( hSRS );
431  if ( !hLayer )
432  {
433  QString msg( tr( "Creation of layer failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
434  if ( !property( "hideDialogs" ).toBool() )
435  QMessageBox::critical( this, tr( "New GeoPackage Layer" ), msg );
436  return false;
437  }
438 
439  QTreeWidgetItemIterator it( mAttributeView );
440  while ( *it )
441  {
442  QString fieldName( ( *it )->text( 0 ) );
443  QString fieldType( ( *it )->text( 1 ) );
444  QString fieldWidth( ( *it )->text( 2 ) );
445 
446  bool isBool = false;
447  OGRFieldType ogrType( OFTString );
448  if ( fieldType == QLatin1String( "text" ) )
449  ogrType = OFTString;
450  else if ( fieldType == QLatin1String( "integer" ) )
451  ogrType = OFTInteger;
452  else if ( fieldType == QLatin1String( "integer64" ) )
453  ogrType = OFTInteger64;
454  else if ( fieldType == QLatin1String( "real" ) )
455  ogrType = OFTReal;
456  else if ( fieldType == QLatin1String( "date" ) )
457  ogrType = OFTDate;
458  else if ( fieldType == QLatin1String( "datetime" ) )
459  ogrType = OFTDateTime;
460  else if ( fieldType == QLatin1String( "bool" ) )
461  {
462  ogrType = OFTInteger;
463  isBool = true;
464  }
465  else if ( fieldType == QLatin1String( "binary" ) )
466  ogrType = OFTBinary;
467 
468  int ogrWidth = fieldWidth.toInt();
469 
470  gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( fieldName.toUtf8().constData(), ogrType ) );
471  if ( ogrType != OFTBinary )
472  OGR_Fld_SetWidth( fld.get(), ogrWidth );
473  if ( isBool )
474  OGR_Fld_SetSubType( fld.get(), OFSTBoolean );
475 
476  if ( OGR_L_CreateField( hLayer, fld.get(), true ) != OGRERR_NONE )
477  {
478  if ( !property( "hideDialogs" ).toBool() )
479  {
480  QMessageBox::critical( this, tr( "New GeoPackage Layer" ),
481  tr( "Creation of field %1 failed (OGR error: %2)" )
482  .arg( fieldName, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
483  }
484  return false;
485  }
486 
487  ++it;
488  }
489 
490  // In GDAL >= 2.0, the driver implements a deferred creation strategy, so
491  // issue a command that will force table creation
492  CPLErrorReset();
493  OGR_L_ResetReading( hLayer );
494  if ( CPLGetLastErrorType() != CE_None )
495  {
496  QString msg( tr( "Creation of layer failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
497  if ( !property( "hideDialogs" ).toBool() )
498  QMessageBox::critical( this, tr( "New GeoPackage Layer" ), msg );
499  return false;
500  }
501  hDS.reset();
502 
503  QString uri( QStringLiteral( "%1|layername=%2" ).arg( fileName, tableName ) );
504  QString userVisiblelayerName( layerIdentifier.isEmpty() ? tableName : layerIdentifier );
506  std::unique_ptr< QgsVectorLayer > layer = qgis::make_unique< QgsVectorLayer >( uri, userVisiblelayerName, QStringLiteral( "ogr" ), layerOptions );
507  if ( layer->isValid() )
508  {
509  if ( mAddToProject )
510  {
511  // register this layer with the central layers registry
512  QList<QgsMapLayer *> myList;
513  myList << layer.release();
514  //addMapLayers returns a list of all successfully added layers
515  //so we compare that to our original list.
516  if ( myList == QgsProject::instance()->addMapLayers( myList ) )
517  return true;
518  }
519  else
520  {
521  return true;
522  }
523  }
524  else
525  {
526  if ( !property( "hideDialogs" ).toBool() )
527  QMessageBox::critical( this, tr( "New GeoPackage Layer" ), tr( "%1 is an invalid layer and cannot be loaded." ).arg( tableName ) );
528  }
529 
530  return false;
531 }
532 
534 {
535  mBehavior = behavior;
536 }
537 
539 {
540  mAddToProject = addToProject;
541 }
542 
543 void QgsNewGeoPackageLayerDialog::showHelp()
544 {
545  QgsHelp::openHelp( QStringLiteral( "managing_data_source/create_layers.html#creating-a-new-geopackage-layer" ) );
546 }
void setOverwriteBehavior(OverwriteBehavior behavior)
Sets the behavior to use when a path to an existing geopackage file is used.
#define DEFAULT_OGR_FID_COLUMN_TITLE
This class is a composition of two QSettings instances:
Definition: qgssettings.h:61
Setting options for loading vector layers.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
QgsNewGeoPackageLayerDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
Constructor.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Keep existing contents and add new layer.
const QgsCoordinateReferenceSystem & crs
A model containing registered connection names for a specific data provider.
OverwriteBehavior
Behavior to use when an existing geopackage already exists.
void fileChanged(const QString &path)
Emitted whenever the current file or directory path is changed.
void setAddToProject(bool addToProject)
Sets whether a newly created layer should automatically be added to the current project.
Full WKT2 string, conforming to ISO 19162:2018 / OGC 18-010, with all possible nodes and new keyword ...
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:99
void lockDatabasePath()
Sets the database path widgets to a locked and read-only mode.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:458
This class represents a coordinate reference system (CRS).
std::unique_ptr< std::remove_pointer< OGRFieldDefnH >::type, OGRFldDeleter > ogr_field_def_unique_ptr
Scoped OGR field definition.
Definition: qgsogrutils.h:124
Select a single new or pre-existing file.
Definition: qgsfilewidget.h:68
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:133
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the crs value for the new layer in the dialog.
std::unique_ptr< std::remove_pointer< OGRDataSourceH >::type, OGRDataSourceDeleter > ogr_datasource_unique_ptr
Scoped OGR data source.
Definition: qgsogrutils.h:114
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
void * OGRSpatialReferenceH
bool isValid() const
Returns whether this CRS is correctly initialized and usable.