17#include "moc_qgsnewvectortabledialog.cpp"
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 QgsDebugError( 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 );
91 mSchemaCbo->addItems( mConnection->
schemas() );
92 connect( mSchemaCbo, &QComboBox::currentTextChanged,
this, [ = ](
const QString & schema )
94 updateTableNames( schema );
100 mSchemaLabel->hide();
105 mSpatialIndexChk->setChecked(
false );
106 mSpatialIndexChk->hide();
107 mSpatialIndexLabel->hide();
113 updateTableNames( mSchemaCbo->currentText() );
116 connect( mTableName, &QLineEdit::textChanged,
this, [ = ](
const QString & )
121 connect( mGeomColumn, &QLineEdit::textChanged,
this, [ = ](
const QString & )
127 connect( mGeomTypeCbo, qOverload<int>( &QComboBox::currentIndexChanged ),
this, [ = ](
int index )
129 const bool hasGeom { index != 0 };
130 mGeomColumn->setEnabled( hasGeom );
131 mGeomColumnLabel->setEnabled( hasGeom );
132 mSpatialIndexChk->setEnabled( hasGeom );
133 mSpatialIndexLabel->setEnabled( hasGeom );
134 mCrs->setEnabled( hasGeom );
135 mCrsLabel->setEnabled( hasGeom );
136 mDimensionsLabel->setEnabled( hasGeom );
137 mHasMChk->setEnabled( hasGeom );
138 mHasZChk->setEnabled( hasGeom );
142 mCrs->setShowAccuracyWarnings(
true );
180 mGeomTypeCbo->setCurrentIndex( 0 );
186 mHasMChk->setEnabled(
false );
187 mHasMChk->setChecked(
false );
191 mHasZChk->setEnabled(
false );
192 mHasZChk->setChecked(
false );
194 if ( ! hasM && ! hasZ )
196 mHasZChk->setVisible(
false );
197 mHasMChk->setVisible(
false );
198 mDimensionsLabel->setVisible(
false );
201 connect( mFieldsTableView->selectionModel(), &QItemSelectionModel::selectionChanged, mFieldsTableView, [ = ](
const QItemSelection & selected,
const QItemSelection & )
203 if ( ! selected.isEmpty() )
205 mCurrentRow = selected.indexes().first().row();
211 const QMetaType::Type defaultFieldType { mFieldModel->nativeTypes().first().mType };
212 const QString defaultFieldTypeName { mFieldModel->nativeTypes().first().mTypeName };
215 connect( mAddFieldBtn, &QPushButton::clicked,
this, [ = ]
218 QgsField newField { QStringLiteral(
"new_field_name" ), defaultFieldType, defaultFieldTypeName };
219 fieldList.append( newField );
220 setFields( fieldList );
221 selectRow( fieldList.count() - 1 );
224 connect( mDeleteFieldBtn, &QPushButton::clicked,
this, [ = ]
227 if ( fieldList.exists( mCurrentRow ) )
229 fieldList.
remove( mCurrentRow );
230 setFields( fieldList );
235 connect( mFieldUpBtn, &QPushButton::clicked,
this, [ = ]
237 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow - 1 ) )
240 for (
int i = 0; i < fields().count(); ++i )
242 if ( i == mCurrentRow - 1 )
244 fieldList.
append( fields().at( mCurrentRow ) );
245 fieldList.
append( fields().at( mCurrentRow - 1 ) );
247 else if ( i != mCurrentRow )
249 fieldList.
append( fields().at( i ) );
252 setFields( fieldList );
253 selectRow( mCurrentRow - 1 );
257 connect( mFieldDownBtn, &QPushButton::clicked,
this, [ = ]
259 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow + 1 ) )
262 for (
int i = 0; i < fields().count(); ++i )
264 if ( i == mCurrentRow )
266 fieldList.
append( fields().at( mCurrentRow + 1 ) );
267 fieldList.
append( fields().at( mCurrentRow ) );
269 else if ( i != mCurrentRow + 1 )
271 fieldList.
append( fields().at( i ) );
274 setFields( fieldList );
275 selectRow( mCurrentRow + 1 );
285 mSchemaCbo->setCurrentText( name );
290 mTableName->setText( name );
295 mGeomTypeCbo->setCurrentIndex( mGeomTypeCbo->findData(
static_cast< quint32
>( type ) ) );
310 return mTableName->text();
315 return mSchemaCbo->currentText();
320 return mGeomColumn->text();
325 return mFieldModel ? mFieldModel->fields() :
QgsFields();
331 if ( mHasMChk->isChecked() )
335 if ( mHasZChk->isChecked() )
347 mFieldModel->setFields(
fields );
353 return mSpatialIndexChk->isChecked();
358 return mValidationErrors;
361void QgsNewVectorTableDialog::updateButtons()
363 mDeleteFieldBtn->setEnabled( mCurrentRow != -1 );
364 mFieldUpBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != 0 );
365 mFieldDownBtn->setEnabled( mCurrentRow != -1 && mCurrentRow !=
fields().count() - 1 );
368void QgsNewVectorTableDialog::selectRow(
int row )
370 QModelIndex index { mFieldsTableView->model()->index( row, 0 ) };
371 mFieldsTableView->setCurrentIndex( index );
372 QItemSelectionModel::SelectionFlags flags { QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current };
373 mFieldsTableView->selectionModel()->select( index, flags );
374 mFieldsTableView->scrollTo( index );
377void QgsNewVectorTableDialog::validate()
379 mValidationErrors.clear();
381 const bool isSpatial { mGeomTypeCbo->currentIndex() > 0 };
382 if ( mTableName->text().trimmed().isEmpty() )
384 mValidationErrors.push_back( tr(
"Table name cannot be empty" ) );
386 else if ( mTableNames.contains( mTableName->text(), Qt::CaseSensitivity::CaseInsensitive ) )
388 mValidationErrors.push_back( tr(
"Table <b>%1</b> already exists" ).arg( mTableName->text() ) );
391 if ( isSpatial &&
fields().names().contains( mGeomColumn->text(), Qt::CaseSensitivity::CaseInsensitive ) )
393 mValidationErrors.push_back( tr(
"Geometry column name <b>%1</b> cannot be equal to an existing field name" ).arg( mGeomColumn->text() ) );
396 if ( ! isSpatial &&
fields().count() == 0 )
398 mValidationErrors.push_back( tr(
"The table has no geometry column and no fields" ) );
404 if ( f.isNumeric() && f.length() >= 0 && f.precision() >= 0 && f.precision() > f.length() )
406 mValidationErrors.push_back( tr(
"Field <b>%1</b>: precision cannot be greater than length" ).arg( f.name() ) );
409 if ( f.name().trimmed().isEmpty() )
411 mValidationErrors.push_back( tr(
"Field name cannot be empty" ) );
415 for (
const QString &illegalName : std::as_const( mIllegalFieldNames ) )
417 if ( f.name().compare( illegalName, Qt::CaseInsensitive ) == 0 )
419 mValidationErrors.push_back( tr(
"<b>%1</b> is an illegal field name for this format and cannot be used" ).arg( f.name() ) );
425 const bool isValid { mValidationErrors.isEmpty() };
428 mValidationResults->setText( mValidationErrors.join( QLatin1String(
"<br>" ) ) );
431 mValidationFrame->setVisible( ! isValid );
432 mButtonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( isValid );
437 QDialog::showEvent( event );
438 mTableName->setFocus();
439 mTableName->selectAll();
446QgsNewVectorTableDialogFieldsDelegate::QgsNewVectorTableDialogFieldsDelegate(
const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
447 : QStyledItemDelegate( parent )
448 , mTypeList( typeList )
453QWidget *QgsNewVectorTableDialogFieldsDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index )
const
455 switch ( index.column() )
457 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
459 QComboBox *cbo =
new QComboBox { parent };
460 cbo->setEditable(
false );
461 cbo->setFrame(
false );
462 connect( cbo, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged );
463 for (
const auto &f : std::as_const( mTypeList ) )
469 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
471 QSpinBox *sp {
new QSpinBox { parent } };
472 const QgsNewVectorTableFieldModel *model {
static_cast<const QgsNewVectorTableFieldModel *
>( index.model() )};
476 sp->setRange( nt.mMinPrec, std::min<int>( nt.mMaxPrec, index.model()->data( index.model()->index( index.row(), index.column() - 1 ) ).toInt() ) );
480 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
482 QSpinBox *sp {
new QSpinBox { parent } };
483 const QgsNewVectorTableFieldModel *model {
static_cast<const QgsNewVectorTableFieldModel *
>( index.model() )};
487 sp->setRange( std::max<int>( nt.mMinLen, index.model()->data( index.model()->index( index.row(), index.column() + 1 ) ).toInt() ), nt.mMaxLen );
493 return QStyledItemDelegate::createEditor( parent, option, index );
498void QgsNewVectorTableDialogFieldsDelegate::setEditorData( QWidget *editor,
const QModelIndex &index )
const
500 const auto m { index.model() };
501 switch ( index.column() )
503 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
505 const QString txt = m->data( index, Qt::DisplayRole ).toString();
506 QComboBox *cbo{ qobject_cast<QComboBox *>( editor ) };
509 cbo->setCurrentIndex( cbo->findText( txt ) );
513 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
514 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
516 const int value = m->data( index, Qt::DisplayRole ).toInt();
517 QSpinBox *sp{ qobject_cast<QSpinBox *>( editor ) };
520 sp->setValue( value );
526 QStyledItemDelegate::setEditorData( editor, index );
531void QgsNewVectorTableDialogFieldsDelegate::setModelData( QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index )
const
533 switch ( index.column() )
535 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
537 QComboBox *cbo { qobject_cast<QComboBox *>( editor ) };
540 model->setData( index, cbo->currentData() );
546 QStyledItemDelegate::setModelData( editor, model, index );
551void QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged(
int index )
554 QComboBox *cb =
static_cast<QComboBox *
>( sender() );
557 emit commitData( cb );
561QgsNewVectorTableFieldModel::QgsNewVectorTableFieldModel(
const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
563 , mNativeTypes( typeList )
568int QgsNewVectorTableFieldModel::columnCount(
const QModelIndex & )
const
573QVariant QgsNewVectorTableFieldModel::data(
const QModelIndex &index,
int role )
const
575 if ( mFields.exists( index.row() ) )
577 const QgsField field { mFields.at( index.row() ) };
580 case Qt::ItemDataRole::DisplayRole:
582 switch (
static_cast<ColumnHeaders
>( index.column() ) )
584 case ColumnHeaders::Name:
588 case ColumnHeaders::Type:
590 return typeDesc( field.typeName() );
592 case ColumnHeaders::ProviderType:
594 return field.typeName();
596 case ColumnHeaders::Comment:
598 return field.comment();
600 case ColumnHeaders::Precision:
602 return field.precision();
604 case ColumnHeaders::Length:
606 return field.length();
613 case Qt::ItemDataRole::TextAlignmentRole:
615 switch (
static_cast<ColumnHeaders
>( index.column() ) )
617 case ColumnHeaders::Precision:
618 case ColumnHeaders::Length:
620 return static_cast<Qt::Alignment::Int
>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignHCenter );
629 if (
static_cast<ColumnHeaders
>( index.column() ) == ColumnHeaders::Name )
639QVariant QgsNewVectorTableFieldModel::headerData(
int section, Qt::Orientation orientation,
int role )
const
641 if ( orientation == Qt::Orientation::Horizontal )
645 case Qt::ItemDataRole::DisplayRole:
647 switch (
static_cast<ColumnHeaders
>( section ) )
649 case ColumnHeaders::Name:
653 case ColumnHeaders::Type:
657 case ColumnHeaders::Comment:
659 return tr(
"Comment" );
661 case ColumnHeaders::ProviderType:
663 return tr(
"Provider type" );
665 case ColumnHeaders::Length:
667 return tr(
"Length" );
669 case ColumnHeaders::Precision:
671 return tr(
"Precision" );
678 case Qt::ItemDataRole::TextAlignmentRole:
680 switch (
static_cast<ColumnHeaders
>( section ) )
682 case ColumnHeaders::Name:
683 case ColumnHeaders::Comment:
684 case ColumnHeaders::Type:
685 case ColumnHeaders::ProviderType:
687 return static_cast<Qt::Alignment::Int
>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignLeft );
691 return static_cast<Qt::Alignment::Int
>( Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignHCenter );
698 QgsFieldModel::headerData( section, orientation, role );
705Qt::ItemFlags QgsNewVectorTableFieldModel::flags(
const QModelIndex &index )
const
707 switch (
static_cast<ColumnHeaders
>( index.column() ) )
709 case ColumnHeaders::Name:
710 case ColumnHeaders::Comment:
711 case ColumnHeaders::Type:
713 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
715 case ColumnHeaders::Length:
717 if ( mFields.exists( index.row( ) ) )
720 if ( nt.mMinLen < nt.mMaxLen )
722 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
727 case ColumnHeaders::Precision:
729 if ( mFields.exists( index.row( ) ) )
732 if ( nt.mMinPrec < nt.mMaxPrec )
734 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
739 case ColumnHeaders::ProviderType:
741 return QgsFieldModel::flags( index );
744 return QgsFieldModel::flags( index );
747QList<QgsVectorDataProvider::NativeType> QgsNewVectorTableFieldModel::nativeTypes()
const
752QString QgsNewVectorTableFieldModel::typeDesc(
const QString &
typeName )
const
754 for (
const auto &t : std::as_const( mNativeTypes ) )
756 if ( t.mTypeName.compare(
typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
764QMetaType::Type QgsNewVectorTableFieldModel::type(
const QString &
typeName )
const
766 return nativeType(
typeName ).mType;
771 for (
const auto &t : std::as_const( mNativeTypes ) )
773 if ( t.mTypeName.compare(
typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
780 return mNativeTypes.first();
785 if ( mFields.exists( row ) )
787 return nativeType( mFields.at( row ).typeName() );
790 QgsDebugError( QStringLiteral(
"Cannot get field for row: %1" ).arg( row ) );
791 return mNativeTypes.first();
794bool QgsNewVectorTableFieldModel::setData(
const QModelIndex &index,
const QVariant &value,
int role )
796 if ( role == Qt::ItemDataRole::EditRole && mFields.exists( index.row() ) && index.column() < 6 )
798 const int fieldIdx { index.row() };
799 QgsField field {mFields.at( fieldIdx )};
800 switch (
static_cast<ColumnHeaders
>( index.column() ) )
802 case ColumnHeaders::Name:
804 field.
setName( value.toString() );
807 case ColumnHeaders::Type:
809 field.setTypeName( value.toString() );
810 const auto tp { nativeType( value.toString() ) };
811 field.setType( tp.mType );
812 field.setLength( std::max( std::min<int>( field.length(), tp.mMaxLen ), tp.mMinLen ) );
813 field.setPrecision( std::max( std::min<int>( field.precision(), tp.mMaxPrec ), tp.mMinPrec ) );
816 case ColumnHeaders::Comment:
818 field.setComment( value.toString() );
821 case ColumnHeaders::ProviderType:
823 field.setTypeName( value.toString() );
826 case ColumnHeaders::Length:
828 field.setLength( value.toInt() );
831 case ColumnHeaders::Precision:
833 field.setPrecision( value.toInt() );
839 for (
int i = 0; i < mFields.count(); ++i )
847 fields.
append( mFields.at( i ) );
852 return QgsFieldModel::setData( index, value, role );
WkbType
The WKB type describes the number of dimensions a geometry has.
@ CompoundCurve
CompoundCurve.
@ MultiPolygon
MultiPolygon.
@ MultiLineString
MultiLineString.
@ 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).
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.
void setName(const QString &name)
Set the field name.
Container of fields for a vector layer.
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
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...
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
#define Q_NOWARN_DEPRECATED_PUSH
#define QgsDebugError(str)
const QgsCoordinateReferenceSystem & crs