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