QGIS API Documentation 3.99.0-Master (357b655ed83)
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
18#include "qgsapplication.h"
19#include "qgsgui.h"
20#include "qgsiconutils.h"
21#include "qgslogger.h"
22
23#include <QMessageBox>
24#include <QSpinBox>
25#include <QString>
26#include <QTimer>
27
28#include "moc_qgsnewvectortabledialog.cpp"
29
30using namespace Qt::StringLiterals;
31
33 : QDialog( parent )
34 , mConnection( conn )
35{
36 setupUi( this );
37
38 // This is a precondition for the dialog to work correctly
39 try
40 {
41 mFieldModel = new QgsNewVectorTableFieldModel( mConnection->nativeTypes(), this );
42 }
44 {
45 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"
46 "Error message: %1" )
47 .arg( ex.what() ) );
48 QTimer::singleShot( 0, this, [this] { reject(); } );
49 return;
50 }
51
52 Q_ASSERT( !mFieldModel->nativeTypes().isEmpty() );
53
55 setWindowTitle( tr( "New Table" ) );
56
57 auto updateTableNames = [this, conn]( const QString &schema = QString() ) {
58 mTableNames.clear();
59 try
60 {
61 const auto constTables { conn->tables( schema ) };
62 for ( const auto &tp : constTables )
63 {
64 mTableNames.push_back( tp.tableName() );
65 }
66 validate();
67 }
69 {
70 // This should never happen but it's not critical, we can safely continue.
71 QgsDebugError( u"Error retrieving tables from connection: %1"_s.arg( ex.what() ) );
72 }
73 };
74
75 // Validate on data changed
76 connect( mFieldModel, &QgsNewVectorTableFieldModel::modelReset, this, [this]() {
77 validate();
78 } );
79
80 mTableName->setText( u"new_table_name"_s );
81 mFieldsTableView->setModel( mFieldModel );
82 QgsNewVectorTableDialogFieldsDelegate *delegate { new QgsNewVectorTableDialogFieldsDelegate( mConnection->nativeTypes(), this ) };
83 mFieldsTableView->setItemDelegate( delegate );
84 mFieldsTableView->setSelectionBehavior( QAbstractItemView::SelectionBehavior::SelectRows );
85 mFieldsTableView->setSelectionMode( QAbstractItemView::SelectionMode::SingleSelection );
86 mFieldsTableView->setVerticalHeader( nullptr );
87
88 // Cosmetics
89 mFieldsTableView->horizontalHeader()->setStretchLastSection( true );
90 mFieldsTableView->setColumnWidth( QgsNewVectorTableFieldModel::ColumnHeaders::Type, 300 );
91
92 // Schema is not supported by all providers
93 if ( mConnection->capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::Schemas ) )
94 {
95 mSchemaCbo->addItems( mConnection->schemas() );
96 connect( mSchemaCbo, &QComboBox::currentTextChanged, this, [updateTableNames]( const QString &schema ) {
97 updateTableNames( schema );
98 } );
99 }
100 else
101 {
102 mSchemaCbo->hide();
103 mSchemaLabel->hide();
104 }
105
106 if ( !mConnection->capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::CreateSpatialIndex ) )
107 {
108 mSpatialIndexChk->setChecked( false );
109 mSpatialIndexChk->hide();
110 mSpatialIndexLabel->hide();
111 }
112
113 mIllegalFieldNames = mConnection->illegalFieldNames();
114
115 // Initial load of table names
116 updateTableNames( mSchemaCbo->currentText() );
117
118 // Validators
119 connect( mTableName, &QLineEdit::textChanged, this, [this]( const QString & ) {
120 validate();
121 } );
122
123 connect( mGeomColumn, &QLineEdit::textChanged, this, [this]( const QString & ) {
124 validate();
125 } );
126
127 // Enable/disable geometry options and call validate
128 connect( mGeomTypeCbo, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this]( int index ) {
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 mGeomTypeCbo->addItem( QgsIconUtils::iconForWkbType( type ), QgsWkbTypes::translatedDisplayString( type ), static_cast<quint32>( type ) );
151 };
152
153 mGeomTypeCbo->addItem( QgsApplication::getThemeIcon( u"mIconTableLayer.svg"_s ), 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 && !hasZ )
194 {
195 mHasZChk->setVisible( false );
196 mHasMChk->setVisible( false );
197 mDimensionsLabel->setVisible( false );
198 }
199
200 connect( mFieldsTableView->selectionModel(), &QItemSelectionModel::selectionChanged, mFieldsTableView, [this]( const QItemSelection &selected, const QItemSelection & ) {
201 if ( !selected.isEmpty() )
202 {
203 mCurrentRow = selected.indexes().first().row();
204 }
205 updateButtons();
206 } );
207
208 // Get a default type for new fields
209 const QMetaType::Type defaultFieldType { mFieldModel->nativeTypes().first().mType };
210 const QString defaultFieldTypeName { mFieldModel->nativeTypes().first().mTypeName };
211
212 // Actions
213 connect( mAddFieldBtn, &QPushButton::clicked, this, [this, defaultFieldType, defaultFieldTypeName] {
214 QgsFields fieldList { fields() };
215 QgsField newField { u"new_field_name"_s, defaultFieldType, defaultFieldTypeName };
216 fieldList.append( newField );
217 setFields( fieldList );
218 selectRow( fieldList.count() - 1 );
219 } );
220
221 connect( mDeleteFieldBtn, &QPushButton::clicked, this, [this] {
222 QgsFields fieldList { fields() };
223 if ( fieldList.exists( mCurrentRow ) )
224 {
225 fieldList.remove( mCurrentRow );
226 setFields( fieldList );
227 mCurrentRow = -1;
228 }
229 } );
230
231 connect( mFieldUpBtn, &QPushButton::clicked, this, [this] {
232 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow - 1 ) )
233 {
234 QgsFields fieldList;
235 for ( int i = 0; i < fields().count(); ++i )
236 {
237 if ( i == mCurrentRow - 1 )
238 {
239 fieldList.append( fields().at( mCurrentRow ) );
240 fieldList.append( fields().at( mCurrentRow - 1 ) );
241 }
242 else if ( i != mCurrentRow )
243 {
244 fieldList.append( fields().at( i ) );
245 }
246 }
247 setFields( fieldList );
248 selectRow( mCurrentRow - 1 );
249 }
250 } );
251
252 connect( mFieldDownBtn, &QPushButton::clicked, this, [this] {
253 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow + 1 ) )
254 {
255 QgsFields fieldList;
256 for ( int i = 0; i < fields().count(); ++i )
257 {
258 if ( i == mCurrentRow )
259 {
260 fieldList.append( fields().at( mCurrentRow + 1 ) );
261 fieldList.append( fields().at( mCurrentRow ) );
262 }
263 else if ( i != mCurrentRow + 1 )
264 {
265 fieldList.append( fields().at( i ) );
266 }
267 }
268 setFields( fieldList );
269 selectRow( mCurrentRow + 1 );
270 }
271 } );
272
273 updateButtons();
274 validate();
275}
276
277void QgsNewVectorTableDialog::setSchemaName( const QString &name )
278{
279 mSchemaCbo->setCurrentText( name );
280}
281
282void QgsNewVectorTableDialog::setTableName( const QString &name )
283{
284 mTableName->setText( name );
285}
286
288{
289 mGeomTypeCbo->setCurrentIndex( mGeomTypeCbo->findData( static_cast<quint32>( type ) ) );
290}
291
293{
294 mCrs->setCrs( crs );
295}
296
298{
299 return mCrs->crs();
300}
301
303{
304 return mTableName->text();
305}
306
308{
309 return mSchemaCbo->currentText();
310}
311
313{
314 return mGeomColumn->text();
315}
316
318{
319 return mFieldModel ? mFieldModel->fields() : QgsFields();
320}
321
323{
324 Qgis::WkbType type { static_cast<Qgis::WkbType>( mGeomTypeCbo->currentData().toInt() ) };
325 if ( mHasMChk->isChecked() )
326 {
327 type = QgsWkbTypes::addM( type );
328 }
329 if ( mHasZChk->isChecked() )
330 {
331 type = QgsWkbTypes::addZ( type );
332 }
333 return type;
334}
335
336
338{
339 if ( mFieldModel )
340 {
341 mFieldModel->setFields( fields );
342 }
343}
344
346{
347 return mSpatialIndexChk->isChecked();
348}
349
351{
352 return mValidationErrors;
353}
354
355void QgsNewVectorTableDialog::updateButtons()
356{
357 mDeleteFieldBtn->setEnabled( mCurrentRow != -1 );
358 mFieldUpBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != 0 );
359 mFieldDownBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != fields().count() - 1 );
360}
361
362void QgsNewVectorTableDialog::selectRow( int row )
363{
364 QModelIndex index { mFieldsTableView->model()->index( row, 0 ) };
365 mFieldsTableView->setCurrentIndex( index );
366 QItemSelectionModel::SelectionFlags flags { QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current };
367 mFieldsTableView->selectionModel()->select( index, flags );
368 mFieldsTableView->scrollTo( index );
369}
370
371void QgsNewVectorTableDialog::validate()
372{
373 mValidationErrors.clear();
374
375 const bool isSpatial { mGeomTypeCbo->currentIndex() > 0 };
376 if ( mTableName->text().trimmed().isEmpty() )
377 {
378 mValidationErrors.push_back( tr( "Table name cannot be empty" ) );
379 }
380 else if ( mTableNames.contains( mTableName->text(), Qt::CaseSensitivity::CaseInsensitive ) )
381 {
382 mValidationErrors.push_back( tr( "Table <b>%1</b> already exists" ).arg( mTableName->text() ) );
383 }
384 // Check for field names and geom col name
385 if ( isSpatial && fields().names().contains( mGeomColumn->text(), Qt::CaseSensitivity::CaseInsensitive ) )
386 {
387 mValidationErrors.push_back( tr( "Geometry column name <b>%1</b> cannot be equal to an existing field name" ).arg( mGeomColumn->text() ) );
388 }
389 // No geometry and no fields? No party!
390 if ( !isSpatial && fields().count() == 0 )
391 {
392 mValidationErrors.push_back( tr( "The table has no geometry column and no fields" ) );
393 }
394 // Check if precision is <= length
395 const QgsFields cFields { fields() };
396 for ( const QgsField &f : cFields )
397 {
398 if ( f.isNumeric() && f.length() >= 0 && f.precision() >= 0 && f.precision() > f.length() )
399 {
400 mValidationErrors.push_back( tr( "Field <b>%1</b>: precision cannot be greater than length" ).arg( f.name() ) );
401 }
402
403 if ( f.name().trimmed().isEmpty() )
404 {
405 mValidationErrors.push_back( tr( "Field name cannot be empty" ) );
406 }
407 else
408 {
409 for ( const QString &illegalName : std::as_const( mIllegalFieldNames ) )
410 {
411 if ( f.name().compare( illegalName, Qt::CaseInsensitive ) == 0 )
412 {
413 mValidationErrors.push_back( tr( "<b>%1</b> is an illegal field name for this format and cannot be used" ).arg( f.name() ) );
414 }
415 }
416 }
417 }
418
419 const bool isValid { mValidationErrors.isEmpty() };
420 if ( !isValid )
421 {
422 mValidationResults->setText( mValidationErrors.join( "<br>"_L1 ) );
423 }
424
425 mValidationFrame->setVisible( !isValid );
426 mButtonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( isValid );
427}
428
429void QgsNewVectorTableDialog::showEvent( QShowEvent *event )
430{
431 QDialog::showEvent( event );
432 mTableName->setFocus();
433 mTableName->selectAll();
434}
435
436
438
439
440QgsNewVectorTableDialogFieldsDelegate::QgsNewVectorTableDialogFieldsDelegate( const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
441 : QStyledItemDelegate( parent )
442 , mTypeList( typeList )
443{
444}
445
446QWidget *QgsNewVectorTableDialogFieldsDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
447{
448 switch ( index.column() )
449 {
450 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
451 {
452 QComboBox *cbo = new QComboBox { parent };
453 cbo->setEditable( false );
454 cbo->setFrame( false );
455 connect( cbo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged );
456 for ( const auto &f : std::as_const( mTypeList ) )
457 {
458 cbo->addItem( QgsFields::iconForFieldType( f.mType, f.mSubType ), f.mTypeDesc, f.mTypeName );
459 }
460 return cbo;
461 }
462 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
463 {
464 QSpinBox *sp { new QSpinBox { parent } };
465 const QgsNewVectorTableFieldModel *model { static_cast<const QgsNewVectorTableFieldModel *>( index.model() ) };
466 if ( model )
467 {
468 const QgsVectorDataProvider::NativeType nt { model->nativeType( index.row() ) };
469 sp->setRange( nt.mMinPrec, std::min<int>( nt.mMaxPrec, index.model()->data( index.model()->index( index.row(), index.column() - 1 ) ).toInt() ) );
470 }
471 return sp;
472 }
473 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
474 {
475 QSpinBox *sp { new QSpinBox { parent } };
476 const QgsNewVectorTableFieldModel *model { static_cast<const QgsNewVectorTableFieldModel *>( index.model() ) };
477 if ( model )
478 {
479 const QgsVectorDataProvider::NativeType nt { model->nativeType( index.row() ) };
480 sp->setRange( std::max<int>( nt.mMinLen, index.model()->data( index.model()->index( index.row(), index.column() + 1 ) ).toInt() ), nt.mMaxLen );
481 }
482 return sp;
483 }
484 default:
485 {
486 return QStyledItemDelegate::createEditor( parent, option, index );
487 }
488 }
489}
490
491void QgsNewVectorTableDialogFieldsDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
492{
493 const auto m { index.model() };
494 switch ( index.column() )
495 {
496 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
497 {
498 const QString txt = m->data( index, Qt::DisplayRole ).toString();
499 QComboBox *cbo { qobject_cast<QComboBox *>( editor ) };
500 if ( cbo )
501 {
502 cbo->setCurrentIndex( cbo->findText( txt ) );
503 }
504 break;
505 }
506 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
507 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
508 {
509 const int value = m->data( index, Qt::DisplayRole ).toInt();
510 QSpinBox *sp { qobject_cast<QSpinBox *>( editor ) };
511 if ( sp )
512 {
513 sp->setValue( value );
514 }
515 break;
516 }
517 default:
518 {
519 QStyledItemDelegate::setEditorData( editor, index );
520 }
521 }
522}
523
524void QgsNewVectorTableDialogFieldsDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
525{
526 switch ( index.column() )
527 {
528 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
529 {
530 QComboBox *cbo { qobject_cast<QComboBox *>( editor ) };
531 if ( cbo )
532 {
533 model->setData( index, cbo->currentData() );
534 }
535 break;
536 }
537 default:
538 {
539 QStyledItemDelegate::setModelData( editor, model, index );
540 }
541 }
542}
543
544void QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged( int index )
545{
546 Q_UNUSED( index )
547 QComboBox *cb = static_cast<QComboBox *>( sender() );
548 if ( cb )
549 {
550 emit commitData( cb );
551 }
552}
553
554QgsNewVectorTableFieldModel::QgsNewVectorTableFieldModel( const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
555 : QgsFieldModel( parent )
556 , mNativeTypes( typeList )
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
756QMetaType::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( u"Cannot get field native type for: %1"_s.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( u"Cannot get field for row: %1"_s.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:280
@ CompoundCurve
CompoundCurve.
Definition qgis.h:291
@ Point
Point.
Definition qgis.h:282
@ LineString
LineString.
Definition qgis.h:283
@ TIN
TIN.
Definition qgis.h:296
@ MultiPoint
MultiPoint.
Definition qgis.h:286
@ Polygon
Polygon.
Definition qgis.h:284
@ MultiPolygon
MultiPolygon.
Definition qgis.h:288
@ Triangle
Triangle.
Definition qgis.h:285
@ NoGeometry
No geometry.
Definition qgis.h:298
@ MultiLineString
MultiLineString.
Definition qgis.h:287
@ MultiCurve
MultiCurve.
Definition qgis.h:293
@ CurvePolygon
CurvePolygon.
Definition qgis.h:292
@ PolyhedralSurface
PolyhedralSurface.
Definition qgis.h:295
@ MultiSurface
MultiSurface.
Definition qgis.h:294
Provides common functionality for database based connections.
@ 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).
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Represents a coordinate reference system (CRS).
QString what() const
A model which displays the list of fields in widgets (optionally associated with a vector layer).
QVariant data(const QModelIndex &index, int role) const override
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:56
QString typeName() const
Gets the field type.
Definition qgsfield.cpp:167
int precision
Definition qgsfield.h:62
int length
Definition qgsfield.h:61
void setPrecision(int precision)
Set the field precision.
Definition qgsfield.cpp:267
void setName(const QString &name)
Set the field name.
Definition qgsfield.cpp:233
void setComment(const QString &comment)
Set the field comment.
Definition qgsfield.cpp:272
void setType(QMetaType::Type type)
Set variant type.
Definition qgsfield.cpp:238
void setLength(int len)
Set the field length.
Definition qgsfield.cpp:263
QString comment
Definition qgsfield.h:64
void setTypeName(const QString &typeName)
Set the field type.
Definition qgsfield.cpp:258
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:76
int count
Definition qgsfields.h:50
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.
Q_INVOKABLE bool exists(int i) const
Returns if a field index is valid.
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:224
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 Q_INVOKABLE 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:7486
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7485
#define QgsDebugError(str)
Definition qgslogger.h:59