QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 "qgsvectorlayer.h"
18 #include "qgslogger.h"
19 #include "qgsgui.h"
20 #include "qgsapplication.h"
21 #include "qgsiconutils.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, this, [ = ] { 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, qOverload<int>( &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  mCrs->setShowAccuracyWarnings( true );
141 
142  // geometry types
143  const bool hasSinglePart { conn->geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::SinglePart ) };
144 
145  const auto addGeomItem = [this]( QgsWkbTypes::Type type )
146  {
147  mGeomTypeCbo->addItem( QgsIconUtils::iconForWkbType( type ), QgsWkbTypes::translatedDisplayString( type ), type );
148  };
149 
150  mGeomTypeCbo->addItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconTableLayer.svg" ) ), tr( "No Geometry" ), QgsWkbTypes::Type::NoGeometry );
151  if ( hasSinglePart )
152  addGeomItem( QgsWkbTypes::Type::Point );
153  addGeomItem( QgsWkbTypes::Type::MultiPoint );
154  if ( hasSinglePart )
155  addGeomItem( QgsWkbTypes::Type::LineString );
156  addGeomItem( QgsWkbTypes::Type::MultiLineString );
157  if ( hasSinglePart )
158  addGeomItem( QgsWkbTypes::Type::Polygon );
159  addGeomItem( QgsWkbTypes::Type::MultiPolygon );
160 
161  if ( conn->geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::Curves ) )
162  {
163  addGeomItem( QgsWkbTypes::Type::CompoundCurve );
164  addGeomItem( QgsWkbTypes::Type::CurvePolygon );
165  addGeomItem( QgsWkbTypes::Type::MultiCurve );
166  addGeomItem( QgsWkbTypes::Type::MultiSurface );
167  }
168 
169  mGeomTypeCbo->setCurrentIndex( 0 );
170 
171  const bool hasZ { conn->geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::Z ) };
172  const bool hasM { conn->geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::M ) };
173  if ( ! hasM )
174  {
175  mHasMChk->setEnabled( false );
176  mHasMChk->setChecked( false );
177  }
178  if ( ! hasZ )
179  {
180  mHasZChk->setEnabled( false );
181  mHasZChk->setChecked( false );
182  }
183  if ( ! hasM && ! hasM )
184  {
185  mHasZChk->setVisible( false );
186  mHasMChk->setVisible( false );
187  mDimensionsLabel->setVisible( false );
188  }
189 
190  connect( mFieldsTableView->selectionModel(), &QItemSelectionModel::selectionChanged, mFieldsTableView, [ = ]( const QItemSelection & selected, const QItemSelection & )
191  {
192  if ( ! selected.isEmpty() )
193  {
194  mCurrentRow = selected.indexes().first().row();
195  }
196  updateButtons();
197  } );
198 
199  // Get a default type for new fields
200  const QVariant::Type defaultFieldType { mFieldModel->nativeTypes().first().mType };
201  const QString defaultFieldTypeName { mFieldModel->nativeTypes().first().mTypeName };
202 
203  // Actions
204  connect( mAddFieldBtn, &QPushButton::clicked, this, [ = ]
205  {
206  QgsFields fieldList { fields() };
207  QgsField newField { QStringLiteral( "new_field_name" ), defaultFieldType, defaultFieldTypeName };
208  fieldList.append( newField );
209  setFields( fieldList );
210  selectRow( fieldList.count() - 1 );
211  } );
212 
213  connect( mDeleteFieldBtn, &QPushButton::clicked, this, [ = ]
214  {
215  QgsFields fieldList { fields() };
216  if ( fieldList.exists( mCurrentRow ) )
217  {
218  fieldList.remove( mCurrentRow );
219  setFields( fieldList );
220  mCurrentRow = -1;
221  }
222  } );
223 
224  connect( mFieldUpBtn, &QPushButton::clicked, this, [ = ]
225  {
226  if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow - 1 ) )
227  {
228  QgsFields fieldList;
229  for ( int i = 0; i < fields().count(); ++i )
230  {
231  if ( i == mCurrentRow - 1 )
232  {
233  fieldList.append( fields().at( mCurrentRow ) );
234  fieldList.append( fields().at( mCurrentRow - 1 ) );
235  }
236  else if ( i != mCurrentRow )
237  {
238  fieldList.append( fields().at( i ) );
239  }
240  }
241  setFields( fieldList );
242  selectRow( mCurrentRow - 1 );
243  }
244  } );
245 
246  connect( mFieldDownBtn, &QPushButton::clicked, this, [ = ]
247  {
248  if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow + 1 ) )
249  {
250  QgsFields fieldList;
251  for ( int i = 0; i < fields().count(); ++i )
252  {
253  if ( i == mCurrentRow )
254  {
255  fieldList.append( fields().at( mCurrentRow + 1 ) );
256  fieldList.append( fields().at( mCurrentRow ) );
257  }
258  else if ( i != mCurrentRow + 1 )
259  {
260  fieldList.append( fields().at( i ) );
261  }
262  }
263  setFields( fieldList );
264  selectRow( mCurrentRow + 1 );
265  }
266  } );
267 
268  updateButtons();
269  validate();
270 }
271 
272 void QgsNewVectorTableDialog::setSchemaName( const QString &name )
273 {
274  mSchemaCbo->setCurrentText( name );
275 }
276 
277 void QgsNewVectorTableDialog::setTableName( const QString &name )
278 {
279  mTableName->setText( name );
280 }
281 
283 {
284  mGeomTypeCbo->setCurrentIndex( mGeomTypeCbo->findData( type ) );
285 }
286 
288 {
289  mCrs->setCrs( crs );
290 }
291 
293 {
294  return mCrs->crs( );
295 }
296 
298 {
299  return mTableName->text();
300 }
301 
303 {
304  return mSchemaCbo->currentText();
305 }
306 
308 {
309  return mGeomColumn->text();
310 }
311 
313 {
314  return mFieldModel ? mFieldModel->fields() : QgsFields();
315 }
316 
318 {
319  QgsWkbTypes::Type type { static_cast<QgsWkbTypes::Type>( mGeomTypeCbo->currentData( ).toInt() ) };
320  if ( mHasMChk->isChecked() )
321  {
322  type = QgsWkbTypes::addM( type );
323  }
324  if ( mHasZChk->isChecked() )
325  {
326  type = QgsWkbTypes::addZ( type );
327  }
328  return type;
329 }
330 
331 
333 {
334  if ( mFieldModel )
335  {
336  mFieldModel->setFields( fields );
337  }
338 }
339 
341 {
342  return mSpatialIndexChk->isChecked();
343 }
344 
346 {
347  return mValidationErrors;
348 }
349 
350 void QgsNewVectorTableDialog::updateButtons()
351 {
352  mDeleteFieldBtn->setEnabled( mCurrentRow != -1 );
353  mFieldUpBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != 0 );
354  mFieldDownBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != fields().count() - 1 );
355 }
356 
357 void QgsNewVectorTableDialog::selectRow( int row )
358 {
359  QModelIndex index { mFieldsTableView->model()->index( row, 0 ) };
360  mFieldsTableView->setCurrentIndex( index );
361  QItemSelectionModel::SelectionFlags flags { QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current };
362  mFieldsTableView->selectionModel()->select( index, flags );
363  mFieldsTableView->scrollTo( index );
364 }
365 
366 void QgsNewVectorTableDialog::validate()
367 {
368  mValidationErrors.clear();
369 
370  const bool isSpatial { mGeomTypeCbo->currentIndex() > 0 };
371  if ( mTableNames.contains( mTableName->text(), Qt::CaseSensitivity::CaseInsensitive ) )
372  {
373  mValidationErrors.push_back( tr( "Table <b>%1</b> already exists!" ).arg( mTableName->text() ) );
374  }
375  // Check for field names and geom col name
376  if ( isSpatial && fields().names().contains( mGeomColumn->text(), Qt::CaseSensitivity::CaseInsensitive ) )
377  {
378  mValidationErrors.push_back( tr( "Geometry column name <b>%1</b> cannot be equal to an existing field name!" ).arg( mGeomColumn->text() ) );
379  }
380  // No geometry and no fields? No party!
381  if ( ! isSpatial && fields().count() == 0 )
382  {
383  mValidationErrors.push_back( tr( "The table has no geometry column and no fields!" ) );
384  }
385  // Check if precision is <= length
386  const auto cFields { fields() };
387  for ( const auto &f : cFields )
388  {
389  if ( f.isNumeric() && f.length() >= 0 && f.precision() >= 0 && f.precision() > f.length() )
390  {
391  mValidationErrors.push_back( tr( "Field <b>%1</b>: precision cannot be greater than length!" ).arg( f.name() ) );
392  }
393  }
394 
395  const bool isValid { mValidationErrors.isEmpty() };
396  if ( ! isValid )
397  {
398  mValidationResults->setText( mValidationErrors.join( QLatin1String( "<br>" ) ) );
399  }
400 
401  mValidationFrame->setVisible( ! isValid );
402  mButtonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( isValid );
403 }
404 
405 void QgsNewVectorTableDialog::showEvent( QShowEvent *event )
406 {
407  QDialog::showEvent( event );
408  mTableName->setFocus();
409  mTableName->selectAll();
410 }
411 
412 
414 
415 
416 QgsNewVectorTableDialogFieldsDelegate::QgsNewVectorTableDialogFieldsDelegate( const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
417  : QStyledItemDelegate( parent )
418  , mTypeList( typeList )
419 {
420 
421 }
422 
423 QWidget *QgsNewVectorTableDialogFieldsDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
424 {
425  switch ( index.column() )
426  {
427  case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
428  {
429  QComboBox *cbo = new QComboBox { parent };
430  cbo->setEditable( false );
431  cbo->setFrame( false );
432  connect( cbo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged );
433  for ( const auto &f : std::as_const( mTypeList ) )
434  {
435  cbo->addItem( f.mTypeDesc, f.mTypeName );
436  }
437  return cbo;
438  }
439  case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
440  {
441  QSpinBox *sp { new QSpinBox { parent } };
442  const QgsNewVectorTableFieldModel *model { static_cast<const QgsNewVectorTableFieldModel *>( index.model() )};
443  if ( model )
444  {
445  const QgsVectorDataProvider::NativeType nt { model->nativeType( index.row() ) };
446  sp->setRange( nt.mMinPrec, std::min<int>( nt.mMaxPrec, index.model()->data( index.model()->index( index.row(), index.column() - 1 ) ).toInt() ) );
447  }
448  return sp;
449  }
450  case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
451  {
452  QSpinBox *sp { new QSpinBox { parent } };
453  const QgsNewVectorTableFieldModel *model { static_cast<const QgsNewVectorTableFieldModel *>( index.model() )};
454  if ( model )
455  {
456  const QgsVectorDataProvider::NativeType nt { model->nativeType( index.row() ) };
457  sp->setRange( std::max<int>( nt.mMinLen, index.model()->data( index.model()->index( index.row(), index.column() + 1 ) ).toInt() ), nt.mMaxLen );
458  }
459  return sp;
460  }
461  default:
462  {
463  return QStyledItemDelegate::createEditor( parent, option, index );
464  }
465  }
466 }
467 
468 void QgsNewVectorTableDialogFieldsDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
469 {
470  const auto m { index.model() };
471  switch ( index.column() )
472  {
473  case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
474  {
475  const QString txt = m->data( index, Qt::DisplayRole ).toString();
476  QComboBox *cbo{ qobject_cast<QComboBox *>( editor ) };
477  if ( cbo )
478  {
479  cbo->setCurrentIndex( cbo->findText( txt ) );
480  }
481  break;
482  }
483  case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
484  case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
485  {
486  const int value = m->data( index, Qt::DisplayRole ).toInt();
487  QSpinBox *sp{ qobject_cast<QSpinBox *>( editor ) };
488  if ( sp )
489  {
490  sp->setValue( value );
491  }
492  break;
493  }
494  default:
495  {
496  QStyledItemDelegate::setEditorData( editor, index );
497  }
498  }
499 }
500 
501 void QgsNewVectorTableDialogFieldsDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
502 {
503  switch ( index.column() )
504  {
505  case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
506  {
507  QComboBox *cbo { qobject_cast<QComboBox *>( editor ) };
508  if ( cbo )
509  {
510  model->setData( index, cbo->currentData() );
511  }
512  break;
513  }
514  default:
515  {
516  QStyledItemDelegate::setModelData( editor, model, index );
517  }
518  }
519 }
520 
521 void QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged( int index )
522 {
523  Q_UNUSED( index )
524  QComboBox *cb = static_cast<QComboBox *>( sender() );
525  if ( cb )
526  {
527  emit commitData( cb );
528  }
529 }
530 
531 QgsNewVectorTableFieldModel::QgsNewVectorTableFieldModel( const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
532  : QgsFieldModel( parent )
533  , mNativeTypes( typeList )
534 {
535 
536 }
537 
538 int QgsNewVectorTableFieldModel::columnCount( const QModelIndex & ) const
539 {
540  return 6;
541 }
542 
543 QVariant QgsNewVectorTableFieldModel::data( const QModelIndex &index, int role ) const
544 {
545  if ( mFields.exists( index.row() ) )
546  {
547  const QgsField field { mFields.at( index.row() ) };
548  switch ( role )
549  {
550  case Qt::ItemDataRole::DisplayRole:
551  {
552  switch ( static_cast<ColumnHeaders>( index.column() ) )
553  {
554  case ColumnHeaders::Name:
555  {
556  return QgsFieldModel::data( index, role );
557  }
558  case ColumnHeaders::Type:
559  {
560  return typeDesc( field.typeName() );
561  }
562  case ColumnHeaders::ProviderType:
563  {
564  return field.typeName();
565  }
566  case ColumnHeaders::Comment:
567  {
568  return field.comment();
569  }
570  case ColumnHeaders::Precision:
571  {
572  return field.precision();
573  }
574  case ColumnHeaders::Length:
575  {
576  return field.length();
577  }
578  default:
579  break;
580  }
581  return QgsFieldModel::data( index, role );
582  }
583  case Qt::ItemDataRole::TextAlignmentRole:
584  {
585  switch ( static_cast<ColumnHeaders>( index.column() ) )
586  {
587  case ColumnHeaders::Precision:
588  case ColumnHeaders::Length:
589  {
590  return static_cast<Qt::Alignment::Int>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignHCenter );
591  }
592  default:
593  break;
594  }
595  return QgsFieldModel::data( index, role );
596  }
597  default:
598  {
599  if ( static_cast<ColumnHeaders>( index.column() ) == ColumnHeaders::Name )
600  {
601  return QgsFieldModel::data( index, role );
602  }
603  }
604  }
605  }
606  return QVariant();
607 }
608 
609 QVariant QgsNewVectorTableFieldModel::headerData( int section, Qt::Orientation orientation, int role ) const
610 {
611  if ( orientation == Qt::Orientation::Horizontal )
612  {
613  switch ( role )
614  {
615  case Qt::ItemDataRole::DisplayRole:
616  {
617  switch ( static_cast<ColumnHeaders>( section ) )
618  {
619  case ColumnHeaders::Name:
620  {
621  return tr( "Name" );
622  }
623  case ColumnHeaders::Type:
624  {
625  return tr( "Type" );
626  }
627  case ColumnHeaders::Comment:
628  {
629  return tr( "Comment" );
630  }
631  case ColumnHeaders::ProviderType:
632  {
633  return tr( "Provider type" );
634  }
635  case ColumnHeaders::Length:
636  {
637  return tr( "Length" );
638  }
639  case ColumnHeaders::Precision:
640  {
641  return tr( "Precision" );
642  }
643  default:
644  return QVariant();
645  }
646  break;
647  }
648  case Qt::ItemDataRole::TextAlignmentRole:
649  {
650  switch ( static_cast<ColumnHeaders>( section ) )
651  {
652  case ColumnHeaders::Name:
653  case ColumnHeaders::Comment:
654  case ColumnHeaders::Type:
655  case ColumnHeaders::ProviderType:
656  {
657  return static_cast<Qt::Alignment::Int>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignLeft );
658  }
659  default:
660  {
661  return static_cast<Qt::Alignment::Int>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignHCenter );
662  }
663  }
664  break;
665  }
666  default:
667  {
668  QgsFieldModel::headerData( section, orientation, role );
669  }
670  }
671  }
672  return QVariant();
673 }
674 
675 Qt::ItemFlags QgsNewVectorTableFieldModel::flags( const QModelIndex &index ) const
676 {
677  switch ( static_cast<ColumnHeaders>( index.column() ) )
678  {
679  case ColumnHeaders::Name:
680  case ColumnHeaders::Comment:
681  case ColumnHeaders::Type:
682  {
683  return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
684  }
685  case ColumnHeaders::Length:
686  {
687  if ( mFields.exists( index.row( ) ) )
688  {
689  const QgsVectorDataProvider::NativeType nt { nativeType( mFields.at( index.row( ) ).typeName() ) };
690  if ( nt.mMinLen < nt.mMaxLen )
691  {
692  return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
693  }
694  }
695  break;
696  }
697  case ColumnHeaders::Precision:
698  {
699  if ( mFields.exists( index.row( ) ) )
700  {
701  const QgsVectorDataProvider::NativeType nt { nativeType( mFields.at( index.row( ) ).typeName() ) };
702  if ( nt.mMinPrec < nt.mMaxPrec )
703  {
704  return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
705  }
706  }
707  break;
708  }
709  case ColumnHeaders::ProviderType:
710  {
711  return QgsFieldModel::flags( index );
712  }
713  }
714  return QgsFieldModel::flags( index );
715 }
716 
717 QList<QgsVectorDataProvider::NativeType> QgsNewVectorTableFieldModel::nativeTypes() const
718 {
719  return mNativeTypes;
720 }
721 
722 QString QgsNewVectorTableFieldModel::typeDesc( const QString &typeName ) const
723 {
724  for ( const auto &t : std::as_const( mNativeTypes ) )
725  {
726  if ( t.mTypeName.compare( typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
727  {
728  return t.mTypeDesc;
729  }
730  }
731  return typeName;
732 }
733 
734 QVariant::Type QgsNewVectorTableFieldModel::type( const QString &typeName ) const
735 {
736  return nativeType( typeName ).mType;
737 }
738 
739 QgsVectorDataProvider::NativeType QgsNewVectorTableFieldModel::nativeType( const QString &typeName ) const
740 {
741  for ( const auto &t : std::as_const( mNativeTypes ) )
742  {
743  if ( t.mTypeName.compare( typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
744  {
745  return t;
746  }
747  }
748  // This should never happen!
749  QgsDebugMsg( QStringLiteral( "Cannot get field native type for: %1" ).arg( typeName ) );
750  return mNativeTypes.first();
751 }
752 
753 QgsVectorDataProvider::NativeType QgsNewVectorTableFieldModel::nativeType( int row ) const
754 {
755  if ( mFields.exists( row ) )
756  {
757  return nativeType( mFields.at( row ).typeName() );
758  }
759  // This should never happen!
760  QgsDebugMsg( QStringLiteral( "Cannot get field for row: %1" ).arg( row ) );
761  return mNativeTypes.first();
762 }
763 
764 bool QgsNewVectorTableFieldModel::setData( const QModelIndex &index, const QVariant &value, int role )
765 {
766  if ( role == Qt::ItemDataRole::EditRole && mFields.exists( index.row() ) && index.column() < 6 )
767  {
768  const int fieldIdx { index.row() };
769  QgsField field {mFields.at( fieldIdx )};
770  switch ( static_cast<ColumnHeaders>( index.column() ) )
771  {
772  case ColumnHeaders::Name:
773  {
774  field.setName( value.toString() );
775  break;
776  }
777  case ColumnHeaders::Type:
778  {
779  field.setTypeName( value.toString() );
780  const auto tp { nativeType( value.toString() ) };
781  field.setType( tp.mType );
782  field.setLength( std::max( std::min<int>( field.length(), tp.mMaxLen ), tp.mMinLen ) );
783  field.setPrecision( std::max( std::min<int>( field.precision(), tp.mMaxPrec ), tp.mMinPrec ) );
784  break;
785  }
786  case ColumnHeaders::Comment:
787  {
788  field.setComment( value.toString() );
789  break;
790  }
791  case ColumnHeaders::ProviderType:
792  {
793  field.setTypeName( value.toString() );
794  break;
795  }
796  case ColumnHeaders::Length:
797  {
798  field.setLength( value.toInt() );
799  break;
800  }
801  case ColumnHeaders::Precision:
802  {
803  field.setPrecision( value.toInt() );
804  break;
805  }
806  }
807 
808  QgsFields fields;
809  for ( int i = 0; i < mFields.count(); ++i )
810  {
811  if ( i == fieldIdx )
812  {
813  fields.append( field );
814  }
815  else
816  {
817  fields.append( mFields.at( i ) );
818  }
819  }
820  setFields( fields );
821  }
822  return QgsFieldModel::setData( index, value, role );
823 }
824 
QgsNewVectorTableDialog::crs
QgsCoordinateReferenceSystem crs() const
Returns the CRS.
Definition: qgsnewvectortabledialog.cpp:292
QgsNewVectorTableDialog::setCrs
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the CRS to crs.
Definition: qgsnewvectortabledialog.cpp:287
QgsNewVectorTableDialog::tableName
QString tableName() const
Returns the table name.
Definition: qgsnewvectortabledialog.cpp:297
QgsNewVectorTableDialog::schemaName
QString schemaName() const
Returns the schema name.
Definition: qgsnewvectortabledialog.cpp:302
QgsField::length
int length
Definition: qgsfield.h:56
qgsgui.h
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:105
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:44
QgsWkbTypes::addZ
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1176
QgsNewVectorTableDialog::createSpatialIndex
bool createSpatialIndex()
Returns true if spatialindex checkbox is cheched.
Definition: qgsnewvectortabledialog.cpp:340
QgsFieldModel::data
QVariant data(const QModelIndex &index, int role) const override
Definition: qgsfieldmodel.cpp:273
QgsField::typeName
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:139
QgsWkbTypes::Type
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:69
QgsAbstractDatabaseProviderConnection::tables
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.
Definition: qgsabstractdatabaseproviderconnection.cpp:1182
field
const QgsField & field
Definition: qgsfield.h:463
QgsNewVectorTableDialog::fields
QgsFields fields() const
Returns the fields.
Definition: qgsnewvectortabledialog.cpp:312
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsFields::append
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
QgsVectorDataProvider::NativeType
Definition: qgsvectordataprovider.h:471
QgsNewVectorTableDialog::setTableName
void setTableName(const QString &name)
Sets the table name.
Definition: qgsnewvectortabledialog.cpp:277
qgsapplication.h
QgsAbstractDatabaseProviderConnection::geometryColumnCapabilities
virtual GeometryColumnCapabilities geometryColumnCapabilities()
Returns connection geometry column capabilities (Z, M, SinglePart, Curves).
Definition: qgsabstractdatabaseproviderconnection.cpp:41
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:180
QgsNewVectorTableDialog::setFields
void setFields(const QgsFields &fields)
Sets the fields to fields.
Definition: qgsnewvectortabledialog.cpp:332
QgsField::precision
int precision
Definition: qgsfield.h:57
QgsWkbTypes::addM
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1201
QgsField::setTypeName
void setTypeName(const QString &typeName)
Set the field type.
Definition: qgsfield.cpp:190
qgsnewvectortabledialog.h
QgsAbstractDatabaseProviderConnection::nativeTypes
virtual QList< QgsVectorDataProvider::NativeType > nativeTypes() const SIP_THROW(QgsProviderConnectionException)=0
Returns a list of native types supported by the connection.
QgsNewVectorTableDialog::setGeometryType
void setGeometryType(QgsWkbTypes::Type type)
Sets the geometry type.
Definition: qgsnewvectortabledialog.cpp:282
QgsException::what
QString what() const
Definition: qgsexception.h:48
QgsField::comment
QString comment
Definition: qgsfield.h:59
QgsField::setLength
void setLength(int len)
Set the field length.
Definition: qgsfield.cpp:195
typeName
const QString & typeName
Definition: qgswfsgetfeature.cpp:109
QgsProviderConnectionException
Custom exception class for provider connection related exceptions.
Definition: qgsexception.h:100
QgsNewVectorTableDialog::setSchemaName
void setSchemaName(const QString &name)
Sets the schema name.
Definition: qgsnewvectortabledialog.cpp:272
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:211
qgsvectorlayer.h
QgsNewVectorTableDialog::validationErrors
QStringList validationErrors() const
Returns the validation errors or an empty list if the dialog is valid.
Definition: qgsnewvectortabledialog.cpp:345
QgsWkbTypes::translatedDisplayString
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...
Definition: qgswkbtypes.cpp:155
QgsField::setPrecision
void setPrecision(int precision)
Set the field precision.
Definition: qgsfield.cpp:199
QgsIconUtils::iconForWkbType
static QIcon iconForWkbType(QgsWkbTypes::Type type)
Returns the icon for a vector layer whose geometry type is provided.
Definition: qgsiconutils.cpp:25
QgsNewVectorTableDialog::geometryType
QgsWkbTypes::Type geometryType() const
Returns the geometry type.
Definition: qgsnewvectortabledialog.cpp:317
qgsiconutils.h
QgsFieldModel
The QgsFieldModel class is a model to display the list of fields in widgets (optionally associated wi...
Definition: qgsfieldmodel.h:38
QgsField::setComment
void setComment(const QString &comment)
Set the field comment.
Definition: qgsfield.cpp:204
QgsField::setType
void setType(QVariant::Type type)
Set variant type.
Definition: qgsfield.cpp:180
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Definition: qgsapplication.cpp:693
QgsNewVectorTableDialog::geometryColumnName
QString geometryColumnName() const
Returns the geometry column name.
Definition: qgsnewvectortabledialog.cpp:307
qgslogger.h
QgsFields::remove
void remove(int fieldIdx)
Removes the field with the given index.
Definition: qgsfields.cpp:101
QgsAbstractDatabaseProviderConnection
The QgsAbstractDatabaseProviderConnection class provides common functionality for DB based connection...
Definition: qgsabstractdatabaseproviderconnection.h:44
QgsNewVectorTableDialog::showEvent
void showEvent(QShowEvent *event) override
Definition: qgsnewvectortabledialog.cpp:405
QgsAbstractDatabaseProviderConnection::schemas
virtual QStringList schemas() const SIP_THROW(QgsProviderConnectionException)
Returns information about the existing schemas.
Definition: qgsabstractdatabaseproviderconnection.cpp:1210
QgsField::setName
void setName(const QString &name)
Set the field name.
Definition: qgsfield.cpp:175
QgsNewVectorTableDialog::QgsNewVectorTableDialog
QgsNewVectorTableDialog(QgsAbstractDatabaseProviderConnection *conn, QWidget *parent=nullptr)
QgsNewVectorTableDialog constructor.
Definition: qgsnewvectortabledialog.cpp:26
QgsAbstractDatabaseProviderConnection::capabilities
Capabilities capabilities() const
Returns connection capabilities.
Definition: qgsabstractdatabaseproviderconnection.cpp:36
QgsField
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:50