23 #include <QMessageBox>
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, [ = ] { 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, qgis::overload<int>::of( &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 );
141 const bool hasSinglePart { conn->
geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::SinglePart ) };
148 mGeomTypeCbo->addItem(
QgsApplication::getThemeIcon( QStringLiteral(
"mIconTableLayer.svg" ) ), tr(
"No Geometry" ), QgsWkbTypes::Type::NoGeometry );
150 addGeomItem( QgsWkbTypes::Type::Point );
151 addGeomItem( QgsWkbTypes::Type::MultiPoint );
153 addGeomItem( QgsWkbTypes::Type::LineString );
154 addGeomItem( QgsWkbTypes::Type::MultiLineString );
156 addGeomItem( QgsWkbTypes::Type::Polygon );
157 addGeomItem( QgsWkbTypes::Type::MultiPolygon );
161 addGeomItem( QgsWkbTypes::Type::CompoundCurve );
162 addGeomItem( QgsWkbTypes::Type::CurvePolygon );
163 addGeomItem( QgsWkbTypes::Type::MultiCurve );
164 addGeomItem( QgsWkbTypes::Type::MultiSurface );
167 mGeomTypeCbo->setCurrentIndex( 0 );
169 const bool hasZ { conn->
geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::Z ) };
170 const bool hasM { conn->
geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::M ) };
173 mHasMChk->setEnabled(
false );
174 mHasMChk->setChecked(
false );
178 mHasZChk->setEnabled(
false );
179 mHasZChk->setChecked(
false );
181 if ( ! hasM && ! hasM )
183 mHasZChk->setVisible(
false );
184 mHasMChk->setVisible(
false );
185 mDimensionsLabel->setVisible(
false );
188 connect( mFieldsTableView->selectionModel(), &QItemSelectionModel::selectionChanged, mFieldsTableView, [ = ](
const QItemSelection & selected,
const QItemSelection & )
190 if ( ! selected.isEmpty() )
192 mCurrentRow = selected.indexes().first().row();
198 const QVariant::Type defaultFieldType { mFieldModel->nativeTypes().first().mType };
199 const QString defaultFieldTypeName { mFieldModel->nativeTypes().first().mTypeName };
202 connect( mAddFieldBtn, &QPushButton::clicked,
this, [ = ]
205 QgsField newField { QStringLiteral(
"new_field_name" ), defaultFieldType, defaultFieldTypeName };
206 fieldList.append( newField );
207 setFields( fieldList );
208 selectRow( fieldList.count() - 1 );
211 connect( mDeleteFieldBtn, &QPushButton::clicked,
this, [ = ]
214 if ( fieldList.exists( mCurrentRow ) )
216 fieldList.
remove( mCurrentRow );
217 setFields( fieldList );
222 connect( mFieldUpBtn, &QPushButton::clicked,
this, [ = ]
224 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow - 1 ) )
227 for (
int i = 0; i < fields().count(); ++i )
229 if ( i == mCurrentRow - 1 )
231 fieldList.
append( fields().at( mCurrentRow ) );
232 fieldList.
append( fields().at( mCurrentRow - 1 ) );
234 else if ( i != mCurrentRow )
236 fieldList.
append( fields().at( i ) );
239 setFields( fieldList );
240 selectRow( mCurrentRow - 1 );
244 connect( mFieldDownBtn, &QPushButton::clicked,
this, [ = ]
246 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow + 1 ) )
249 for (
int i = 0; i < fields().count(); ++i )
251 if ( i == mCurrentRow )
253 fieldList.
append( fields().at( mCurrentRow + 1 ) );
254 fieldList.
append( fields().at( mCurrentRow ) );
256 else if ( i != mCurrentRow + 1 )
258 fieldList.
append( fields().at( i ) );
261 setFields( fieldList );
262 selectRow( mCurrentRow + 1 );
272 mSchemaCbo->setCurrentText( name );
277 mTableName->setText( name );
282 mGeomTypeCbo->setCurrentIndex( mGeomTypeCbo->findData( type ) );
297 return mTableName->text();
302 return mSchemaCbo->currentText();
307 return mGeomColumn->text();
312 return mFieldModel ? mFieldModel->fields() :
QgsFields();
318 if ( mHasMChk->isChecked() )
322 if ( mHasZChk->isChecked() )
334 mFieldModel->setFields(
fields );
340 return mSpatialIndexChk->isChecked();
345 return mValidationErrors;
348 void QgsNewVectorTableDialog::updateButtons()
350 mDeleteFieldBtn->setEnabled( mCurrentRow != -1 );
351 mFieldUpBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != 0 );
352 mFieldDownBtn->setEnabled( mCurrentRow != -1 && mCurrentRow !=
fields().count() - 1 );
355 void QgsNewVectorTableDialog::selectRow(
int row )
357 QModelIndex index { mFieldsTableView->model()->index( row, 0 ) };
358 mFieldsTableView->setCurrentIndex( index );
359 QItemSelectionModel::SelectionFlags flags { QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current };
360 mFieldsTableView->selectionModel()->select( index, flags );
361 mFieldsTableView->scrollTo( index );
364 void QgsNewVectorTableDialog::validate()
366 mValidationErrors.clear();
368 const bool isSpatial { mGeomTypeCbo->currentIndex() > 0 };
369 if ( mTableNames.contains( mTableName->text(), Qt::CaseSensitivity::CaseInsensitive ) )
371 mValidationErrors.push_back( tr(
"Table <b>%1</b> already exists!" ).arg( mTableName->text() ) );
374 if ( isSpatial &&
fields().names().contains( mGeomColumn->text(), Qt::CaseSensitivity::CaseInsensitive ) )
376 mValidationErrors.push_back( tr(
"Geometry column name <b>%1</b> cannot be equal to an existing field name!" ).arg( mGeomColumn->text() ) );
379 if ( ! isSpatial &&
fields().count() == 0 )
381 mValidationErrors.push_back( tr(
"The table has no geometry column and no fields!" ) );
384 const auto cFields {
fields() };
385 for (
const auto &f : cFields )
387 if ( f.isNumeric() && f.length() >= 0 && f.precision() >= 0 && f.precision() > f.length() )
389 mValidationErrors.push_back( tr(
"Field <b>%1</b>: precision cannot be greater than length!" ).arg( f.name() ) );
393 const bool isValid { mValidationErrors.isEmpty() };
396 mValidationResults->setText( mValidationErrors.join( QLatin1String(
"<br>" ) ) );
399 mValidationFrame->setVisible( ! isValid );
400 mButtonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( isValid );
405 QDialog::showEvent( event );
406 mTableName->setFocus();
407 mTableName->selectAll();
414 QgsNewVectorTableDialogFieldsDelegate::QgsNewVectorTableDialogFieldsDelegate(
const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
415 : QStyledItemDelegate( parent )
416 , mTypeList( typeList )
421 QWidget *QgsNewVectorTableDialogFieldsDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index )
const
423 switch ( index.column() )
425 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
427 QComboBox *cbo =
new QComboBox { parent };
428 cbo->setEditable(
false );
429 cbo->setFrame(
false );
430 connect( cbo, qgis::overload<int>::of( &QComboBox::currentIndexChanged ),
this, &QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged );
431 for (
const auto &f : qgis::as_const( mTypeList ) )
433 cbo->addItem( f.mTypeDesc, f.mTypeName );
437 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
439 QSpinBox *sp {
new QSpinBox { parent } };
440 const QgsNewVectorTableFieldModel *model {
static_cast<const QgsNewVectorTableFieldModel *
>( index.model() )};
444 sp->setRange( nt.mMinPrec, std::min<int>( nt.mMaxPrec, index.model()->data( index.model()->index( index.row(), index.column() - 1 ) ).toInt() ) );
448 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
450 QSpinBox *sp {
new QSpinBox { parent } };
451 const QgsNewVectorTableFieldModel *model {
static_cast<const QgsNewVectorTableFieldModel *
>( index.model() )};
455 sp->setRange( std::max<int>( nt.mMinLen, index.model()->data( index.model()->index( index.row(), index.column() + 1 ) ).toInt() ), nt.mMaxLen );
461 return QStyledItemDelegate::createEditor( parent, option, index );
466 void QgsNewVectorTableDialogFieldsDelegate::setEditorData( QWidget *editor,
const QModelIndex &index )
const
468 const auto m { index.model() };
469 switch ( index.column() )
471 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
473 const QString txt = m->data( index, Qt::DisplayRole ).toString();
474 QComboBox *cbo{ qobject_cast<QComboBox *>( editor ) };
477 cbo->setCurrentIndex( cbo->findText( txt ) );
481 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
482 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
484 const int value = m->data( index, Qt::DisplayRole ).toInt();
485 QSpinBox *sp{ qobject_cast<QSpinBox *>( editor ) };
488 sp->setValue( value );
494 QStyledItemDelegate::setEditorData( editor, index );
499 void QgsNewVectorTableDialogFieldsDelegate::setModelData( QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index )
const
501 switch ( index.column() )
503 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
505 QComboBox *cbo { qobject_cast<QComboBox *>( editor ) };
508 model->setData( index, cbo->currentData() );
514 QStyledItemDelegate::setModelData( editor, model, index );
519 void QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged(
int index )
522 QComboBox *cb =
static_cast<QComboBox *
>( sender() );
525 emit commitData( cb );
529 QgsNewVectorTableFieldModel::QgsNewVectorTableFieldModel(
const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
531 , mNativeTypes( typeList )
536 int QgsNewVectorTableFieldModel::columnCount(
const QModelIndex & )
const
541 QVariant QgsNewVectorTableFieldModel::data(
const QModelIndex &index,
int role )
const
543 if ( mFields.exists( index.row() ) )
548 case Qt::ItemDataRole::DisplayRole:
550 switch (
static_cast<ColumnHeaders
>( index.column() ) )
552 case ColumnHeaders::Name:
556 case ColumnHeaders::Type:
560 case ColumnHeaders::ProviderType:
564 case ColumnHeaders::Comment:
568 case ColumnHeaders::Precision:
572 case ColumnHeaders::Length:
581 case Qt::ItemDataRole::TextAlignmentRole:
583 switch (
static_cast<ColumnHeaders
>( index.column() ) )
585 case ColumnHeaders::Precision:
586 case ColumnHeaders::Length:
588 return Qt::AlignmentFlag::AlignVCenter + Qt::AlignmentFlag::AlignHCenter;
597 if (
static_cast<ColumnHeaders
>( index.column() ) == ColumnHeaders::Name )
607 QVariant QgsNewVectorTableFieldModel::headerData(
int section, Qt::Orientation orientation,
int role )
const
609 if ( orientation == Qt::Orientation::Horizontal )
613 case Qt::ItemDataRole::DisplayRole:
615 switch (
static_cast<ColumnHeaders
>( section ) )
617 case ColumnHeaders::Name:
621 case ColumnHeaders::Type:
625 case ColumnHeaders::Comment:
627 return tr(
"Comment" );
629 case ColumnHeaders::ProviderType:
631 return tr(
"Provider type" );
633 case ColumnHeaders::Length:
635 return tr(
"Length" );
637 case ColumnHeaders::Precision:
639 return tr(
"Precision" );
646 case Qt::ItemDataRole::TextAlignmentRole:
648 switch (
static_cast<ColumnHeaders
>( section ) )
650 case ColumnHeaders::Name:
651 case ColumnHeaders::Comment:
652 case ColumnHeaders::Type:
653 case ColumnHeaders::ProviderType:
655 return Qt::AlignmentFlag::AlignVCenter + Qt::AlignmentFlag::AlignLeft;
659 return Qt::AlignmentFlag::AlignVCenter + Qt::AlignmentFlag::AlignHCenter;
666 QgsFieldModel::headerData( section, orientation, role );
673 Qt::ItemFlags QgsNewVectorTableFieldModel::flags(
const QModelIndex &index )
const
675 switch (
static_cast<ColumnHeaders
>( index.column() ) )
677 case ColumnHeaders::Name:
678 case ColumnHeaders::Comment:
679 case ColumnHeaders::Type:
681 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
683 case ColumnHeaders::Length:
685 if ( mFields.exists( index.row( ) ) )
688 if ( nt.mMinLen < nt.mMaxLen )
690 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
695 case ColumnHeaders::Precision:
697 if ( mFields.exists( index.row( ) ) )
700 if ( nt.mMinPrec < nt.mMaxPrec )
702 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
707 case ColumnHeaders::ProviderType:
709 return QgsFieldModel::flags( index );
712 return QgsFieldModel::flags( index );
715 QList<QgsVectorDataProvider::NativeType> QgsNewVectorTableFieldModel::nativeTypes()
const
720 QString QgsNewVectorTableFieldModel::typeDesc(
const QString &
typeName )
const
722 for (
const auto &t : qgis::as_const( mNativeTypes ) )
724 if ( t.mTypeName.compare(
typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
732 QVariant::Type QgsNewVectorTableFieldModel::type(
const QString &
typeName )
const
734 return nativeType(
typeName ).mType;
739 for (
const auto &t : qgis::as_const( mNativeTypes ) )
741 if ( t.mTypeName.compare(
typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
748 return mNativeTypes.first();
753 if ( mFields.exists( row ) )
755 return nativeType( mFields.at( row ).typeName() );
758 QgsDebugMsg( QStringLiteral(
"Cannot get field for row: %1" ).arg( row ) );
759 return mNativeTypes.first();
762 bool QgsNewVectorTableFieldModel::setData(
const QModelIndex &index,
const QVariant &value,
int role )
764 if ( role == Qt::ItemDataRole::EditRole && mFields.exists( index.row() ) && index.column() < 6 )
766 const int fieldIdx { index.row() };
768 switch (
static_cast<ColumnHeaders
>( index.column() ) )
770 case ColumnHeaders::Name:
775 case ColumnHeaders::Type:
778 const auto tp { nativeType( value.toString() ) };
784 case ColumnHeaders::Comment:
789 case ColumnHeaders::ProviderType:
794 case ColumnHeaders::Length:
799 case ColumnHeaders::Precision:
807 for (
int i = 0; i < mFields.count(); ++i )
815 fields.
append( mFields.at( i ) );
820 return QgsFieldModel::setData( index, value, role );
The QgsAbstractDatabaseProviderConnection class provides common functionality for DB based connection...
virtual GeometryColumnCapabilities geometryColumnCapabilities()
Returns connection geomerty 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)
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)
void remove(int fieldIdx)
Removes a 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.
const QgsCoordinateReferenceSystem & crs