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