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, 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 );
143 const bool hasSinglePart { conn->
geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::SinglePart ) };
150 mGeomTypeCbo->addItem(
QgsApplication::getThemeIcon( QStringLiteral(
"mIconTableLayer.svg" ) ), tr(
"No Geometry" ), QgsWkbTypes::Type::NoGeometry );
152 addGeomItem( QgsWkbTypes::Type::Point );
153 addGeomItem( QgsWkbTypes::Type::MultiPoint );
155 addGeomItem( QgsWkbTypes::Type::LineString );
156 addGeomItem( QgsWkbTypes::Type::MultiLineString );
158 addGeomItem( QgsWkbTypes::Type::Polygon );
159 addGeomItem( QgsWkbTypes::Type::MultiPolygon );
163 addGeomItem( QgsWkbTypes::Type::CompoundCurve );
164 addGeomItem( QgsWkbTypes::Type::CurvePolygon );
165 addGeomItem( QgsWkbTypes::Type::MultiCurve );
166 addGeomItem( QgsWkbTypes::Type::MultiSurface );
169 mGeomTypeCbo->setCurrentIndex( 0 );
171 const bool hasZ { conn->
geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::Z ) };
172 const bool hasM { conn->
geometryColumnCapabilities().testFlag( QgsAbstractDatabaseProviderConnection::GeometryColumnCapability::M ) };
175 mHasMChk->setEnabled(
false );
176 mHasMChk->setChecked(
false );
180 mHasZChk->setEnabled(
false );
181 mHasZChk->setChecked(
false );
183 if ( ! hasM && ! hasM )
185 mHasZChk->setVisible(
false );
186 mHasMChk->setVisible(
false );
187 mDimensionsLabel->setVisible(
false );
190 connect( mFieldsTableView->selectionModel(), &QItemSelectionModel::selectionChanged, mFieldsTableView, [ = ](
const QItemSelection & selected,
const QItemSelection & )
192 if ( ! selected.isEmpty() )
194 mCurrentRow = selected.indexes().first().row();
200 const QVariant::Type defaultFieldType { mFieldModel->nativeTypes().first().mType };
201 const QString defaultFieldTypeName { mFieldModel->nativeTypes().first().mTypeName };
204 connect( mAddFieldBtn, &QPushButton::clicked,
this, [ = ]
207 QgsField newField { QStringLiteral(
"new_field_name" ), defaultFieldType, defaultFieldTypeName };
208 fieldList.append( newField );
209 setFields( fieldList );
210 selectRow( fieldList.count() - 1 );
213 connect( mDeleteFieldBtn, &QPushButton::clicked,
this, [ = ]
216 if ( fieldList.exists( mCurrentRow ) )
218 fieldList.
remove( mCurrentRow );
219 setFields( fieldList );
224 connect( mFieldUpBtn, &QPushButton::clicked,
this, [ = ]
226 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow - 1 ) )
229 for (
int i = 0; i < fields().count(); ++i )
231 if ( i == mCurrentRow - 1 )
233 fieldList.
append( fields().at( mCurrentRow ) );
234 fieldList.
append( fields().at( mCurrentRow - 1 ) );
236 else if ( i != mCurrentRow )
238 fieldList.
append( fields().at( i ) );
241 setFields( fieldList );
242 selectRow( mCurrentRow - 1 );
246 connect( mFieldDownBtn, &QPushButton::clicked,
this, [ = ]
248 if ( fields().exists( mCurrentRow ) && fields().exists( mCurrentRow + 1 ) )
251 for (
int i = 0; i < fields().count(); ++i )
253 if ( i == mCurrentRow )
255 fieldList.
append( fields().at( mCurrentRow + 1 ) );
256 fieldList.
append( fields().at( mCurrentRow ) );
258 else if ( i != mCurrentRow + 1 )
260 fieldList.
append( fields().at( i ) );
263 setFields( fieldList );
264 selectRow( mCurrentRow + 1 );
274 mSchemaCbo->setCurrentText( name );
279 mTableName->setText( name );
284 mGeomTypeCbo->setCurrentIndex( mGeomTypeCbo->findData( type ) );
299 return mTableName->text();
304 return mSchemaCbo->currentText();
309 return mGeomColumn->text();
314 return mFieldModel ? mFieldModel->fields() :
QgsFields();
320 if ( mHasMChk->isChecked() )
324 if ( mHasZChk->isChecked() )
336 mFieldModel->setFields(
fields );
342 return mSpatialIndexChk->isChecked();
347 return mValidationErrors;
350 void QgsNewVectorTableDialog::updateButtons()
352 mDeleteFieldBtn->setEnabled( mCurrentRow != -1 );
353 mFieldUpBtn->setEnabled( mCurrentRow != -1 && mCurrentRow != 0 );
354 mFieldDownBtn->setEnabled( mCurrentRow != -1 && mCurrentRow !=
fields().count() - 1 );
357 void QgsNewVectorTableDialog::selectRow(
int row )
359 QModelIndex index { mFieldsTableView->model()->index( row, 0 ) };
360 mFieldsTableView->setCurrentIndex( index );
361 QItemSelectionModel::SelectionFlags flags { QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current };
362 mFieldsTableView->selectionModel()->select( index, flags );
363 mFieldsTableView->scrollTo( index );
366 void QgsNewVectorTableDialog::validate()
368 mValidationErrors.clear();
370 const bool isSpatial { mGeomTypeCbo->currentIndex() > 0 };
371 if ( mTableNames.contains( mTableName->text(), Qt::CaseSensitivity::CaseInsensitive ) )
373 mValidationErrors.push_back( tr(
"Table <b>%1</b> already exists!" ).arg( mTableName->text() ) );
376 if ( isSpatial &&
fields().names().contains( mGeomColumn->text(), Qt::CaseSensitivity::CaseInsensitive ) )
378 mValidationErrors.push_back( tr(
"Geometry column name <b>%1</b> cannot be equal to an existing field name!" ).arg( mGeomColumn->text() ) );
381 if ( ! isSpatial &&
fields().count() == 0 )
383 mValidationErrors.push_back( tr(
"The table has no geometry column and no fields!" ) );
386 const auto cFields {
fields() };
387 for (
const auto &f : cFields )
389 if ( f.isNumeric() && f.length() >= 0 && f.precision() >= 0 && f.precision() > f.length() )
391 mValidationErrors.push_back( tr(
"Field <b>%1</b>: precision cannot be greater than length!" ).arg( f.name() ) );
395 const bool isValid { mValidationErrors.isEmpty() };
398 mValidationResults->setText( mValidationErrors.join( QLatin1String(
"<br>" ) ) );
401 mValidationFrame->setVisible( ! isValid );
402 mButtonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( isValid );
407 QDialog::showEvent( event );
408 mTableName->setFocus();
409 mTableName->selectAll();
416 QgsNewVectorTableDialogFieldsDelegate::QgsNewVectorTableDialogFieldsDelegate(
const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
417 : QStyledItemDelegate( parent )
418 , mTypeList( typeList )
423 QWidget *QgsNewVectorTableDialogFieldsDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index )
const
425 switch ( index.column() )
427 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
429 QComboBox *cbo =
new QComboBox { parent };
430 cbo->setEditable(
false );
431 cbo->setFrame(
false );
432 connect( cbo, qOverload<int>( &QComboBox::currentIndexChanged ),
this, &QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged );
433 for (
const auto &f : std::as_const( mTypeList ) )
435 cbo->addItem( f.mTypeDesc, f.mTypeName );
439 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
441 QSpinBox *sp {
new QSpinBox { parent } };
442 const QgsNewVectorTableFieldModel *model {
static_cast<const QgsNewVectorTableFieldModel *
>( index.model() )};
446 sp->setRange( nt.mMinPrec, std::min<int>( nt.mMaxPrec, index.model()->data( index.model()->index( index.row(), index.column() - 1 ) ).toInt() ) );
450 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
452 QSpinBox *sp {
new QSpinBox { parent } };
453 const QgsNewVectorTableFieldModel *model {
static_cast<const QgsNewVectorTableFieldModel *
>( index.model() )};
457 sp->setRange( std::max<int>( nt.mMinLen, index.model()->data( index.model()->index( index.row(), index.column() + 1 ) ).toInt() ), nt.mMaxLen );
463 return QStyledItemDelegate::createEditor( parent, option, index );
468 void QgsNewVectorTableDialogFieldsDelegate::setEditorData( QWidget *editor,
const QModelIndex &index )
const
470 const auto m { index.model() };
471 switch ( index.column() )
473 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
475 const QString txt = m->data( index, Qt::DisplayRole ).toString();
476 QComboBox *cbo{ qobject_cast<QComboBox *>( editor ) };
479 cbo->setCurrentIndex( cbo->findText( txt ) );
483 case QgsNewVectorTableFieldModel::ColumnHeaders::Precision:
484 case QgsNewVectorTableFieldModel::ColumnHeaders::Length:
486 const int value = m->data( index, Qt::DisplayRole ).toInt();
487 QSpinBox *sp{ qobject_cast<QSpinBox *>( editor ) };
490 sp->setValue( value );
496 QStyledItemDelegate::setEditorData( editor, index );
501 void QgsNewVectorTableDialogFieldsDelegate::setModelData( QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index )
const
503 switch ( index.column() )
505 case QgsNewVectorTableFieldModel::ColumnHeaders::Type:
507 QComboBox *cbo { qobject_cast<QComboBox *>( editor ) };
510 model->setData( index, cbo->currentData() );
516 QStyledItemDelegate::setModelData( editor, model, index );
521 void QgsNewVectorTableDialogFieldsDelegate::onFieldTypeChanged(
int index )
524 QComboBox *cb =
static_cast<QComboBox *
>( sender() );
527 emit commitData( cb );
531 QgsNewVectorTableFieldModel::QgsNewVectorTableFieldModel(
const QList<QgsVectorDataProvider::NativeType> &typeList, QObject *parent )
533 , mNativeTypes( typeList )
538 int QgsNewVectorTableFieldModel::columnCount(
const QModelIndex & )
const
543 QVariant QgsNewVectorTableFieldModel::data(
const QModelIndex &index,
int role )
const
545 if ( mFields.exists( index.row() ) )
550 case Qt::ItemDataRole::DisplayRole:
552 switch (
static_cast<ColumnHeaders
>( index.column() ) )
554 case ColumnHeaders::Name:
558 case ColumnHeaders::Type:
562 case ColumnHeaders::ProviderType:
566 case ColumnHeaders::Comment:
570 case ColumnHeaders::Precision:
574 case ColumnHeaders::Length:
583 case Qt::ItemDataRole::TextAlignmentRole:
585 switch (
static_cast<ColumnHeaders
>( index.column() ) )
587 case ColumnHeaders::Precision:
588 case ColumnHeaders::Length:
590 return Qt::AlignmentFlag::AlignVCenter + Qt::AlignmentFlag::AlignHCenter;
599 if (
static_cast<ColumnHeaders
>( index.column() ) == ColumnHeaders::Name )
609 QVariant QgsNewVectorTableFieldModel::headerData(
int section, Qt::Orientation orientation,
int role )
const
611 if ( orientation == Qt::Orientation::Horizontal )
615 case Qt::ItemDataRole::DisplayRole:
617 switch (
static_cast<ColumnHeaders
>( section ) )
619 case ColumnHeaders::Name:
623 case ColumnHeaders::Type:
627 case ColumnHeaders::Comment:
629 return tr(
"Comment" );
631 case ColumnHeaders::ProviderType:
633 return tr(
"Provider type" );
635 case ColumnHeaders::Length:
637 return tr(
"Length" );
639 case ColumnHeaders::Precision:
641 return tr(
"Precision" );
648 case Qt::ItemDataRole::TextAlignmentRole:
650 switch (
static_cast<ColumnHeaders
>( section ) )
652 case ColumnHeaders::Name:
653 case ColumnHeaders::Comment:
654 case ColumnHeaders::Type:
655 case ColumnHeaders::ProviderType:
657 return Qt::AlignmentFlag::AlignVCenter + Qt::AlignmentFlag::AlignLeft;
661 return Qt::AlignmentFlag::AlignVCenter + Qt::AlignmentFlag::AlignHCenter;
668 QgsFieldModel::headerData( section, orientation, role );
675 Qt::ItemFlags QgsNewVectorTableFieldModel::flags(
const QModelIndex &index )
const
677 switch (
static_cast<ColumnHeaders
>( index.column() ) )
679 case ColumnHeaders::Name:
680 case ColumnHeaders::Comment:
681 case ColumnHeaders::Type:
683 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
685 case ColumnHeaders::Length:
687 if ( mFields.exists( index.row( ) ) )
690 if ( nt.mMinLen < nt.mMaxLen )
692 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
697 case ColumnHeaders::Precision:
699 if ( mFields.exists( index.row( ) ) )
702 if ( nt.mMinPrec < nt.mMaxPrec )
704 return QgsFieldModel::flags( index ) | Qt::ItemIsEditable;
709 case ColumnHeaders::ProviderType:
711 return QgsFieldModel::flags( index );
714 return QgsFieldModel::flags( index );
717 QList<QgsVectorDataProvider::NativeType> QgsNewVectorTableFieldModel::nativeTypes()
const
722 QString QgsNewVectorTableFieldModel::typeDesc(
const QString &
typeName )
const
724 for (
const auto &t : std::as_const( mNativeTypes ) )
726 if ( t.mTypeName.compare(
typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
734 QVariant::Type QgsNewVectorTableFieldModel::type(
const QString &
typeName )
const
736 return nativeType(
typeName ).mType;
741 for (
const auto &t : std::as_const( mNativeTypes ) )
743 if ( t.mTypeName.compare(
typeName, Qt::CaseSensitivity::CaseInsensitive ) == 0 )
750 return mNativeTypes.first();
755 if ( mFields.exists( row ) )
757 return nativeType( mFields.at( row ).typeName() );
760 QgsDebugMsg( QStringLiteral(
"Cannot get field for row: %1" ).arg( row ) );
761 return mNativeTypes.first();
764 bool QgsNewVectorTableFieldModel::setData(
const QModelIndex &index,
const QVariant &value,
int role )
766 if ( role == Qt::ItemDataRole::EditRole && mFields.exists( index.row() ) && index.column() < 6 )
768 const int fieldIdx { index.row() };
770 switch (
static_cast<ColumnHeaders
>( index.column() ) )
772 case ColumnHeaders::Name:
777 case ColumnHeaders::Type:
780 const auto tp { nativeType( value.toString() ) };
786 case ColumnHeaders::Comment:
791 case ColumnHeaders::ProviderType:
796 case ColumnHeaders::Length:
801 case ColumnHeaders::Precision:
809 for (
int i = 0; i < mFields.count(); ++i )
817 fields.
append( mFields.at( i ) );
822 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, 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)
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.
const QgsCoordinateReferenceSystem & crs