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