QGIS API Documentation 4.1.0-Master (70f46ec8b69)
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 addGeomItem( Qgis::WkbType::NurbsCurve );
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 { u"new_field_name"_s, 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( "<br>"_L1 ) );
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
442QWidget *QgsNewVectorTableDialogFieldsDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
443{
444 switch ( index.column() )
445 {
446 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
447 {
448 QComboBox *cbo = new QComboBox { parent };
449 cbo->setEditable( false );
450 cbo->setFrame( false );
451 connect( cbo, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged );
452 for ( const auto &f : std::as_const( mTypeList ) )
453 {
454 cbo->addItem( QgsFields::iconForFieldType( f.mType, f.mSubType ), f.mTypeDesc, f.mTypeName );
455 }
456 return cbo;
457 }
458 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
459 {
460 QSpinBox *sp { new QSpinBox { parent } };
461 const QgsNewVectorTableFieldModel *model { static_cast<const QgsNewVectorTableFieldModel *>( index.model() ) };
462 if ( model )
463 {
464 const QgsVectorDataProvider::NativeType nt { model->nativeType( index.row() ) };
465 sp->setRange( nt.mMinPrec, std::min<int>( nt.mMaxPrec, index.model()->data( index.model()->index( index.row(), index.column() - 1 ) ).toInt() ) );
466 }
467 return sp;
468 }
469 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
470 {
471 QSpinBox *sp { new QSpinBox { parent } };
472 const QgsNewVectorTableFieldModel *model { static_cast<const QgsNewVectorTableFieldModel *>( index.model() ) };
473 if ( model )
474 {
475 const QgsVectorDataProvider::NativeType nt { model->nativeType( index.row() ) };
476 sp->setRange( std::max<int>( nt.mMinLen, index.model()->data( index.model()->index( index.row(), index.column() + 1 ) ).toInt() ), nt.mMaxLen );
477 }
478 return sp;
479 }
480 default:
481 {
482 return QStyledItemDelegate::createEditor( parent, option, index );
483 }
484 }
485}
486
487void QgsNewVectorTableDialogFieldsDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
488{
489 const auto m { index.model() };
490 switch ( index.column() )
491 {
492 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
493 {
494 const QString txt = m->data( index, Qt::DisplayRole ).toString();
495 QComboBox *cbo { qobject_cast<QComboBox *>( editor ) };
496 if ( cbo )
497 {
498 cbo->setCurrentIndex( cbo->findText( txt ) );
499 }
500 break;
501 }
502 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
503 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
504 {
505 const int value = m->data( index, Qt::DisplayRole ).toInt();
506 QSpinBox *sp { qobject_cast<QSpinBox *>( editor ) };
507 if ( sp )
508 {
509 sp->setValue( value );
510 }
511 break;
512 }
513 default:
514 {
515 QStyledItemDelegate::setEditorData( editor, index );
516 }
517 }
518}
519
520void QgsNewVectorTableDialogFieldsDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
521{
522 switch ( index.column() )
523 {
524 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
525 {
526 QComboBox *cbo { qobject_cast<QComboBox *>( editor ) };
527 if ( cbo )
528 {
529 model->setData( index, cbo->currentData() );
530 }
531 break;
532 }
533 default:
534 {
535 QStyledItemDelegate::setModelData( editor, model, index );
536 }
537 }
538}
539
540void QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged( int index )
541{
542 Q_UNUSED( index )
543 QComboBox *cb = static_cast<QComboBox *>( sender() );
544 if ( cb )
545 {
546 emit commitData( cb );
547 }
548}
549
550QgsNewVectorTableFieldModel::QgsNewVectorTableFieldModel( const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
551 : QgsFieldModel( parent )
552 , mNativeTypes( typeList )
553{}
554
555int QgsNewVectorTableFieldModel::columnCount( const QModelIndex & ) const
556{
557 return 6;
558}
559
560QVariant QgsNewVectorTableFieldModel::data( const QModelIndex &index, int role ) const
561{
562 if ( mFields.exists( index.row() ) )
563 {
564 const QgsField field { mFields.at( index.row() ) };
565 switch ( role )
566 {
567 case Qt::ItemDataRole::DisplayRole:
568 {
569 switch ( static_cast<ColumnHeaders>( index.column() ) )
570 {
571 case ColumnHeaders::Name:
572 {
573 return QgsFieldModel::data( index, role );
574 }
575 case ColumnHeaders::Type:
576 {
577 return typeDesc( field.typeName() );
578 }
579 case ColumnHeaders::ProviderType:
580 {
581 return field.typeName();
582 }
583 case ColumnHeaders::Comment:
584 {
585 return field.comment();
586 }
587 case ColumnHeaders::Precision:
588 {
589 return field.precision();
590 }
591 case ColumnHeaders::Length:
592 {
593 return field.length();
594 }
595 default:
596 break;
597 }
598 return QgsFieldModel::data( index, role );
599 }
600 case Qt::ItemDataRole::TextAlignmentRole:
601 {
602 switch ( static_cast<ColumnHeaders>( index.column() ) )
603 {
604 case ColumnHeaders::Precision:
605 case ColumnHeaders::Length:
606 {
607 return static_cast<Qt::Alignment::Int>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignHCenter );
608 }
609 default:
610 break;
611 }
612 return QgsFieldModel::data( index, role );
613 }
614 default:
615 {
616 if ( static_cast<ColumnHeaders>( index.column() ) == ColumnHeaders::Name )
617 {
618 return QgsFieldModel::data( index, role );
619 }
620 }
621 }
622 }
623 return QVariant();
624}
625
626QVariant QgsNewVectorTableFieldModel::headerData( int section, Qt::Orientation orientation, int role ) const
627{
628 if ( orientation == Qt::Orientation::Horizontal )
629 {
630 switch ( role )
631 {
632 case Qt::ItemDataRole::DisplayRole:
633 {
634 switch ( static_cast<ColumnHeaders>( section ) )
635 {
636 case ColumnHeaders::Name:
637 {
638 return tr( "Name" );
639 }
640 case ColumnHeaders::Type:
641 {
642 return tr( "Type" );
643 }
644 case ColumnHeaders::Comment:
645 {
646 return tr( "Comment" );
647 }
648 case ColumnHeaders::ProviderType:
649 {
650 return tr( "Provider type" );
651 }
652 case ColumnHeaders::Length:
653 {
654 return tr( "Length" );
655 }
656 case ColumnHeaders::Precision:
657 {
658 return tr( "Precision" );
659 }
660 default:
661 return QVariant();
662 }
663 break;
664 }
665 case Qt::ItemDataRole::TextAlignmentRole:
666 {
667 switch ( static_cast<ColumnHeaders>( section ) )
668 {
669 case ColumnHeaders::Name:
670 case ColumnHeaders::Comment:
671 case ColumnHeaders::Type:
672 case ColumnHeaders::ProviderType:
673 {
674 return static_cast<Qt::Alignment::Int>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignLeft );
675 }
676 default:
677 {
678 return static_cast<Qt::Alignment::Int>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignHCenter );
679 }
680 }
681 break;
682 }
683 default:
684 {
685 QgsFieldModel::headerData( section, orientation, role );
686 }
687 }
688 }
689 return QVariant();
690}
691
692Qt::ItemFlags QgsNewVectorTableFieldModel::flags( const QModelIndex &index ) const
693{
694 switch ( static_cast<ColumnHeaders>( index.column() ) )
695 {
696 case ColumnHeaders::Name:
697 case ColumnHeaders::Comment:
698 case ColumnHeaders::Type:
699 {
700 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
701 }
702 case ColumnHeaders::Length:
703 {
704 if ( mFields.exists( index.row() ) )
705 {
706 const QgsVectorDataProvider::NativeType nt { nativeType( mFields.at( index.row() ).typeName() ) };
707 if ( nt.mMinLen < nt.mMaxLen )
708 {
709 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
710 }
711 }
712 break;
713 }
714 case ColumnHeaders::Precision:
715 {
716 if ( mFields.exists( index.row() ) )
717 {
718 const QgsVectorDataProvider::NativeType nt { nativeType( mFields.at( index.row() ).typeName() ) };
719 if ( nt.mMinPrec < nt.mMaxPrec )
720 {
721 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
722 }
723 }
724 break;
725 }
726 case ColumnHeaders::ProviderType:
727 {
728 return QgsFieldModel::flags( index );
729 }
730 }
731 return QgsFieldModel::flags( index );
732}
733
734QList<QgsVectorDataProvider::NativeType> QgsNewVectorTableFieldModel::nativeTypes() const
735{
736 return mNativeTypes;
737}
738
739QString QgsNewVectorTableFieldModel::typeDesc( const QString &typeName ) const
740{
741 for ( const auto &t : std::as_const( mNativeTypes ) )
742 {
743 if ( t.mTypeName.compare( typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
744 {
745 return t.mTypeDesc;
746 }
747 }
748 return typeName;
749}
750
751QMetaType::Type QgsNewVectorTableFieldModel::type( const QString &typeName ) const
752{
753 return nativeType( typeName ).mType;
754}
755
756QgsVectorDataProvider::NativeType QgsNewVectorTableFieldModel::nativeType( const QString &typeName ) const
757{
758 for ( const auto &t : std::as_const( mNativeTypes ) )
759 {
760 if ( t.mTypeName.compare( typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
761 {
762 return t;
763 }
764 }
765 // This should never happen!
766 QgsDebugError( u"Cannot get field native type for: %1"_s.arg( typeName ) );
767 return mNativeTypes.first();
768}
769
770QgsVectorDataProvider::NativeType QgsNewVectorTableFieldModel::nativeType( int row ) const
771{
772 if ( mFields.exists( row ) )
773 {
774 return nativeType( mFields.at( row ).typeName() );
775 }
776 // This should never happen!
777 QgsDebugError( u"Cannot get field for row: %1"_s.arg( row ) );
778 return mNativeTypes.first();
779}
780
781bool QgsNewVectorTableFieldModel::setData( const QModelIndex &index, const QVariant &value, int role )
782{
783 if ( role == Qt::ItemDataRole::EditRole && mFields.exists( index.row() ) && index.column() < 6 )
784 {
785 const int fieldIdx { index.row() };
786 QgsField field { mFields.at( fieldIdx ) };
787 switch ( static_cast<ColumnHeaders>( index.column() ) )
788 {
789 case ColumnHeaders::Name:
790 {
791 field.setName( value.toString() );
792 break;
793 }
794 case ColumnHeaders::Type:
795 {
796 field.setTypeName( value.toString() );
797 const auto tp { nativeType( value.toString() ) };
798 field.setType( tp.mType );
799 field.setLength( std::max( std::min<int>( field.length(), tp.mMaxLen ), tp.mMinLen ) );
800 field.setPrecision( std::max( std::min<int>( field.precision(), tp.mMaxPrec ), tp.mMinPrec ) );
801 break;
802 }
803 case ColumnHeaders::Comment:
804 {
805 field.setComment( value.toString() );
806 break;
807 }
808 case ColumnHeaders::ProviderType:
809 {
810 field.setTypeName( value.toString() );
811 break;
812 }
813 case ColumnHeaders::Length:
814 {
815 field.setLength( value.toInt() );
816 break;
817 }
818 case ColumnHeaders::Precision:
819 {
820 field.setPrecision( value.toInt() );
821 break;
822 }
823 }
824
825 QgsFields fields;
826 for ( int i = 0; i < mFields.count(); ++i )
827 {
828 if ( i == fieldIdx )
829 {
830 fields.append( field );
831 }
832 else
833 {
834 fields.append( mFields.at( i ) );
835 }
836 }
837 setFields( fields );
838 }
839 return QgsFieldModel::setData( index, value, role );
840}
841
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
@ NurbsCurve
NurbsCurve.
Definition qgis.h:311
@ 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:7925
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7924
#define QgsDebugError(str)
Definition qgslogger.h:71