QGIS API Documentation 3.41.0-Master (57ec4277f5e)
Loading...
Searching...
No Matches
qgsnewvectortabledialog.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsnewvectortabledialog.cpp - QgsNewVectorTableDialog
3
4 ---------------------
5 begin : 12.7.2020
6 copyright : (C) 2020 by Alessandro Pasotti
7 email : elpaso at itopen dot it
8 ***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
17#include "moc_qgsnewvectortabledialog.cpp"
18#include "qgslogger.h"
19#include "qgsgui.h"
20#include "qgsapplication.h"
21#include "qgsiconutils.h"
22#include <QSpinBox>
23#include <QMessageBox>
24#include <QTimer>
25
27 : QDialog( parent )
28 , mConnection( conn )
29{
30 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" )
41 .arg( ex.what() ) );
42 QTimer::singleShot( 0, this, [=] { reject(); } );
43 return;
44 }
45
46 Q_ASSERT( !mFieldModel->nativeTypes().isEmpty() );
47
49 setWindowTitle( tr( "New Table" ) );
50
51 auto updateTableNames = [=]( const QString &schema = QString() ) {
52 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 validate();
72 } );
73
74 mTableName->setText( QStringLiteral( "new_table_name" ) );
75 mFieldsTableView->setModel( mFieldModel );
76 QgsNewVectorTableDialogFieldsDelegate *delegate { new QgsNewVectorTableDialogFieldsDelegate( mConnection->nativeTypes(), this ) };
77 mFieldsTableView->setItemDelegate( delegate );
78 mFieldsTableView->setSelectionBehavior( QAbstractItemView::SelectionBehavior::SelectRows );
79 mFieldsTableView->setSelectionMode( QAbstractItemView::SelectionMode::SingleSelection );
80 mFieldsTableView->setVerticalHeader( nullptr );
81
82 // Cosmetics
83 mFieldsTableView->horizontalHeader()->setStretchLastSection( true );
84 mFieldsTableView->setColumnWidth( QgsNewVectorTableFieldModel::ColumnHeaders::Type, 300 );
85
86 // Schema is not supported by all providers
88 {
89 mSchemaCbo->addItems( mConnection->schemas() );
90 connect( mSchemaCbo, &QComboBox::currentTextChanged, this, [=]( const QString &schema ) {
91 updateTableNames( schema );
92 } );
93 }
94 else
95 {
96 mSchemaCbo->hide();
97 mSchemaLabel->hide();
98 }
99
101 {
102 mSpatialIndexChk->setChecked( false );
103 mSpatialIndexChk->hide();
104 mSpatialIndexLabel->hide();
105 }
106
107 mIllegalFieldNames = mConnection->illegalFieldNames();
108
109 // Initial load of table names
110 updateTableNames( mSchemaCbo->currentText() );
111
112 // Validators
113 connect( mTableName, &QLineEdit::textChanged, this, [=]( const QString & ) {
114 validate();
115 } );
116
117 connect( mGeomColumn, &QLineEdit::textChanged, this, [=]( const QString & ) {
118 validate();
119 } );
120
121 // Enable/disable geometry options and call validate
122 connect( mGeomTypeCbo, qOverload<int>( &QComboBox::currentIndexChanged ), this, [=]( int index ) {
123 const bool hasGeom { index != 0 };
124 mGeomColumn->setEnabled( hasGeom );
125 mGeomColumnLabel->setEnabled( hasGeom );
126 mSpatialIndexChk->setEnabled( hasGeom );
127 mSpatialIndexLabel->setEnabled( hasGeom );
128 mCrs->setEnabled( hasGeom );
129 mCrsLabel->setEnabled( hasGeom );
130 mDimensionsLabel->setEnabled( hasGeom );
131 mHasMChk->setEnabled( hasGeom );
132 mHasZChk->setEnabled( hasGeom );
133 validate();
134 } );
135
136 mCrs->setShowAccuracyWarnings( true );
137
138 // geometry types
142
143 const auto addGeomItem = [this]( Qgis::WkbType type ) {
144 mGeomTypeCbo->addItem( QgsIconUtils::iconForWkbType( type ), QgsWkbTypes::translatedDisplayString( type ), static_cast<quint32>( type ) );
145 };
146
147 mGeomTypeCbo->addItem( QgsApplication::getThemeIcon( QStringLiteral( "mIconTableLayer.svg" ) ), tr( "No Geometry" ), static_cast<quint32>( Qgis::WkbType::NoGeometry ) );
149 addGeomItem( Qgis::WkbType::Point );
150 addGeomItem( Qgis::WkbType::MultiPoint );
152 addGeomItem( Qgis::WkbType::LineString );
153 addGeomItem( Qgis::WkbType::MultiLineString );
155 addGeomItem( Qgis::WkbType::Polygon );
156 addGeomItem( Qgis::WkbType::MultiPolygon );
157
159 {
160 addGeomItem( Qgis::WkbType::CompoundCurve );
161 addGeomItem( Qgis::WkbType::CurvePolygon );
162 addGeomItem( Qgis::WkbType::MultiCurve );
163 addGeomItem( Qgis::WkbType::MultiSurface );
164 }
165
167 {
168 addGeomItem( Qgis::WkbType::Triangle ); // Not exactly surfaces, but only PostGIS (and memory) supports these types
170 addGeomItem( Qgis::WkbType::TIN );
171 }
172
173 mGeomTypeCbo->setCurrentIndex( 0 );
174
177 if ( !hasM )
178 {
179 mHasMChk->setEnabled( false );
180 mHasMChk->setChecked( false );
181 }
182 if ( !hasZ )
183 {
184 mHasZChk->setEnabled( false );
185 mHasZChk->setChecked( false );
186 }
187 if ( !hasM && !hasZ )
188 {
189 mHasZChk->setVisible( false );
190 mHasMChk->setVisible( false );
191 mDimensionsLabel->setVisible( false );
192 }
193
194 connect( mFieldsTableView->selectionModel(), &QItemSelectionModel::selectionChanged, mFieldsTableView, [=]( const QItemSelection &selected, const QItemSelection & ) {
195 if ( !selected.isEmpty() )
196 {
197 mCurrentRow = selected.indexes().first().row();
198 }
199 updateButtons();
200 } );
201
202 // Get a default type for new fields
203 const QMetaType::Type defaultFieldType { mFieldModel->nativeTypes().first().mType };
204 const QString defaultFieldTypeName { mFieldModel->nativeTypes().first().mTypeName };
205
206 // Actions
207 connect( mAddFieldBtn, &QPushButton::clicked, this, [=] {
208 QgsFields fieldList { fields() };
209 QgsField newField { QStringLiteral( "new_field_name" ), defaultFieldType, defaultFieldTypeName };
210 fieldList.append( newField );
211 setFields( fieldList );
212 selectRow( fieldList.count() - 1 );
213 } );
214
215 connect( mDeleteFieldBtn, &QPushButton::clicked, this, [=] {
216 QgsFields fieldList { fields() };
217 if ( fieldList.exists( mCurrentRow ) )
218 {
219 fieldList.remove( mCurrentRow );
220 setFields( fieldList );
221 mCurrentRow = -1;
222 }
223 } );
224
225 connect( mFieldUpBtn, &QPushButton::clicked, this, [=] {
226 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow - 1 ) )
227 {
228 QgsFields fieldList;
229 for ( int i = 0; i < fields().count(); ++i )
230 {
231 if ( i == mCurrentRow - 1 )
232 {
233 fieldList.append( fields().at( mCurrentRow ) );
234 fieldList.append( fields().at( mCurrentRow - 1 ) );
235 }
236 else if ( i != mCurrentRow )
237 {
238 fieldList.append( fields().at( i ) );
239 }
240 }
241 setFields( fieldList );
242 selectRow( mCurrentRow - 1 );
243 }
244 } );
245
246 connect( mFieldDownBtn, &QPushButton::clicked, this, [=] {
247 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow + 1 ) )
248 {
249 QgsFields fieldList;
250 for ( int i = 0; i < fields().count(); ++i )
251 {
252 if ( i == mCurrentRow )
253 {
254 fieldList.append( fields().at( mCurrentRow + 1 ) );
255 fieldList.append( fields().at( mCurrentRow ) );
256 }
257 else if ( i != mCurrentRow + 1 )
258 {
259 fieldList.append( fields().at( i ) );
260 }
261 }
262 setFields( fieldList );
263 selectRow( mCurrentRow + 1 );
264 }
265 } );
266
267 updateButtons();
268 validate();
269}
270
271void QgsNewVectorTableDialog::setSchemaName( const QString &name )
272{
273 mSchemaCbo->setCurrentText( name );
274}
275
276void QgsNewVectorTableDialog::setTableName( const QString &name )
277{
278 mTableName->setText( name );
279}
280
282{
283 mGeomTypeCbo->setCurrentIndex( mGeomTypeCbo->findData( static_cast<quint32>( type ) ) );
284}
285
287{
288 mCrs->setCrs( crs );
289}
290
292{
293 return mCrs->crs();
294}
295
297{
298 return mTableName->text();
299}
300
302{
303 return mSchemaCbo->currentText();
304}
305
307{
308 return mGeomColumn->text();
309}
310
312{
313 return mFieldModel ? mFieldModel->fields() : QgsFields();
314}
315
317{
318 Qgis::WkbType type { static_cast<Qgis::WkbType>( mGeomTypeCbo->currentData().toInt() ) };
319 if ( mHasMChk->isChecked() )
320 {
321 type = QgsWkbTypes::addM( type );
322 }
323 if ( mHasZChk->isChecked() )
324 {
325 type = QgsWkbTypes::addZ( type );
326 }
327 return type;
328}
329
330
332{
333 if ( mFieldModel )
334 {
335 mFieldModel->setFields( fields );
336 }
337}
338
340{
341 return mSpatialIndexChk->isChecked();
342}
343
345{
346 return mValidationErrors;
347}
348
349void QgsNewVectorTableDialog::updateButtons()
350{
351 mDeleteFieldBtn->setEnabled( mCurrentRow != -1 );
352 mFieldUpBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != 0 );
353 mFieldDownBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != fields().count() - 1 );
354}
355
356void QgsNewVectorTableDialog::selectRow( int row )
357{
358 QModelIndex index { mFieldsTableView->model()->index( row, 0 ) };
359 mFieldsTableView->setCurrentIndex( index );
360 QItemSelectionModel::SelectionFlags flags { QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current };
361 mFieldsTableView->selectionModel()->select( index, flags );
362 mFieldsTableView->scrollTo( index );
363}
364
365void QgsNewVectorTableDialog::validate()
366{
367 mValidationErrors.clear();
368
369 const bool isSpatial { mGeomTypeCbo->currentIndex() > 0 };
370 if ( mTableName->text().trimmed().isEmpty() )
371 {
372 mValidationErrors.push_back( tr( "Table name cannot be empty" ) );
373 }
374 else if ( mTableNames.contains( mTableName->text(), Qt::CaseSensitivity::CaseInsensitive ) )
375 {
376 mValidationErrors.push_back( tr( "Table <b>%1</b> already exists" ).arg( mTableName->text() ) );
377 }
378 // Check for field names and geom col name
379 if ( isSpatial && fields().names().contains( mGeomColumn->text(), Qt::CaseSensitivity::CaseInsensitive ) )
380 {
381 mValidationErrors.push_back( tr( "Geometry column name <b>%1</b> cannot be equal to an existing field name" ).arg( mGeomColumn->text() ) );
382 }
383 // No geometry and no fields? No party!
384 if ( !isSpatial && fields().count() == 0 )
385 {
386 mValidationErrors.push_back( tr( "The table has no geometry column and no fields" ) );
387 }
388 // Check if precision is <= length
389 const QgsFields cFields { fields() };
390 for ( const QgsField &f : cFields )
391 {
392 if ( f.isNumeric() && f.length() >= 0 && f.precision() >= 0 && f.precision() > f.length() )
393 {
394 mValidationErrors.push_back( tr( "Field <b>%1</b>: precision cannot be greater than length" ).arg( f.name() ) );
395 }
396
397 if ( f.name().trimmed().isEmpty() )
398 {
399 mValidationErrors.push_back( tr( "Field name cannot be empty" ) );
400 }
401 else
402 {
403 for ( const QString &illegalName : std::as_const( mIllegalFieldNames ) )
404 {
405 if ( f.name().compare( illegalName, Qt::CaseInsensitive ) == 0 )
406 {
407 mValidationErrors.push_back( tr( "<b>%1</b> is an illegal field name for this format and cannot be used" ).arg( f.name() ) );
408 }
409 }
410 }
411 }
412
413 const bool isValid { mValidationErrors.isEmpty() };
414 if ( !isValid )
415 {
416 mValidationResults->setText( mValidationErrors.join( QLatin1String( "<br>" ) ) );
417 }
418
419 mValidationFrame->setVisible( !isValid );
420 mButtonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( isValid );
421}
422
423void QgsNewVectorTableDialog::showEvent( QShowEvent *event )
424{
425 QDialog::showEvent( event );
426 mTableName->setFocus();
427 mTableName->selectAll();
428}
429
430
432
433
434QgsNewVectorTableDialogFieldsDelegate::QgsNewVectorTableDialogFieldsDelegate( const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
435 : QStyledItemDelegate( parent )
436 , mTypeList( typeList )
437{
438}
439
440QWidget *QgsNewVectorTableDialogFieldsDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
441{
442 switch ( index.column() )
443 {
444 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
445 {
446 QComboBox *cbo = new QComboBox { parent };
447 cbo->setEditable( false );
448 cbo->setFrame( false );
449 connect( cbo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged );
450 for ( const auto &f : std::as_const( mTypeList ) )
451 {
452 cbo->addItem( QgsFields::iconForFieldType( f.mType, f.mSubType ), f.mTypeDesc, f.mTypeName );
453 }
454 return cbo;
455 }
456 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
457 {
458 QSpinBox *sp { new QSpinBox { parent } };
459 const QgsNewVectorTableFieldModel *model { static_cast<const QgsNewVectorTableFieldModel *>( index.model() ) };
460 if ( model )
461 {
462 const QgsVectorDataProvider::NativeType nt { model->nativeType( index.row() ) };
463 sp->setRange( nt.mMinPrec, std::min<int>( nt.mMaxPrec, index.model()->data( index.model()->index( index.row(), index.column() - 1 ) ).toInt() ) );
464 }
465 return sp;
466 }
467 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
468 {
469 QSpinBox *sp { new QSpinBox { parent } };
470 const QgsNewVectorTableFieldModel *model { static_cast<const QgsNewVectorTableFieldModel *>( index.model() ) };
471 if ( model )
472 {
473 const QgsVectorDataProvider::NativeType nt { model->nativeType( index.row() ) };
474 sp->setRange( std::max<int>( nt.mMinLen, index.model()->data( index.model()->index( index.row(), index.column() + 1 ) ).toInt() ), nt.mMaxLen );
475 }
476 return sp;
477 }
478 default:
479 {
480 return QStyledItemDelegate::createEditor( parent, option, index );
481 }
482 }
483}
484
485void QgsNewVectorTableDialogFieldsDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
486{
487 const auto m { index.model() };
488 switch ( index.column() )
489 {
490 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
491 {
492 const QString txt = m->data( index, Qt::DisplayRole ).toString();
493 QComboBox *cbo { qobject_cast<QComboBox *>( editor ) };
494 if ( cbo )
495 {
496 cbo->setCurrentIndex( cbo->findText( txt ) );
497 }
498 break;
499 }
500 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
501 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
502 {
503 const int value = m->data( index, Qt::DisplayRole ).toInt();
504 QSpinBox *sp { qobject_cast<QSpinBox *>( editor ) };
505 if ( sp )
506 {
507 sp->setValue( value );
508 }
509 break;
510 }
511 default:
512 {
513 QStyledItemDelegate::setEditorData( editor, index );
514 }
515 }
516}
517
518void QgsNewVectorTableDialogFieldsDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
519{
520 switch ( index.column() )
521 {
522 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
523 {
524 QComboBox *cbo { qobject_cast<QComboBox *>( editor ) };
525 if ( cbo )
526 {
527 model->setData( index, cbo->currentData() );
528 }
529 break;
530 }
531 default:
532 {
533 QStyledItemDelegate::setModelData( editor, model, index );
534 }
535 }
536}
537
538void QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged( int index )
539{
540 Q_UNUSED( index )
541 QComboBox *cb = static_cast<QComboBox *>( sender() );
542 if ( cb )
543 {
544 emit commitData( cb );
545 }
546}
547
548QgsNewVectorTableFieldModel::QgsNewVectorTableFieldModel( const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
549 : QgsFieldModel( parent )
550 , mNativeTypes( typeList )
551{
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( QStringLiteral( "Cannot get field native type for: %1" ).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( QStringLiteral( "Cannot get field for row: %1" ).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:256
@ CompoundCurve
CompoundCurve.
@ LineString
LineString.
@ MultiPoint
MultiPoint.
@ Polygon
Polygon.
@ MultiPolygon
MultiPolygon.
@ Triangle
Triangle.
@ NoGeometry
No geometry.
@ MultiLineString
MultiLineString.
@ MultiCurve
MultiCurve.
@ CurvePolygon
CurvePolygon.
@ PolyhedralSurface
PolyhedralSurface.
@ MultiSurface
MultiSurface.
The QgsAbstractDatabaseProviderConnection class provides common functionality for DB based connection...
@ PolyhedralSurfaces
Supports polyhedral surfaces (PolyhedralSurface, TIN) types (as distinct from multi polygon types)
@ SinglePart
Multi and single part types are distinct types. Deprecated since QGIS 3.28 – use the granular SingleP...
@ SinglePolygon
Supports single polygon types (as distinct from multi polygon types)
@ SinglePoint
Supports single point types (as distinct from multi point types)
@ SingleLineString
Supports single linestring types (as distinct from multi line types)
virtual QList< QgsAbstractDatabaseProviderConnection::TableProperty > tables(const QString &schema=QString(), const QgsAbstractDatabaseProviderConnection::TableFlags &flags=QgsAbstractDatabaseProviderConnection::TableFlags(), QgsFeedback *feedback=nullptr) const
Returns information on the tables in the given schema.
@ CreateSpatialIndex
The connection can create spatial indices.
@ Schemas
Can list schemas (if not set, the connection does not support schemas)
virtual GeometryColumnCapabilities geometryColumnCapabilities()
Returns connection geometry column capabilities (Z, M, SinglePart, Curves).
virtual QSet< QString > illegalFieldNames() const
Returns a list of field names which are considered illegal by the connection and should not be used w...
virtual QStringList schemas() const
Returns information about the existing schemas.
virtual QList< QgsVectorDataProvider::NativeType > nativeTypes() const =0
Returns a list of native types supported by the connection.
Capabilities capabilities() const
Returns connection capabilities.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
This class represents a coordinate reference system (CRS).
QString what() const
The QgsFieldModel class is a model to display the list of fields in widgets (optionally associated wi...
QVariant data(const QModelIndex &index, int role) const override
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:53
void setName(const QString &name)
Set the field name.
Definition qgsfield.cpp:227
Container of fields for a vector layer.
Definition qgsfields.h:46
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:70
void remove(int fieldIdx)
Removes the field with the given index.
static QIcon iconForFieldType(QMetaType::Type type, QMetaType::Type subType=QMetaType::Type::UnknownType, const QString &typeString=QString())
Returns an icon corresponding to a field type.
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition qgsgui.cpp:210
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:6643
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:6642
#define QgsDebugError(str)
Definition qgslogger.h:38
const QgsCoordinateReferenceSystem & crs
const QString & typeName