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