QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgsnewvectortabledialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsnewvectortabledialog.cpp - QgsNewVectorTableDialog
3 
4  ---------------------
5  begin : 12.7.2020
6  copyright : (C) 2020 by Alessandro Pasotti
7  email : elpaso at itopen dot it
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
17 #include "qgsdataitem.h"
18 #include "qgsvectorlayer.h"
19 #include "qgslogger.h"
20 #include "qgsgui.h"
21 #include "qgsapplication.h"
22 #include <QSpinBox>
23 #include <QMessageBox>
24 #include <QTimer>
25 
27  : QDialog( parent )
28  , mConnection( conn )
29 {
30 
31  setupUi( this );
32 
33  // This is a precondition for the dialog to work correctly
34  try
35  {
36  mFieldModel = new QgsNewVectorTableFieldModel( mConnection->nativeTypes(), this );
37  }
38  catch ( QgsProviderConnectionException &ex )
39  {
40  QMessageBox::critical( nullptr, tr( "Cannot Create New Tables" ), tr( "Error retrieving native types from the data provider: creation of new tables is not possible.\n"
41  "Error message: %1" ).arg( ex.what() ) );
42  QTimer::singleShot( 0, [ = ] { reject(); } );
43  return;
44  }
45 
46  Q_ASSERT( ! mFieldModel->nativeTypes().isEmpty() );
47 
49  setWindowTitle( tr( "New Table" ) );
50 
51  auto updateTableNames = [ = ]( const QString &schema = QString( ) )
52  {
53  mTableNames.clear();
54  try
55  {
56  const auto constTables { conn->tables( schema ) };
57  for ( const auto &tp : constTables )
58  {
59  mTableNames.push_back( tp.tableName() );
60  }
61  validate();
62  }
63  catch ( QgsProviderConnectionException &ex )
64  {
65  // This should never happen but it's not critical, we can safely continue.
66  QgsDebugMsg( QStringLiteral( "Error retrieving tables from connection: %1" ).arg( ex.what() ) );
67  }
68  };
69 
70  // Validate on data changed
71  connect( mFieldModel, &QgsNewVectorTableFieldModel::modelReset, this, [ = ]()
72  {
73  validate();
74  } );
75 
76  mTableName->setText( QStringLiteral( "new_table_name" ) );
77  mFieldsTableView->setModel( mFieldModel );
78  QgsNewVectorTableDialogFieldsDelegate *delegate { new QgsNewVectorTableDialogFieldsDelegate( mConnection->nativeTypes(), this )};
79  mFieldsTableView->setItemDelegate( delegate );
80  mFieldsTableView->setSelectionBehavior( QAbstractItemView::SelectionBehavior::SelectRows );
81  mFieldsTableView->setSelectionMode( QAbstractItemView::SelectionMode::SingleSelection );
82  mFieldsTableView->setVerticalHeader( nullptr );
83 
84  // Cosmetics
85  mFieldsTableView->horizontalHeader()->setStretchLastSection( true );
86  mFieldsTableView->setColumnWidth( QgsNewVectorTableFieldModel::ColumnHeaders::Type, 300 );
87 
88  // Schema is not supported by all providers
89  if ( mConnection->capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::Schemas ) )
90  {
91  mSchemaCbo->addItems( mConnection->schemas() );
92  connect( mSchemaCbo, &QComboBox::currentTextChanged, this, [ = ]( const QString & schema )
93  {
94  updateTableNames( schema );
95  } );
96  }
97  else
98  {
99  mSchemaCbo->hide();
100  mSchemaLabel->hide();
101  }
102 
103  if ( ! mConnection->capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::CreateSpatialIndex ) )
104  {
105  mSpatialIndexChk->setChecked( false );
106  mSpatialIndexChk->hide();
107  mSpatialIndexLabel->hide();
108  }
109 
110  // Initial load of table names
111  updateTableNames( mSchemaCbo->currentText() );
112 
113  // Validators
114  connect( mTableName, &QLineEdit::textChanged, this, [ = ]( const QString & )
115  {
116  validate();
117  } );
118 
119  connect( mGeomColumn, &QLineEdit::textChanged, this, [ = ]( const QString & )
120  {
121  validate();
122  } );
123 
124  // Enable/disable geometry options and call validate
125  connect( mGeomTypeCbo, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, [ = ]( int index )
126  {
127  const bool hasGeom { index != 0 };
128  mGeomColumn->setEnabled( hasGeom );
129  mGeomColumnLabel->setEnabled( hasGeom );
130  mSpatialIndexChk->setEnabled( hasGeom );
131  mSpatialIndexLabel->setEnabled( hasGeom );
132  mCrs->setEnabled( hasGeom );
133  mCrsLabel->setEnabled( hasGeom );
134  mDimensionsLabel->setEnabled( hasGeom );
135  mHasMChk->setEnabled( hasGeom );
136  mHasZChk->setEnabled( hasGeom );
137  validate();
138  } );
139 
140  // geometry types
141  const bool hasSinglePart { conn->geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::SinglePart ) };
142 
143  const auto addGeomItem = [this]( QgsWkbTypes::Type type )
144  {
145  mGeomTypeCbo->addItem( QgsLayerItem::iconForWkbType( type ), QgsWkbTypes::translatedDisplayString( type ), type );
146  };
147 
148  mGeomTypeCbo->addItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconTableLayer.svg" ) ), tr( "No Geometry" ), QgsWkbTypes::Type::NoGeometry );
149  if ( hasSinglePart )
150  addGeomItem( QgsWkbTypes::Type::Point );
151  addGeomItem( QgsWkbTypes::Type::MultiPoint );
152  if ( hasSinglePart )
153  addGeomItem( QgsWkbTypes::Type::LineString );
154  addGeomItem( QgsWkbTypes::Type::MultiLineString );
155  if ( hasSinglePart )
156  addGeomItem( QgsWkbTypes::Type::Polygon );
157  addGeomItem( QgsWkbTypes::Type::MultiPolygon );
158 
159  if ( conn->geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::Curves ) )
160  {
161  addGeomItem( QgsWkbTypes::Type::CompoundCurve );
162  addGeomItem( QgsWkbTypes::Type::CurvePolygon );
163  addGeomItem( QgsWkbTypes::Type::MultiCurve );
164  addGeomItem( QgsWkbTypes::Type::MultiSurface );
165  }
166 
167  mGeomTypeCbo->setCurrentIndex( 0 );
168 
169  const bool hasZ { conn->geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::Z ) };
170  const bool hasM { conn->geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::M ) };
171  if ( ! hasM )
172  {
173  mHasMChk->setEnabled( false );
174  mHasMChk->setChecked( false );
175  }
176  if ( ! hasZ )
177  {
178  mHasZChk->setEnabled( false );
179  mHasZChk->setChecked( false );
180  }
181  if ( ! hasM && ! hasM )
182  {
183  mHasZChk->setVisible( false );
184  mHasMChk->setVisible( false );
185  mDimensionsLabel->setVisible( false );
186  }
187 
188  connect( mFieldsTableView->selectionModel(), &QItemSelectionModel::selectionChanged, mFieldsTableView, [ = ]( const QItemSelection & selected, const QItemSelection & )
189  {
190  if ( ! selected.isEmpty() )
191  {
192  mCurrentRow = selected.indexes().first().row();
193  }
194  updateButtons();
195  } );
196 
197  // Get a default type for new fields
198  const QVariant::Type defaultFieldType { mFieldModel->nativeTypes().first().mType };
199  const QString defaultFieldTypeName { mFieldModel->nativeTypes().first().mTypeName };
200 
201  // Actions
202  connect( mAddFieldBtn, &QPushButton::clicked, this, [ = ]
203  {
204  QgsFields fieldList { fields() };
205  QgsField newField { QStringLiteral( "new_field_name" ), defaultFieldType, defaultFieldTypeName };
206  fieldList.append( newField );
207  setFields( fieldList );
208  selectRow( fieldList.count() - 1 );
209  } );
210 
211  connect( mDeleteFieldBtn, &QPushButton::clicked, this, [ = ]
212  {
213  QgsFields fieldList { fields() };
214  if ( fieldList.exists( mCurrentRow ) )
215  {
216  fieldList.remove( mCurrentRow );
217  setFields( fieldList );
218  mCurrentRow = -1;
219  }
220  } );
221 
222  connect( mFieldUpBtn, &QPushButton::clicked, this, [ = ]
223  {
224  if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow - 1 ) )
225  {
226  QgsFields fieldList;
227  for ( int i = 0; i < fields().count(); ++i )
228  {
229  if ( i == mCurrentRow - 1 )
230  {
231  fieldList.append( fields().at( mCurrentRow ) );
232  fieldList.append( fields().at( mCurrentRow - 1 ) );
233  }
234  else if ( i != mCurrentRow )
235  {
236  fieldList.append( fields().at( i ) );
237  }
238  }
239  setFields( fieldList );
240  selectRow( mCurrentRow - 1 );
241  }
242  } );
243 
244  connect( mFieldDownBtn, &QPushButton::clicked, this, [ = ]
245  {
246  if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow + 1 ) )
247  {
248  QgsFields fieldList;
249  for ( int i = 0; i < fields().count(); ++i )
250  {
251  if ( i == mCurrentRow )
252  {
253  fieldList.append( fields().at( mCurrentRow + 1 ) );
254  fieldList.append( fields().at( mCurrentRow ) );
255  }
256  else if ( i != mCurrentRow + 1 )
257  {
258  fieldList.append( fields().at( i ) );
259  }
260  }
261  setFields( fieldList );
262  selectRow( mCurrentRow + 1 );
263  }
264  } );
265 
266  updateButtons();
267  validate();
268 }
269 
270 void QgsNewVectorTableDialog::setSchemaName( const QString &name )
271 {
272  mSchemaCbo->setCurrentText( name );
273 }
274 
275 void QgsNewVectorTableDialog::setTableName( const QString &name )
276 {
277  mTableName->setText( name );
278 }
279 
281 {
282  mGeomTypeCbo->setCurrentIndex( mGeomTypeCbo->findData( type ) );
283 }
284 
286 {
287  mCrs->setCrs( crs );
288 }
289 
291 {
292  return mCrs->crs( );
293 }
294 
296 {
297  return mTableName->text();
298 }
299 
301 {
302  return mSchemaCbo->currentText();
303 }
304 
306 {
307  return mGeomColumn->text();
308 }
309 
311 {
312  return mFieldModel ? mFieldModel->fields() : QgsFields();
313 }
314 
316 {
317  QgsWkbTypes::Type type { static_cast<QgsWkbTypes::Type>( mGeomTypeCbo->currentData( ).toInt() ) };
318  if ( mHasMChk->isChecked() )
319  {
320  type = QgsWkbTypes::addM( type );
321  }
322  if ( mHasZChk->isChecked() )
323  {
324  type = QgsWkbTypes::addZ( type );
325  }
326  return type;
327 }
328 
329 
331 {
332  if ( mFieldModel )
333  {
334  mFieldModel->setFields( fields );
335  }
336 }
337 
339 {
340  return mSpatialIndexChk->isChecked();
341 }
342 
344 {
345  return mValidationErrors;
346 }
347 
348 void QgsNewVectorTableDialog::updateButtons()
349 {
350  mDeleteFieldBtn->setEnabled( mCurrentRow != -1 );
351  mFieldUpBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != 0 );
352  mFieldDownBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != fields().count() - 1 );
353 }
354 
355 void QgsNewVectorTableDialog::selectRow( int row )
356 {
357  QModelIndex index { mFieldsTableView->model()->index( row, 0 ) };
358  mFieldsTableView->setCurrentIndex( index );
359  QItemSelectionModel::SelectionFlags flags { QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current };
360  mFieldsTableView->selectionModel()->select( index, flags );
361  mFieldsTableView->scrollTo( index );
362 }
363 
364 void QgsNewVectorTableDialog::validate()
365 {
366  mValidationErrors.clear();
367 
368  const bool isSpatial { mGeomTypeCbo->currentIndex() > 0 };
369  if ( mTableNames.contains( mTableName->text(), Qt::CaseSensitivity::CaseInsensitive ) )
370  {
371  mValidationErrors.push_back( tr( "Table <b>%1</b> already exists!" ).arg( mTableName->text() ) );
372  }
373  // Check for field names and geom col name
374  if ( isSpatial && fields().names().contains( mGeomColumn->text(), Qt::CaseSensitivity::CaseInsensitive ) )
375  {
376  mValidationErrors.push_back( tr( "Geometry column name <b>%1</b> cannot be equal to an existing field name!" ).arg( mGeomColumn->text() ) );
377  }
378  // No geometry and no fields? No party!
379  if ( ! isSpatial && fields().count() == 0 )
380  {
381  mValidationErrors.push_back( tr( "The table has no geometry column and no fields!" ) );
382  }
383  // Check if precision is <= length
384  const auto cFields { fields() };
385  for ( const auto &f : cFields )
386  {
387  if ( f.isNumeric() && f.length() >= 0 && f.precision() >= 0 && f.precision() > f.length() )
388  {
389  mValidationErrors.push_back( tr( "Field <b>%1</b>: precision cannot be greater than length!" ).arg( f.name() ) );
390  }
391  }
392 
393  const bool isValid { mValidationErrors.isEmpty() };
394  if ( ! isValid )
395  {
396  mValidationResults->setText( mValidationErrors.join( QLatin1String( "<br>" ) ) );
397  }
398 
399  mValidationFrame->setVisible( ! isValid );
400  mButtonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( isValid );
401 }
402 
403 void QgsNewVectorTableDialog::showEvent( QShowEvent *event )
404 {
405  QDialog::showEvent( event );
406  mTableName->setFocus();
407  mTableName->selectAll();
408 }
409 
410 
412 
413 
414 QgsNewVectorTableDialogFieldsDelegate::QgsNewVectorTableDialogFieldsDelegate( const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
415  : QStyledItemDelegate( parent )
416  , mTypeList( typeList )
417 {
418 
419 }
420 
421 QWidget *QgsNewVectorTableDialogFieldsDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
422 {
423  switch ( index.column() )
424  {
425  case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
426  {
427  QComboBox *cbo = new QComboBox { parent };
428  cbo->setEditable( false );
429  cbo->setFrame( false );
430  connect( cbo, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged );
431  for ( const auto &f : qgis::as_const( mTypeList ) )
432  {
433  cbo->addItem( f.mTypeDesc, f.mTypeName );
434  }
435  return cbo;
436  }
437  case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
438  {
439  QSpinBox *sp { new QSpinBox { parent } };
440  const QgsNewVectorTableFieldModel *model { static_cast<const QgsNewVectorTableFieldModel *>( index.model() )};
441  if ( model )
442  {
443  const QgsVectorDataProvider::NativeType nt { model->nativeType( index.row() ) };
444  sp->setRange( nt.mMinPrec, std::min<int>( nt.mMaxPrec, index.model()->data( index.model()->index( index.row(), index.column() - 1 ) ).toInt() ) );
445  }
446  return sp;
447  }
448  case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
449  {
450  QSpinBox *sp { new QSpinBox { parent } };
451  const QgsNewVectorTableFieldModel *model { static_cast<const QgsNewVectorTableFieldModel *>( index.model() )};
452  if ( model )
453  {
454  const QgsVectorDataProvider::NativeType nt { model->nativeType( index.row() ) };
455  sp->setRange( std::max<int>( nt.mMinLen, index.model()->data( index.model()->index( index.row(), index.column() + 1 ) ).toInt() ), nt.mMaxLen );
456  }
457  return sp;
458  }
459  default:
460  {
461  return QStyledItemDelegate::createEditor( parent, option, index );
462  }
463  }
464 }
465 
466 void QgsNewVectorTableDialogFieldsDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
467 {
468  const auto m { index.model() };
469  switch ( index.column() )
470  {
471  case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
472  {
473  const QString txt = m->data( index, Qt::DisplayRole ).toString();
474  QComboBox *cbo{ qobject_cast<QComboBox *>( editor ) };
475  if ( cbo )
476  {
477  cbo->setCurrentIndex( cbo->findText( txt ) );
478  }
479  break;
480  }
481  case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
482  case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
483  {
484  const int value = m->data( index, Qt::DisplayRole ).toInt();
485  QSpinBox *sp{ qobject_cast<QSpinBox *>( editor ) };
486  if ( sp )
487  {
488  sp->setValue( value );
489  }
490  break;
491  }
492  default:
493  {
494  QStyledItemDelegate::setEditorData( editor, index );
495  }
496  }
497 }
498 
499 void QgsNewVectorTableDialogFieldsDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
500 {
501  switch ( index.column() )
502  {
503  case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
504  {
505  QComboBox *cbo { qobject_cast<QComboBox *>( editor ) };
506  if ( cbo )
507  {
508  model->setData( index, cbo->currentData() );
509  }
510  break;
511  }
512  default:
513  {
514  QStyledItemDelegate::setModelData( editor, model, index );
515  }
516  }
517 }
518 
519 void QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged( int index )
520 {
521  Q_UNUSED( index )
522  QComboBox *cb = static_cast<QComboBox *>( sender() );
523  if ( cb )
524  {
525  emit commitData( cb );
526  }
527 }
528 
529 QgsNewVectorTableFieldModel::QgsNewVectorTableFieldModel( const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
530  : QgsFieldModel( parent )
531  , mNativeTypes( typeList )
532 {
533 
534 }
535 
536 int QgsNewVectorTableFieldModel::columnCount( const QModelIndex & ) const
537 {
538  return 6;
539 }
540 
541 QVariant QgsNewVectorTableFieldModel::data( const QModelIndex &index, int role ) const
542 {
543  if ( mFields.exists( index.row() ) )
544  {
545  const QgsField field { mFields.at( index.row() ) };
546  switch ( role )
547  {
548  case Qt::ItemDataRole::DisplayRole:
549  {
550  switch ( static_cast<ColumnHeaders>( index.column() ) )
551  {
552  case ColumnHeaders::Name:
553  {
554  return QgsFieldModel::data( index, role );
555  }
556  case ColumnHeaders::Type:
557  {
558  return typeDesc( field.typeName() );
559  }
560  case ColumnHeaders::ProviderType:
561  {
562  return field.typeName();
563  }
564  case ColumnHeaders::Comment:
565  {
566  return field.comment();
567  }
568  case ColumnHeaders::Precision:
569  {
570  return field.precision();
571  }
572  case ColumnHeaders::Length:
573  {
574  return field.length();
575  }
576  default:
577  break;
578  }
579  return QgsFieldModel::data( index, role );
580  }
581  case Qt::ItemDataRole::TextAlignmentRole:
582  {
583  switch ( static_cast<ColumnHeaders>( index.column() ) )
584  {
585  case ColumnHeaders::Precision:
586  case ColumnHeaders::Length:
587  {
588  return Qt::AlignmentFlag::AlignVCenter + Qt::AlignmentFlag::AlignHCenter;
589  }
590  default:
591  break;
592  }
593  return QgsFieldModel::data( index, role );
594  }
595  default:
596  {
597  if ( static_cast<ColumnHeaders>( index.column() ) == ColumnHeaders::Name )
598  {
599  return QgsFieldModel::data( index, role );
600  }
601  }
602  }
603  }
604  return QVariant();
605 }
606 
607 QVariant QgsNewVectorTableFieldModel::headerData( int section, Qt::Orientation orientation, int role ) const
608 {
609  if ( orientation == Qt::Orientation::Horizontal )
610  {
611  switch ( role )
612  {
613  case Qt::ItemDataRole::DisplayRole:
614  {
615  switch ( static_cast<ColumnHeaders>( section ) )
616  {
617  case ColumnHeaders::Name:
618  {
619  return tr( "Name" );
620  }
621  case ColumnHeaders::Type:
622  {
623  return tr( "Type" );
624  }
625  case ColumnHeaders::Comment:
626  {
627  return tr( "Comment" );
628  }
629  case ColumnHeaders::ProviderType:
630  {
631  return tr( "Provider type" );
632  }
633  case ColumnHeaders::Length:
634  {
635  return tr( "Length" );
636  }
637  case ColumnHeaders::Precision:
638  {
639  return tr( "Precision" );
640  }
641  default:
642  return QVariant();
643  }
644  break;
645  }
646  case Qt::ItemDataRole::TextAlignmentRole:
647  {
648  switch ( static_cast<ColumnHeaders>( section ) )
649  {
650  case ColumnHeaders::Name:
651  case ColumnHeaders::Comment:
652  case ColumnHeaders::Type:
653  case ColumnHeaders::ProviderType:
654  {
655  return Qt::AlignmentFlag::AlignVCenter + Qt::AlignmentFlag::AlignLeft;
656  }
657  default:
658  {
659  return Qt::AlignmentFlag::AlignVCenter + Qt::AlignmentFlag::AlignHCenter;
660  }
661  }
662  break;
663  }
664  default:
665  {
666  QgsFieldModel::headerData( section, orientation, role );
667  }
668  }
669  }
670  return QVariant();
671 }
672 
673 Qt::ItemFlags QgsNewVectorTableFieldModel::flags( const QModelIndex &index ) const
674 {
675  switch ( static_cast<ColumnHeaders>( index.column() ) )
676  {
677  case ColumnHeaders::Name:
678  case ColumnHeaders::Comment:
679  case ColumnHeaders::Type:
680  {
681  return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
682  }
683  case ColumnHeaders::Length:
684  {
685  if ( mFields.exists( index.row( ) ) )
686  {
687  const QgsVectorDataProvider::NativeType nt { nativeType( mFields.at( index.row( ) ).typeName() ) };
688  if ( nt.mMinLen < nt.mMaxLen )
689  {
690  return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
691  }
692  }
693  break;
694  }
695  case ColumnHeaders::Precision:
696  {
697  if ( mFields.exists( index.row( ) ) )
698  {
699  const QgsVectorDataProvider::NativeType nt { nativeType( mFields.at( index.row( ) ).typeName() ) };
700  if ( nt.mMinPrec < nt.mMaxPrec )
701  {
702  return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
703  }
704  }
705  break;
706  }
707  case ColumnHeaders::ProviderType:
708  {
709  return QgsFieldModel::flags( index );
710  }
711  }
712  return QgsFieldModel::flags( index );
713 }
714 
715 QList<QgsVectorDataProvider::NativeType> QgsNewVectorTableFieldModel::nativeTypes() const
716 {
717  return mNativeTypes;
718 }
719 
720 QString QgsNewVectorTableFieldModel::typeDesc( const QString &typeName ) const
721 {
722  for ( const auto &t : qgis::as_const( mNativeTypes ) )
723  {
724  if ( t.mTypeName.compare( typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
725  {
726  return t.mTypeDesc;
727  }
728  }
729  return typeName;
730 }
731 
732 QVariant::Type QgsNewVectorTableFieldModel::type( const QString &typeName ) const
733 {
734  return nativeType( typeName ).mType;
735 }
736 
737 QgsVectorDataProvider::NativeType QgsNewVectorTableFieldModel::nativeType( const QString &typeName ) const
738 {
739  for ( const auto &t : qgis::as_const( mNativeTypes ) )
740  {
741  if ( t.mTypeName.compare( typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
742  {
743  return t;
744  }
745  }
746  // This should never happen!
747  QgsDebugMsg( QStringLiteral( "Cannot get field native type for: %1" ).arg( typeName ) );
748  return mNativeTypes.first();
749 }
750 
751 QgsVectorDataProvider::NativeType QgsNewVectorTableFieldModel::nativeType( int row ) const
752 {
753  if ( mFields.exists( row ) )
754  {
755  return nativeType( mFields.at( row ).typeName() );
756  }
757  // This should never happen!
758  QgsDebugMsg( QStringLiteral( "Cannot get field for row: %1" ).arg( row ) );
759  return mNativeTypes.first();
760 }
761 
762 bool QgsNewVectorTableFieldModel::setData( const QModelIndex &index, const QVariant &value, int role )
763 {
764  if ( role == Qt::ItemDataRole::EditRole && mFields.exists( index.row() ) && index.column() < 6 )
765  {
766  const int fieldIdx { index.row() };
767  QgsField field {mFields.at( fieldIdx )};
768  switch ( static_cast<ColumnHeaders>( index.column() ) )
769  {
770  case ColumnHeaders::Name:
771  {
772  field.setName( value.toString() );
773  break;
774  }
775  case ColumnHeaders::Type:
776  {
777  field.setTypeName( value.toString() );
778  const auto tp { nativeType( value.toString() ) };
779  field.setType( tp.mType );
780  field.setLength( std::max( std::min<int>( field.length(), tp.mMaxLen ), tp.mMinLen ) );
781  field.setPrecision( std::max( std::min<int>( field.precision(), tp.mMaxPrec ), tp.mMinPrec ) );
782  break;
783  }
784  case ColumnHeaders::Comment:
785  {
786  field.setComment( value.toString() );
787  break;
788  }
789  case ColumnHeaders::ProviderType:
790  {
791  field.setTypeName( value.toString() );
792  break;
793  }
794  case ColumnHeaders::Length:
795  {
796  field.setLength( value.toInt() );
797  break;
798  }
799  case ColumnHeaders::Precision:
800  {
801  field.setPrecision( value.toInt() );
802  break;
803  }
804  }
805 
806  QgsFields fields;
807  for ( int i = 0; i < mFields.count(); ++i )
808  {
809  if ( i == fieldIdx )
810  {
811  fields.append( field );
812  }
813  else
814  {
815  fields.append( mFields.at( i ) );
816  }
817  }
818  setFields( fields );
819  }
820  return QgsFieldModel::setData( index, value, role );
821 }
822 
The QgsAbstractDatabaseProviderConnection class provides common functionality for DB based connection...
virtual GeometryColumnCapabilities geometryColumnCapabilities()
Returns connection geomerty column capabilities (Z, M, SinglePart, Curves)
virtual QList< QgsVectorDataProvider::NativeType > nativeTypes() const SIP_THROW(QgsProviderConnectionException)=0
Returns a list of native types supported by the connection.
virtual QStringList schemas() const SIP_THROW(QgsProviderConnectionException)
Returns information about the existing schemas.
virtual QList< QgsAbstractDatabaseProviderConnection::TableProperty > tables(const QString &schema=QString(), const QgsAbstractDatabaseProviderConnection::TableFlags &flags=QgsAbstractDatabaseProviderConnection::TableFlags()) const
Returns information on the tables in the given schema.
Capabilities capabilities() const
Returns connection capabilities.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
This class represents a coordinate reference system (CRS).
QString what() const
Definition: qgsexception.h:48
The QgsFieldModel class is a model to display the list of fields in widgets (optionally associated wi...
Definition: qgsfieldmodel.h:39
QVariant data(const QModelIndex &index, int role) const override
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:138
int precision
Definition: qgsfield.h:57
int length
Definition: qgsfield.h:56
void setPrecision(int precision)
Set the field precision.
Definition: qgsfield.cpp:198
void setName(const QString &name)
Set the field name.
Definition: qgsfield.cpp:174
void setComment(const QString &comment)
Set the field comment.
Definition: qgsfield.cpp:203
void setLength(int len)
Set the field length.
Definition: qgsfield.cpp:194
void setType(QVariant::Type type)
Set variant type.
Definition: qgsfield.cpp:179
QString comment
Definition: qgsfield.h:59
void setTypeName(const QString &typeName)
Set the field type.
Definition: qgsfield.cpp:189
Container of fields for a vector layer.
Definition: qgsfields.h:45
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
void remove(int fieldIdx)
Removes a field with the given index.
Definition: qgsfields.cpp:101
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:156
static QIcon iconForWkbType(QgsWkbTypes::Type type)
Returns the icon for a vector layer whose geometry type is provided.
Definition: qgsdataitem.cpp:57
QString schemaName() const
Returns the schema name.
bool createSpatialIndex()
Returns true if spatialindex checkbox is cheched.
QgsFields fields() const
Returns the fields.
QStringList validationErrors() const
Returns the validation errors or an empty list if the dialog is valid.
void setGeometryType(QgsWkbTypes::Type type)
Sets the geometry type.
void setFields(const QgsFields &fields)
Sets the fields to fields.
QgsCoordinateReferenceSystem crs() const
Returns the CRS.
QString tableName() const
Returns the table name.
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the CRS to crs.
QString geometryColumnName() const
Returns the geometry column name.
void setSchemaName(const QString &name)
Sets the schema name.
QgsWkbTypes::Type geometryType() const
Returns the geometry type.
QgsNewVectorTableDialog(QgsAbstractDatabaseProviderConnection *conn, QWidget *parent=nullptr)
QgsNewVectorTableDialog constructor.
void setTableName(const QString &name)
Sets the table name.
void showEvent(QShowEvent *event) override
Custom exception class for provider connection related exceptions.
Definition: qgsexception.h:101
static QString translatedDisplayString(Type type) SIP_HOLDGIL
Returns a translated display string type for a WKB type, e.g., the geometry name used in WKT geometry...
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1146
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1171
const QgsField & field
Definition: qgsfield.h:472
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
const QgsCoordinateReferenceSystem & crs
const QString & typeName