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