36 mFieldModel =
new QgsNewVectorTableFieldModel( mConnection->
nativeTypes(),
this );
40 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"
41 "Error message: %1" ).arg( ex.
what() ) );
42 QTimer::singleShot( 0,
this, [ = ] { reject(); } );
46 Q_ASSERT( ! mFieldModel->nativeTypes().isEmpty() );
49 setWindowTitle( tr(
"New Table" ) );
51 auto updateTableNames = [ = ](
const QString &schema = QString( ) )
56 const auto constTables { conn->
tables( schema ) };
57 for (
const auto &tp : constTables )
59 mTableNames.push_back( tp.tableName() );
66 QgsDebugMsg( QStringLiteral(
"Error retrieving tables from connection: %1" ).arg( ex.
what() ) );
71 connect( mFieldModel, &QgsNewVectorTableFieldModel::modelReset,
this, [ = ]()
76 mTableName->setText( QStringLiteral(
"new_table_name" ) );
77 mFieldsTableView->setModel( mFieldModel );
78 QgsNewVectorTableDialogFieldsDelegate *delegate {
new QgsNewVectorTableDialogFieldsDelegate( mConnection->
nativeTypes(),
this )};
79 mFieldsTableView->setItemDelegate( delegate );
80 mFieldsTableView->setSelectionBehavior( QAbstractItemView::SelectionBehavior::SelectRows );
81 mFieldsTableView->setSelectionMode( QAbstractItemView::SelectionMode::SingleSelection );
82 mFieldsTableView->setVerticalHeader(
nullptr );
85 mFieldsTableView->horizontalHeader()->setStretchLastSection(
true );
86 mFieldsTableView->setColumnWidth( QgsNewVectorTableFieldModel::ColumnHeaders::Type, 300 );
89 if ( mConnection->
capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::Schemas ) )
91 mSchemaCbo->addItems( mConnection->
schemas() );
92 connect( mSchemaCbo, &QComboBox::currentTextChanged,
this, [ = ](
const QString & schema )
94 updateTableNames( schema );
100 mSchemaLabel->hide();
103 if ( ! mConnection->
capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::CreateSpatialIndex ) )
105 mSpatialIndexChk->setChecked(
false );
106 mSpatialIndexChk->hide();
107 mSpatialIndexLabel->hide();
111 updateTableNames( mSchemaCbo->currentText() );
114 connect( mTableName, &QLineEdit::textChanged,
this, [ = ](
const QString & )
119 connect( mGeomColumn, &QLineEdit::textChanged,
this, [ = ](
const QString & )
125 connect( mGeomTypeCbo, qOverload<int>( &QComboBox::currentIndexChanged ),
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 );
140 mCrs->setShowAccuracyWarnings(
true );
144 const bool hasSinglePart { conn->
geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::SinglePart ) };
152 mGeomTypeCbo->addItem(
QgsApplication::getThemeIcon( QStringLiteral(
"mIconTableLayer.svg" ) ), tr(
"No Geometry" ), QgsWkbTypes::Type::NoGeometry );
153 if ( hasSinglePart || conn->
geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::SinglePoint ) )
154 addGeomItem( QgsWkbTypes::Type::Point );
155 addGeomItem( QgsWkbTypes::Type::MultiPoint );
156 if ( hasSinglePart || conn->
geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::SingleLineString ) )
157 addGeomItem( QgsWkbTypes::Type::LineString );
158 addGeomItem( QgsWkbTypes::Type::MultiLineString );
159 if ( hasSinglePart || conn->
geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::SinglePolygon ) )
160 addGeomItem( QgsWkbTypes::Type::Polygon );
161 addGeomItem( QgsWkbTypes::Type::MultiPolygon );
165 addGeomItem( QgsWkbTypes::Type::CompoundCurve );
166 addGeomItem( QgsWkbTypes::Type::CurvePolygon );
167 addGeomItem( QgsWkbTypes::Type::MultiCurve );
168 addGeomItem( QgsWkbTypes::Type::MultiSurface );
171 mGeomTypeCbo->setCurrentIndex( 0 );
173 const bool hasZ { conn->
geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::Z ) };
174 const bool hasM { conn->
geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::M ) };
177 mHasMChk->setEnabled(
false );
178 mHasMChk->setChecked(
false );
182 mHasZChk->setEnabled(
false );
183 mHasZChk->setChecked(
false );
185 if ( ! hasM && ! hasM )
187 mHasZChk->setVisible(
false );
188 mHasMChk->setVisible(
false );
189 mDimensionsLabel->setVisible(
false );
192 connect( mFieldsTableView->selectionModel(), &QItemSelectionModel::selectionChanged, mFieldsTableView, [ = ](
const QItemSelection & selected,
const QItemSelection & )
194 if ( ! selected.isEmpty() )
196 mCurrentRow = selected.indexes().first().row();
202 const QVariant::Type defaultFieldType { mFieldModel->nativeTypes().first().mType };
203 const QString defaultFieldTypeName { mFieldModel->nativeTypes().first().mTypeName };
206 connect( mAddFieldBtn, &QPushButton::clicked,
this, [ = ]
209 QgsField newField { QStringLiteral(
"new_field_name" ), defaultFieldType, defaultFieldTypeName };
210 fieldList.append( newField );
211 setFields( fieldList );
212 selectRow( fieldList.count() - 1 );
215 connect( mDeleteFieldBtn, &QPushButton::clicked,
this, [ = ]
218 if ( fieldList.exists( mCurrentRow ) )
220 fieldList.
remove( mCurrentRow );
221 setFields( fieldList );
226 connect( mFieldUpBtn, &QPushButton::clicked,
this, [ = ]
228 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow - 1 ) )
231 for (
int i = 0; i < fields().count(); ++i )
233 if ( i == mCurrentRow - 1 )
235 fieldList.
append( fields().at( mCurrentRow ) );
236 fieldList.
append( fields().at( mCurrentRow - 1 ) );
238 else if ( i != mCurrentRow )
240 fieldList.
append( fields().at( i ) );
243 setFields( fieldList );
244 selectRow( mCurrentRow - 1 );
248 connect( mFieldDownBtn, &QPushButton::clicked,
this, [ = ]
250 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow + 1 ) )
253 for (
int i = 0; i < fields().count(); ++i )
255 if ( i == mCurrentRow )
257 fieldList.
append( fields().at( mCurrentRow + 1 ) );
258 fieldList.
append( fields().at( mCurrentRow ) );
260 else if ( i != mCurrentRow + 1 )
262 fieldList.
append( fields().at( i ) );
265 setFields( fieldList );
266 selectRow( mCurrentRow + 1 );
276 mSchemaCbo->setCurrentText( name );
281 mTableName->setText( name );
286 mGeomTypeCbo->setCurrentIndex( mGeomTypeCbo->findData( type ) );
301 return mTableName->text();
306 return mSchemaCbo->currentText();
311 return mGeomColumn->text();
316 return mFieldModel ? mFieldModel->fields() :
QgsFields();
322 if ( mHasMChk->isChecked() )
326 if ( mHasZChk->isChecked() )
338 mFieldModel->setFields(
fields );
344 return mSpatialIndexChk->isChecked();
349 return mValidationErrors;
352void QgsNewVectorTableDialog::updateButtons()
354 mDeleteFieldBtn->setEnabled( mCurrentRow != -1 );
355 mFieldUpBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != 0 );
356 mFieldDownBtn->setEnabled( mCurrentRow != -1 && mCurrentRow !=
fields().count() - 1 );
359void QgsNewVectorTableDialog::selectRow(
int row )
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 );
368void QgsNewVectorTableDialog::validate()
370 mValidationErrors.clear();
372 const bool isSpatial { mGeomTypeCbo->currentIndex() > 0 };
373 if ( mTableNames.contains( mTableName->text(), Qt::CaseSensitivity::CaseInsensitive ) )
375 mValidationErrors.push_back( tr(
"Table <b>%1</b> already exists!" ).arg( mTableName->text() ) );
378 if ( isSpatial &&
fields().names().contains( mGeomColumn->text(), Qt::CaseSensitivity::CaseInsensitive ) )
380 mValidationErrors.push_back( tr(
"Geometry column name <b>%1</b> cannot be equal to an existing field name!" ).arg( mGeomColumn->text() ) );
383 if ( ! isSpatial &&
fields().count() == 0 )
385 mValidationErrors.push_back( tr(
"The table has no geometry column and no fields!" ) );
388 const auto cFields {
fields() };
389 for (
const auto &f : cFields )
391 if ( f.isNumeric() && f.length() >= 0 && f.precision() >= 0 && f.precision() > f.length() )
393 mValidationErrors.push_back( tr(
"Field <b>%1</b>: precision cannot be greater than length!" ).arg( f.name() ) );
397 const bool isValid { mValidationErrors.isEmpty() };
400 mValidationResults->setText( mValidationErrors.join( QLatin1String(
"<br>" ) ) );
403 mValidationFrame->setVisible( ! isValid );
404 mButtonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( isValid );
409 QDialog::showEvent( event );
410 mTableName->setFocus();
411 mTableName->selectAll();
418QgsNewVectorTableDialogFieldsDelegate::QgsNewVectorTableDialogFieldsDelegate(
const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
419 : QStyledItemDelegate( parent )
420 , mTypeList( typeList )
425QWidget *QgsNewVectorTableDialogFieldsDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index )
const
427 switch ( index.column() )
429 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
431 QComboBox *cbo =
new QComboBox { parent };
432 cbo->setEditable(
false );
433 cbo->setFrame(
false );
434 connect( cbo, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged );
435 for (
const auto &f : std::as_const( mTypeList ) )
441 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
443 QSpinBox *sp {
new QSpinBox { parent } };
444 const QgsNewVectorTableFieldModel *model {
static_cast<const QgsNewVectorTableFieldModel *
>( index.model() )};
448 sp->setRange( nt.mMinPrec, std::min<int>( nt.mMaxPrec, index.model()->data( index.model()->index( index.row(), index.column() - 1 ) ).toInt() ) );
452 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
454 QSpinBox *sp {
new QSpinBox { parent } };
455 const QgsNewVectorTableFieldModel *model {
static_cast<const QgsNewVectorTableFieldModel *
>( index.model() )};
459 sp->setRange( std::max<int>( nt.mMinLen, index.model()->data( index.model()->index( index.row(), index.column() + 1 ) ).toInt() ), nt.mMaxLen );
465 return QStyledItemDelegate::createEditor( parent, option, index );
470void QgsNewVectorTableDialogFieldsDelegate::setEditorData( QWidget *editor,
const QModelIndex &index )
const
472 const auto m { index.model() };
473 switch ( index.column() )
475 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
477 const QString txt = m->data( index, Qt::DisplayRole ).toString();
478 QComboBox *cbo{ qobject_cast<QComboBox *>( editor ) };
481 cbo->setCurrentIndex( cbo->findText( txt ) );
485 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
486 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
488 const int value = m->data( index, Qt::DisplayRole ).toInt();
489 QSpinBox *sp{ qobject_cast<QSpinBox *>( editor ) };
492 sp->setValue( value );
498 QStyledItemDelegate::setEditorData( editor, index );
503void QgsNewVectorTableDialogFieldsDelegate::setModelData( QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index )
const
505 switch ( index.column() )
507 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
509 QComboBox *cbo { qobject_cast<QComboBox *>( editor ) };
512 model->setData( index, cbo->currentData() );
518 QStyledItemDelegate::setModelData( editor, model, index );
523void QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged(
int index )
526 QComboBox *cb =
static_cast<QComboBox *
>( sender() );
529 emit commitData( cb );
533QgsNewVectorTableFieldModel::QgsNewVectorTableFieldModel(
const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
535 , mNativeTypes( typeList )
540int QgsNewVectorTableFieldModel::columnCount(
const QModelIndex & )
const
545QVariant QgsNewVectorTableFieldModel::data(
const QModelIndex &index,
int role )
const
547 if ( mFields.exists( index.row() ) )
552 case Qt::ItemDataRole::DisplayRole:
554 switch (
static_cast<ColumnHeaders
>( index.column() ) )
556 case ColumnHeaders::Name:
560 case ColumnHeaders::Type:
564 case ColumnHeaders::ProviderType:
568 case ColumnHeaders::Comment:
572 case ColumnHeaders::Precision:
576 case ColumnHeaders::Length:
585 case Qt::ItemDataRole::TextAlignmentRole:
587 switch (
static_cast<ColumnHeaders
>( index.column() ) )
589 case ColumnHeaders::Precision:
590 case ColumnHeaders::Length:
592 return static_cast<Qt::Alignment::Int
>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignHCenter );
601 if (
static_cast<ColumnHeaders
>( index.column() ) == ColumnHeaders::Name )
611QVariant QgsNewVectorTableFieldModel::headerData(
int section, Qt::Orientation orientation,
int role )
const
613 if ( orientation == Qt::Orientation::Horizontal )
617 case Qt::ItemDataRole::DisplayRole:
619 switch (
static_cast<ColumnHeaders
>( section ) )
621 case ColumnHeaders::Name:
625 case ColumnHeaders::Type:
629 case ColumnHeaders::Comment:
631 return tr(
"Comment" );
633 case ColumnHeaders::ProviderType:
635 return tr(
"Provider type" );
637 case ColumnHeaders::Length:
639 return tr(
"Length" );
641 case ColumnHeaders::Precision:
643 return tr(
"Precision" );
650 case Qt::ItemDataRole::TextAlignmentRole:
652 switch (
static_cast<ColumnHeaders
>( section ) )
654 case ColumnHeaders::Name:
655 case ColumnHeaders::Comment:
656 case ColumnHeaders::Type:
657 case ColumnHeaders::ProviderType:
659 return static_cast<Qt::Alignment::Int
>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignLeft );
663 return static_cast<Qt::Alignment::Int
>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignHCenter );
670 QgsFieldModel::headerData( section, orientation, role );
677Qt::ItemFlags QgsNewVectorTableFieldModel::flags(
const QModelIndex &index )
const
679 switch (
static_cast<ColumnHeaders
>( index.column() ) )
681 case ColumnHeaders::Name:
682 case ColumnHeaders::Comment:
683 case ColumnHeaders::Type:
685 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
687 case ColumnHeaders::Length:
689 if ( mFields.exists( index.row( ) ) )
692 if ( nt.mMinLen < nt.mMaxLen )
694 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
699 case ColumnHeaders::Precision:
701 if ( mFields.exists( index.row( ) ) )
704 if ( nt.mMinPrec < nt.mMaxPrec )
706 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
711 case ColumnHeaders::ProviderType:
713 return QgsFieldModel::flags( index );
716 return QgsFieldModel::flags( index );
719QList<QgsVectorDataProvider::NativeType> QgsNewVectorTableFieldModel::nativeTypes()
const
724QString QgsNewVectorTableFieldModel::typeDesc(
const QString &
typeName )
const
726 for (
const auto &t : std::as_const( mNativeTypes ) )
728 if ( t.mTypeName.compare(
typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
736QVariant::Type QgsNewVectorTableFieldModel::type(
const QString &
typeName )
const
738 return nativeType(
typeName ).mType;
743 for (
const auto &t : std::as_const( mNativeTypes ) )
745 if ( t.mTypeName.compare(
typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
752 return mNativeTypes.first();
757 if ( mFields.exists( row ) )
759 return nativeType( mFields.at( row ).typeName() );
762 QgsDebugMsg( QStringLiteral(
"Cannot get field for row: %1" ).arg( row ) );
763 return mNativeTypes.first();
766bool QgsNewVectorTableFieldModel::setData(
const QModelIndex &index,
const QVariant &value,
int role )
768 if ( role == Qt::ItemDataRole::EditRole && mFields.exists( index.row() ) && index.column() < 6 )
770 const int fieldIdx { index.row() };
772 switch (
static_cast<ColumnHeaders
>( index.column() ) )
774 case ColumnHeaders::Name:
779 case ColumnHeaders::Type:
782 const auto tp { nativeType( value.toString() ) };
788 case ColumnHeaders::Comment:
793 case ColumnHeaders::ProviderType:
798 case ColumnHeaders::Length:
803 case ColumnHeaders::Precision:
811 for (
int i = 0; i < mFields.count(); ++i )
819 fields.
append( mFields.at( i ) );
824 return QgsFieldModel::setData( index, value, role );
The QgsAbstractDatabaseProviderConnection class provides common functionality for DB based connection...
virtual GeometryColumnCapabilities geometryColumnCapabilities()
Returns connection geometry column capabilities (Z, M, SinglePart, Curves).
virtual QList< QgsVectorDataProvider::NativeType > nativeTypes() const SIP_THROW(QgsProviderConnectionException)=0
Returns a list of native types supported by the connection.
virtual QStringList schemas() const SIP_THROW(QgsProviderConnectionException)
Returns information about the existing schemas.
virtual QList< QgsAbstractDatabaseProviderConnection::TableProperty > tables(const QString &schema=QString(), const QgsAbstractDatabaseProviderConnection::TableFlags &flags=QgsAbstractDatabaseProviderConnection::TableFlags()) const
Returns information on the tables in the given schema.
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).
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.
QString typeName() const
Gets the field type.
void setPrecision(int precision)
Set the field precision.
void setName(const QString &name)
Set the field name.
void setComment(const QString &comment)
Set the field comment.
void setLength(int len)
Set the field length.
void setType(QVariant::Type type)
Set variant type.
void setTypeName(const QString &typeName)
Set the field type.
Container of fields for a vector layer.
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
static QIcon iconForFieldType(QVariant::Type type, QVariant::Type subType=QVariant::Type::Invalid)
Returns an icon corresponding to a field type.
void remove(int fieldIdx)
Removes the field with the given index.
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...
static QIcon iconForWkbType(QgsWkbTypes::Type 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 cheched.
QgsFields fields() const
Returns the fields.
QStringList validationErrors() const
Returns the validation errors or an empty list if the dialog is valid.
void setGeometryType(QgsWkbTypes::Type type)
Sets the geometry type.
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.
QgsWkbTypes::Type 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(Type type) SIP_HOLDGIL
Returns a translated display string type for a WKB type, e.g., the geometry name used in WKT geometry...
Type
The WKB type describes the number of dimensions a geometry has.
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
#define Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_PUSH
const QgsCoordinateReferenceSystem & crs