QGIS API Documentation 3.41.0-Master (3440c17df1d)
Loading...
Searching...
No Matches
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 "moc_qgsnewvectortabledialog.cpp"
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 QgsDebugError( 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
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
104 {
105 mSpatialIndexChk->setChecked( false );
106 mSpatialIndexChk->hide();
107 mSpatialIndexLabel->hide();
108 }
109
110 mIllegalFieldNames = mConnection->illegalFieldNames();
111
112 // Initial load of table names
113 updateTableNames( mSchemaCbo->currentText() );
114
115 // Validators
116 connect( mTableName, &QLineEdit::textChanged, this, [ = ]( const QString & )
117 {
118 validate();
119 } );
120
121 connect( mGeomColumn, &QLineEdit::textChanged, this, [ = ]( const QString & )
122 {
123 validate();
124 } );
125
126 // Enable/disable geometry options and call validate
127 connect( mGeomTypeCbo, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int index )
128 {
129 const bool hasGeom { index != 0 };
130 mGeomColumn->setEnabled( hasGeom );
131 mGeomColumnLabel->setEnabled( hasGeom );
132 mSpatialIndexChk->setEnabled( hasGeom );
133 mSpatialIndexLabel->setEnabled( hasGeom );
134 mCrs->setEnabled( hasGeom );
135 mCrsLabel->setEnabled( hasGeom );
136 mDimensionsLabel->setEnabled( hasGeom );
137 mHasMChk->setEnabled( hasGeom );
138 mHasZChk->setEnabled( hasGeom );
139 validate();
140 } );
141
142 mCrs->setShowAccuracyWarnings( true );
143
144 // geometry types
148
149 const auto addGeomItem = [this]( Qgis::WkbType type )
150 {
151 mGeomTypeCbo->addItem( QgsIconUtils::iconForWkbType( type ), QgsWkbTypes::translatedDisplayString( type ), static_cast< quint32>( type ) );
152 };
153
154 mGeomTypeCbo->addItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconTableLayer.svg" ) ), tr( "No Geometry" ), static_cast< quint32>( Qgis::WkbType::NoGeometry ) );
156 addGeomItem( Qgis::WkbType::Point );
157 addGeomItem( Qgis::WkbType::MultiPoint );
159 addGeomItem( Qgis::WkbType::LineString );
160 addGeomItem( Qgis::WkbType::MultiLineString );
162 addGeomItem( Qgis::WkbType::Polygon );
163 addGeomItem( Qgis::WkbType::MultiPolygon );
164
166 {
167 addGeomItem( Qgis::WkbType::CompoundCurve );
168 addGeomItem( Qgis::WkbType::CurvePolygon );
169 addGeomItem( Qgis::WkbType::MultiCurve );
170 addGeomItem( Qgis::WkbType::MultiSurface );
171 }
172
174 {
175 addGeomItem( Qgis::WkbType::Triangle ); // Not exactly surfaces, but only PostGIS (and memory) supports these types
177 addGeomItem( Qgis::WkbType::TIN );
178 }
179
180 mGeomTypeCbo->setCurrentIndex( 0 );
181
184 if ( ! hasM )
185 {
186 mHasMChk->setEnabled( false );
187 mHasMChk->setChecked( false );
188 }
189 if ( ! hasZ )
190 {
191 mHasZChk->setEnabled( false );
192 mHasZChk->setChecked( false );
193 }
194 if ( ! hasM && ! hasZ )
195 {
196 mHasZChk->setVisible( false );
197 mHasMChk->setVisible( false );
198 mDimensionsLabel->setVisible( false );
199 }
200
201 connect( mFieldsTableView->selectionModel(), &QItemSelectionModel::selectionChanged, mFieldsTableView, [ = ]( const QItemSelection & selected, const QItemSelection & )
202 {
203 if ( ! selected.isEmpty() )
204 {
205 mCurrentRow = selected.indexes().first().row();
206 }
207 updateButtons();
208 } );
209
210 // Get a default type for new fields
211 const QMetaType::Type defaultFieldType { mFieldModel->nativeTypes().first().mType };
212 const QString defaultFieldTypeName { mFieldModel->nativeTypes().first().mTypeName };
213
214 // Actions
215 connect( mAddFieldBtn, &QPushButton::clicked, this, [ = ]
216 {
217 QgsFields fieldList { fields() };
218 QgsField newField { QStringLiteral( "new_field_name" ), defaultFieldType, defaultFieldTypeName };
219 fieldList.append( newField );
220 setFields( fieldList );
221 selectRow( fieldList.count() - 1 );
222 } );
223
224 connect( mDeleteFieldBtn, &QPushButton::clicked, this, [ = ]
225 {
226 QgsFields fieldList { fields() };
227 if ( fieldList.exists( mCurrentRow ) )
228 {
229 fieldList.remove( mCurrentRow );
230 setFields( fieldList );
231 mCurrentRow = -1;
232 }
233 } );
234
235 connect( mFieldUpBtn, &QPushButton::clicked, this, [ = ]
236 {
237 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow - 1 ) )
238 {
239 QgsFields fieldList;
240 for ( int i = 0; i < fields().count(); ++i )
241 {
242 if ( i == mCurrentRow - 1 )
243 {
244 fieldList.append( fields().at( mCurrentRow ) );
245 fieldList.append( fields().at( mCurrentRow - 1 ) );
246 }
247 else if ( i != mCurrentRow )
248 {
249 fieldList.append( fields().at( i ) );
250 }
251 }
252 setFields( fieldList );
253 selectRow( mCurrentRow - 1 );
254 }
255 } );
256
257 connect( mFieldDownBtn, &QPushButton::clicked, this, [ = ]
258 {
259 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow + 1 ) )
260 {
261 QgsFields fieldList;
262 for ( int i = 0; i < fields().count(); ++i )
263 {
264 if ( i == mCurrentRow )
265 {
266 fieldList.append( fields().at( mCurrentRow + 1 ) );
267 fieldList.append( fields().at( mCurrentRow ) );
268 }
269 else if ( i != mCurrentRow + 1 )
270 {
271 fieldList.append( fields().at( i ) );
272 }
273 }
274 setFields( fieldList );
275 selectRow( mCurrentRow + 1 );
276 }
277 } );
278
279 updateButtons();
280 validate();
281}
282
283void QgsNewVectorTableDialog::setSchemaName( const QString &name )
284{
285 mSchemaCbo->setCurrentText( name );
286}
287
288void QgsNewVectorTableDialog::setTableName( const QString &name )
289{
290 mTableName->setText( name );
291}
292
294{
295 mGeomTypeCbo->setCurrentIndex( mGeomTypeCbo->findData( static_cast< quint32>( type ) ) );
296}
297
299{
300 mCrs->setCrs( crs );
301}
302
304{
305 return mCrs->crs( );
306}
307
309{
310 return mTableName->text();
311}
312
314{
315 return mSchemaCbo->currentText();
316}
317
319{
320 return mGeomColumn->text();
321}
322
324{
325 return mFieldModel ? mFieldModel->fields() : QgsFields();
326}
327
329{
330 Qgis::WkbType type { static_cast<Qgis::WkbType>( mGeomTypeCbo->currentData( ).toInt() ) };
331 if ( mHasMChk->isChecked() )
332 {
333 type = QgsWkbTypes::addM( type );
334 }
335 if ( mHasZChk->isChecked() )
336 {
337 type = QgsWkbTypes::addZ( type );
338 }
339 return type;
340}
341
342
344{
345 if ( mFieldModel )
346 {
347 mFieldModel->setFields( fields );
348 }
349}
350
352{
353 return mSpatialIndexChk->isChecked();
354}
355
357{
358 return mValidationErrors;
359}
360
361void QgsNewVectorTableDialog::updateButtons()
362{
363 mDeleteFieldBtn->setEnabled( mCurrentRow != -1 );
364 mFieldUpBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != 0 );
365 mFieldDownBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != fields().count() - 1 );
366}
367
368void QgsNewVectorTableDialog::selectRow( int row )
369{
370 QModelIndex index { mFieldsTableView->model()->index( row, 0 ) };
371 mFieldsTableView->setCurrentIndex( index );
372 QItemSelectionModel::SelectionFlags flags { QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current };
373 mFieldsTableView->selectionModel()->select( index, flags );
374 mFieldsTableView->scrollTo( index );
375}
376
377void QgsNewVectorTableDialog::validate()
378{
379 mValidationErrors.clear();
380
381 const bool isSpatial { mGeomTypeCbo->currentIndex() > 0 };
382 if ( mTableName->text().trimmed().isEmpty() )
383 {
384 mValidationErrors.push_back( tr( "Table name cannot be empty" ) );
385 }
386 else if ( mTableNames.contains( mTableName->text(), Qt::CaseSensitivity::CaseInsensitive ) )
387 {
388 mValidationErrors.push_back( tr( "Table <b>%1</b> already exists" ).arg( mTableName->text() ) );
389 }
390 // Check for field names and geom col name
391 if ( isSpatial && fields().names().contains( mGeomColumn->text(), Qt::CaseSensitivity::CaseInsensitive ) )
392 {
393 mValidationErrors.push_back( tr( "Geometry column name <b>%1</b> cannot be equal to an existing field name" ).arg( mGeomColumn->text() ) );
394 }
395 // No geometry and no fields? No party!
396 if ( ! isSpatial && fields().count() == 0 )
397 {
398 mValidationErrors.push_back( tr( "The table has no geometry column and no fields" ) );
399 }
400 // Check if precision is <= length
401 const QgsFields cFields { fields() };
402 for ( const QgsField &f : cFields )
403 {
404 if ( f.isNumeric() && f.length() >= 0 && f.precision() >= 0 && f.precision() > f.length() )
405 {
406 mValidationErrors.push_back( tr( "Field <b>%1</b>: precision cannot be greater than length" ).arg( f.name() ) );
407 }
408
409 if ( f.name().trimmed().isEmpty() )
410 {
411 mValidationErrors.push_back( tr( "Field name cannot be empty" ) );
412 }
413 else
414 {
415 for ( const QString &illegalName : std::as_const( mIllegalFieldNames ) )
416 {
417 if ( f.name().compare( illegalName, Qt::CaseInsensitive ) == 0 )
418 {
419 mValidationErrors.push_back( tr( "<b>%1</b> is an illegal field name for this format and cannot be used" ).arg( f.name() ) );
420 }
421 }
422 }
423 }
424
425 const bool isValid { mValidationErrors.isEmpty() };
426 if ( ! isValid )
427 {
428 mValidationResults->setText( mValidationErrors.join( QLatin1String( "<br>" ) ) );
429 }
430
431 mValidationFrame->setVisible( ! isValid );
432 mButtonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( isValid );
433}
434
435void QgsNewVectorTableDialog::showEvent( QShowEvent *event )
436{
437 QDialog::showEvent( event );
438 mTableName->setFocus();
439 mTableName->selectAll();
440}
441
442
444
445
446QgsNewVectorTableDialogFieldsDelegate::QgsNewVectorTableDialogFieldsDelegate( const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
447 : QStyledItemDelegate( parent )
448 , mTypeList( typeList )
449{
450
451}
452
453QWidget *QgsNewVectorTableDialogFieldsDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
454{
455 switch ( index.column() )
456 {
457 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
458 {
459 QComboBox *cbo = new QComboBox { parent };
460 cbo->setEditable( false );
461 cbo->setFrame( false );
462 connect( cbo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged );
463 for ( const auto &f : std::as_const( mTypeList ) )
464 {
465 cbo->addItem( QgsFields::iconForFieldType( f.mType, f.mSubType ), f.mTypeDesc, f.mTypeName );
466 }
467 return cbo;
468 }
469 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
470 {
471 QSpinBox *sp { new QSpinBox { parent } };
472 const QgsNewVectorTableFieldModel *model { static_cast<const QgsNewVectorTableFieldModel *>( index.model() )};
473 if ( model )
474 {
475 const QgsVectorDataProvider::NativeType nt { model->nativeType( index.row() ) };
476 sp->setRange( nt.mMinPrec, std::min<int>( nt.mMaxPrec, index.model()->data( index.model()->index( index.row(), index.column() - 1 ) ).toInt() ) );
477 }
478 return sp;
479 }
480 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
481 {
482 QSpinBox *sp { new QSpinBox { parent } };
483 const QgsNewVectorTableFieldModel *model { static_cast<const QgsNewVectorTableFieldModel *>( index.model() )};
484 if ( model )
485 {
486 const QgsVectorDataProvider::NativeType nt { model->nativeType( index.row() ) };
487 sp->setRange( std::max<int>( nt.mMinLen, index.model()->data( index.model()->index( index.row(), index.column() + 1 ) ).toInt() ), nt.mMaxLen );
488 }
489 return sp;
490 }
491 default:
492 {
493 return QStyledItemDelegate::createEditor( parent, option, index );
494 }
495 }
496}
497
498void QgsNewVectorTableDialogFieldsDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
499{
500 const auto m { index.model() };
501 switch ( index.column() )
502 {
503 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
504 {
505 const QString txt = m->data( index, Qt::DisplayRole ).toString();
506 QComboBox *cbo{ qobject_cast<QComboBox *>( editor ) };
507 if ( cbo )
508 {
509 cbo->setCurrentIndex( cbo->findText( txt ) );
510 }
511 break;
512 }
513 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
514 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
515 {
516 const int value = m->data( index, Qt::DisplayRole ).toInt();
517 QSpinBox *sp{ qobject_cast<QSpinBox *>( editor ) };
518 if ( sp )
519 {
520 sp->setValue( value );
521 }
522 break;
523 }
524 default:
525 {
526 QStyledItemDelegate::setEditorData( editor, index );
527 }
528 }
529}
530
531void QgsNewVectorTableDialogFieldsDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
532{
533 switch ( index.column() )
534 {
535 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
536 {
537 QComboBox *cbo { qobject_cast<QComboBox *>( editor ) };
538 if ( cbo )
539 {
540 model->setData( index, cbo->currentData() );
541 }
542 break;
543 }
544 default:
545 {
546 QStyledItemDelegate::setModelData( editor, model, index );
547 }
548 }
549}
550
551void QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged( int index )
552{
553 Q_UNUSED( index )
554 QComboBox *cb = static_cast<QComboBox *>( sender() );
555 if ( cb )
556 {
557 emit commitData( cb );
558 }
559}
560
561QgsNewVectorTableFieldModel::QgsNewVectorTableFieldModel( const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
562 : QgsFieldModel( parent )
563 , mNativeTypes( typeList )
564{
565
566}
567
568int QgsNewVectorTableFieldModel::columnCount( const QModelIndex & ) const
569{
570 return 6;
571}
572
573QVariant QgsNewVectorTableFieldModel::data( const QModelIndex &index, int role ) const
574{
575 if ( mFields.exists( index.row() ) )
576 {
577 const QgsField field { mFields.at( index.row() ) };
578 switch ( role )
579 {
580 case Qt::ItemDataRole::DisplayRole:
581 {
582 switch ( static_cast<ColumnHeaders>( index.column() ) )
583 {
584 case ColumnHeaders::Name:
585 {
586 return QgsFieldModel::data( index, role );
587 }
588 case ColumnHeaders::Type:
589 {
590 return typeDesc( field.typeName() );
591 }
592 case ColumnHeaders::ProviderType:
593 {
594 return field.typeName();
595 }
596 case ColumnHeaders::Comment:
597 {
598 return field.comment();
599 }
600 case ColumnHeaders::Precision:
601 {
602 return field.precision();
603 }
604 case ColumnHeaders::Length:
605 {
606 return field.length();
607 }
608 default:
609 break;
610 }
611 return QgsFieldModel::data( index, role );
612 }
613 case Qt::ItemDataRole::TextAlignmentRole:
614 {
615 switch ( static_cast<ColumnHeaders>( index.column() ) )
616 {
617 case ColumnHeaders::Precision:
618 case ColumnHeaders::Length:
619 {
620 return static_cast<Qt::Alignment::Int>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignHCenter );
621 }
622 default:
623 break;
624 }
625 return QgsFieldModel::data( index, role );
626 }
627 default:
628 {
629 if ( static_cast<ColumnHeaders>( index.column() ) == ColumnHeaders::Name )
630 {
631 return QgsFieldModel::data( index, role );
632 }
633 }
634 }
635 }
636 return QVariant();
637}
638
639QVariant QgsNewVectorTableFieldModel::headerData( int section, Qt::Orientation orientation, int role ) const
640{
641 if ( orientation == Qt::Orientation::Horizontal )
642 {
643 switch ( role )
644 {
645 case Qt::ItemDataRole::DisplayRole:
646 {
647 switch ( static_cast<ColumnHeaders>( section ) )
648 {
649 case ColumnHeaders::Name:
650 {
651 return tr( "Name" );
652 }
653 case ColumnHeaders::Type:
654 {
655 return tr( "Type" );
656 }
657 case ColumnHeaders::Comment:
658 {
659 return tr( "Comment" );
660 }
661 case ColumnHeaders::ProviderType:
662 {
663 return tr( "Provider type" );
664 }
665 case ColumnHeaders::Length:
666 {
667 return tr( "Length" );
668 }
669 case ColumnHeaders::Precision:
670 {
671 return tr( "Precision" );
672 }
673 default:
674 return QVariant();
675 }
676 break;
677 }
678 case Qt::ItemDataRole::TextAlignmentRole:
679 {
680 switch ( static_cast<ColumnHeaders>( section ) )
681 {
682 case ColumnHeaders::Name:
683 case ColumnHeaders::Comment:
684 case ColumnHeaders::Type:
685 case ColumnHeaders::ProviderType:
686 {
687 return static_cast<Qt::Alignment::Int>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignLeft );
688 }
689 default:
690 {
691 return static_cast<Qt::Alignment::Int>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignHCenter );
692 }
693 }
694 break;
695 }
696 default:
697 {
698 QgsFieldModel::headerData( section, orientation, role );
699 }
700 }
701 }
702 return QVariant();
703}
704
705Qt::ItemFlags QgsNewVectorTableFieldModel::flags( const QModelIndex &index ) const
706{
707 switch ( static_cast<ColumnHeaders>( index.column() ) )
708 {
709 case ColumnHeaders::Name:
710 case ColumnHeaders::Comment:
711 case ColumnHeaders::Type:
712 {
713 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
714 }
715 case ColumnHeaders::Length:
716 {
717 if ( mFields.exists( index.row( ) ) )
718 {
719 const QgsVectorDataProvider::NativeType nt { nativeType( mFields.at( index.row( ) ).typeName() ) };
720 if ( nt.mMinLen < nt.mMaxLen )
721 {
722 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
723 }
724 }
725 break;
726 }
727 case ColumnHeaders::Precision:
728 {
729 if ( mFields.exists( index.row( ) ) )
730 {
731 const QgsVectorDataProvider::NativeType nt { nativeType( mFields.at( index.row( ) ).typeName() ) };
732 if ( nt.mMinPrec < nt.mMaxPrec )
733 {
734 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
735 }
736 }
737 break;
738 }
739 case ColumnHeaders::ProviderType:
740 {
741 return QgsFieldModel::flags( index );
742 }
743 }
744 return QgsFieldModel::flags( index );
745}
746
747QList<QgsVectorDataProvider::NativeType> QgsNewVectorTableFieldModel::nativeTypes() const
748{
749 return mNativeTypes;
750}
751
752QString QgsNewVectorTableFieldModel::typeDesc( const QString &typeName ) const
753{
754 for ( const auto &t : std::as_const( mNativeTypes ) )
755 {
756 if ( t.mTypeName.compare( typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
757 {
758 return t.mTypeDesc;
759 }
760 }
761 return typeName;
762}
763
764QMetaType::Type QgsNewVectorTableFieldModel::type( const QString &typeName ) const
765{
766 return nativeType( typeName ).mType;
767}
768
769QgsVectorDataProvider::NativeType QgsNewVectorTableFieldModel::nativeType( const QString &typeName ) const
770{
771 for ( const auto &t : std::as_const( mNativeTypes ) )
772 {
773 if ( t.mTypeName.compare( typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
774 {
775 return t;
776 }
777 }
778 // This should never happen!
779 QgsDebugError( QStringLiteral( "Cannot get field native type for: %1" ).arg( typeName ) );
780 return mNativeTypes.first();
781}
782
783QgsVectorDataProvider::NativeType QgsNewVectorTableFieldModel::nativeType( int row ) const
784{
785 if ( mFields.exists( row ) )
786 {
787 return nativeType( mFields.at( row ).typeName() );
788 }
789 // This should never happen!
790 QgsDebugError( QStringLiteral( "Cannot get field for row: %1" ).arg( row ) );
791 return mNativeTypes.first();
792}
793
794bool QgsNewVectorTableFieldModel::setData( const QModelIndex &index, const QVariant &value, int role )
795{
796 if ( role == Qt::ItemDataRole::EditRole && mFields.exists( index.row() ) && index.column() < 6 )
797 {
798 const int fieldIdx { index.row() };
799 QgsField field {mFields.at( fieldIdx )};
800 switch ( static_cast<ColumnHeaders>( index.column() ) )
801 {
802 case ColumnHeaders::Name:
803 {
804 field.setName( value.toString() );
805 break;
806 }
807 case ColumnHeaders::Type:
808 {
809 field.setTypeName( value.toString() );
810 const auto tp { nativeType( value.toString() ) };
811 field.setType( tp.mType );
812 field.setLength( std::max( std::min<int>( field.length(), tp.mMaxLen ), tp.mMinLen ) );
813 field.setPrecision( std::max( std::min<int>( field.precision(), tp.mMaxPrec ), tp.mMinPrec ) );
814 break;
815 }
816 case ColumnHeaders::Comment:
817 {
818 field.setComment( value.toString() );
819 break;
820 }
821 case ColumnHeaders::ProviderType:
822 {
823 field.setTypeName( value.toString() );
824 break;
825 }
826 case ColumnHeaders::Length:
827 {
828 field.setLength( value.toInt() );
829 break;
830 }
831 case ColumnHeaders::Precision:
832 {
833 field.setPrecision( value.toInt() );
834 break;
835 }
836 }
837
838 QgsFields fields;
839 for ( int i = 0; i < mFields.count(); ++i )
840 {
841 if ( i == fieldIdx )
842 {
843 fields.append( field );
844 }
845 else
846 {
847 fields.append( mFields.at( i ) );
848 }
849 }
850 setFields( fields );
851 }
852 return QgsFieldModel::setData( index, value, role );
853}
854
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:256
@ CompoundCurve
CompoundCurve.
@ LineString
LineString.
@ MultiPoint
MultiPoint.
@ Polygon
Polygon.
@ MultiPolygon
MultiPolygon.
@ Triangle
Triangle.
@ NoGeometry
No geometry.
@ MultiLineString
MultiLineString.
@ MultiCurve
MultiCurve.
@ CurvePolygon
CurvePolygon.
@ PolyhedralSurface
PolyhedralSurface.
@ MultiSurface
MultiSurface.
The QgsAbstractDatabaseProviderConnection class provides common functionality for DB based connection...
@ PolyhedralSurfaces
Supports polyhedral surfaces (PolyhedralSurface, TIN) types (as distinct from multi polygon types)
@ SinglePart
Multi and single part types are distinct types. Deprecated since QGIS 3.28 – use the granular SingleP...
@ SinglePolygon
Supports single polygon types (as distinct from multi polygon types)
@ SinglePoint
Supports single point types (as distinct from multi point types)
@ SingleLineString
Supports single linestring types (as distinct from multi line types)
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.
@ CreateSpatialIndex
The connection can create spatial indices.
@ Schemas
Can list schemas (if not set, the connection does not support schemas)
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
The QgsFieldModel class is a model to display the list of fields in widgets (optionally associated wi...
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:227
Container of fields for a vector layer.
Definition qgsfields.h:46
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:70
void remove(int fieldIdx)
Removes the field with the given index.
static QIcon iconForFieldType(QMetaType::Type type, QMetaType::Type subType=QMetaType::Type::UnknownType, const QString &typeString=QString())
Returns an icon corresponding to a field type.
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:209
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.
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.
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:6535
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:6534
#define QgsDebugError(str)
Definition qgslogger.h:38
const QgsCoordinateReferenceSystem & crs
const QString & typeName