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