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