23 #include <QMessageBox>
24 #include <QPushButton>
25 #include <QStandardItemModel>
26 #include <QToolButton>
36 : QAbstractTableModel( parent )
37 , mExpressionContextGenerator( new
QgsFieldMappingModel::ExpressionContextGenerator( sourceFields ) )
44 if ( role == Qt::DisplayRole )
46 switch ( orientation )
54 return tr(
"Source Expression" );
58 return tr(
"Aggregate Function" );
62 return tr(
"Delimiter" );
74 return tr(
"Length" );
78 return tr(
"Precision" );
99 if ( parent.isValid() )
101 return mMapping.count();
106 if ( parent.isValid() )
113 if ( index.isValid() )
116 const Aggregate &agg { mMapping.at( index.row() ) };
120 case Qt::DisplayRole:
131 return agg.aggregate;
135 return agg.delimiter;
139 return agg.field.displayName();
143 return agg.field.typeName();
147 return agg.field.length();
151 return agg.field.precision();
163 if ( index.isValid() )
165 return Qt::ItemFlags( Qt::ItemIsSelectable |
169 return Qt::ItemFlags();
174 if ( index.isValid() )
176 if ( role == Qt::EditRole )
204 QgsFieldMappingModel::setFieldTypeFromName( f.
field, value.toString() );
210 const int length { value.toInt( &ok ) };
218 const int precision { value.toInt( &ok ) };
224 emit dataChanged( index, index );
235 bool QgsAggregateMappingModel::moveUpOrDown(
const QModelIndex &index,
bool up )
237 if ( ! index.isValid() && index.model() ==
this )
241 const int row { up ? index.row() - 1 : index.row() };
243 if ( row < 0 || row + 1 >=
rowCount( QModelIndex() ) )
247 beginMoveRows( QModelIndex( ), row, row, QModelIndex(), row + 2 );
248 #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
249 mMapping.swap( row, row + 1 );
251 mMapping.swapItemsAt( row, row + 1 );
260 if ( mExpressionContextGenerator )
261 mExpressionContextGenerator->setSourceFields( mSourceFields );
263 const QStringList usedFields;
271 aggregate.
field.
setTypeName( QgsFieldMappingModel::qgsFieldToTypeName( f ) );
275 aggregate.
aggregate = QStringLiteral(
"sum" );
276 else if ( f.type() == QVariant::String || ( f.type() == QVariant::List && f.subType() == QVariant::String ) )
277 aggregate.
aggregate = QStringLiteral(
"concatenate" );
281 mMapping.push_back( aggregate );
288 return mExpressionContextGenerator.get();
293 mExpressionContextGenerator->setBaseExpressionContextGenerator( generator );
305 for (
auto &agg : mMapping )
307 agg.field.setTypeName( QgsFieldMappingModel::qgsFieldToTypeName( agg.field ) );
314 const int lastRow {
rowCount( QModelIndex( ) ) };
315 beginInsertRows( QModelIndex(), lastRow, lastRow );
322 mMapping.push_back( agg );
328 if ( index.isValid() && index.model() ==
this && index.row() <
rowCount( QModelIndex() ) )
330 beginRemoveRows( QModelIndex(), index.row(), index.row() );
331 mMapping.removeAt( index.row() );
343 return moveUpOrDown( index );
348 return moveUpOrDown( index,
false );
360 QVBoxLayout *verticalLayout =
new QVBoxLayout();
361 verticalLayout->setContentsMargins( 0, 0, 0, 0 );
362 mTableView =
new QTableView();
363 verticalLayout->addWidget( mTableView );
364 setLayout( verticalLayout );
367 mTableView->setModel( mModel );
373 connect( mModel, &QgsAggregateMappingModel::rowsInserted,
this, [ = ] { updateColumns(); } );
374 connect( mModel, &QgsAggregateMappingModel::modelReset,
this, [ = ] { updateColumns(); } );
383 return qobject_cast<QgsAggregateMappingModel *>( mModel );
398 return mTableView->selectionModel();
408 mSourceLayer = layer;
418 mTableView->scrollTo( index );
433 if ( ! mTableView->selectionModel()->hasSelection() )
436 std::list<int> rowsToRemove { selectedRows() };
437 rowsToRemove.reverse();
438 for (
const int row : rowsToRemove )
440 if ( !
model()->removeField(
model()->index( row, 0, QModelIndex() ) ) )
450 if ( ! mTableView->selectionModel()->hasSelection() )
453 const std::list<int> rowsToMoveUp { selectedRows() };
454 for (
const int row : rowsToMoveUp )
456 if ( !
model()->moveUp(
model()->index( row, 0, QModelIndex() ) ) )
466 if ( ! mTableView->selectionModel()->hasSelection() )
469 std::list<int> rowsToMoveDown { selectedRows() };
470 rowsToMoveDown.reverse();
471 for (
const int row : rowsToMoveDown )
473 if ( !
model()->moveDown(
model()->index( row, 0, QModelIndex() ) ) )
481 void QgsAggregateMappingWidget::updateColumns()
483 for (
int i = 0; i < mModel->rowCount(); ++i )
490 for (
int i = 0; i < mModel->columnCount(); ++i )
492 mTableView->resizeColumnToContents( i );
496 std::list<int> QgsAggregateMappingWidget::selectedRows()
499 if ( mTableView->selectionModel()->hasSelection() )
501 const QModelIndexList constSelection { mTableView->selectionModel()->selectedIndexes() };
502 for (
const QModelIndex &index : constSelection )
504 rows.push_back( index.row() );
518 QgsAggregateMappingWidget::AggregateDelegate::AggregateDelegate( QObject *parent )
519 : QStyledItemDelegate( parent )
523 QWidget *QgsAggregateMappingWidget::AggregateDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex & )
const
526 QComboBox *editor =
new QComboBox( parent );
528 const QStringList aggregateList { QgsAggregateMappingWidget::AggregateDelegate::aggregates() };
530 for (
const QString &aggregate : aggregateList )
532 editor->addItem( aggregate );
533 editor->setItemData( i, aggregate, Qt::UserRole );
538 qOverload<int >( &QComboBox::currentIndexChanged ),
540 [ = ](
int currentIndex )
542 Q_UNUSED( currentIndex )
543 const_cast< QgsAggregateMappingWidget::AggregateDelegate *
>( this )->emit commitData( editor );
549 void QgsAggregateMappingWidget::AggregateDelegate::setEditorData( QWidget *editor,
const QModelIndex &index )
const
551 QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
552 if ( ! editorWidget )
555 const QVariant value = index.model()->data( index, Qt::EditRole );
556 editorWidget->setCurrentIndex( editorWidget->findData( value ) );
559 void QgsAggregateMappingWidget::AggregateDelegate::setModelData( QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index )
const
561 QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
562 if ( ! editorWidget )
565 const QVariant currentValue = editorWidget->currentData( );
566 model->setData( index, currentValue, Qt::EditRole );
569 const QStringList QgsAggregateMappingWidget::AggregateDelegate::aggregates()
571 static QStringList sAggregates;
572 static std::once_flag initialized;
573 std::call_once( initialized, [ = ]( )
575 sAggregates << QStringLiteral(
"first_value" )
576 << QStringLiteral(
"last_value" );
581 if ( !
function || function->isDeprecated() || function->name().isEmpty() || function->name().at( 0 ) ==
'_' )
584 if ( function->groups().contains( QLatin1String(
"Aggregates" ) ) )
586 if ( function->name() == QLatin1String(
"aggregate" )
587 || function->name() == QLatin1String(
"relation_aggregate" ) )
590 sAggregates.append( function->name() );
593 std::sort( sAggregates.begin(), sAggregates.end() );
The QgsAggregateMappingModel holds mapping information for defining sets of aggregates of fields from...
QgsFields sourceFields() const
Returns a list of source fields.
void appendField(const QgsField &field, const QString &source=QString(), const QString &aggregate=QString())
Appends a new field to the model, with an optional source and aggregate.
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
ColumnDataIndex
The ColumnDataIndex enum represents the column index for the view.
@ Aggregate
Aggregate name.
@ SourceExpression
Expression.
@ DestinationPrecision
Destination field precision.
@ DestinationName
Destination field name.
@ DestinationType
Destination field type string.
@ DestinationLength
Destination field length.
Qt::ItemFlags flags(const QModelIndex &index) const override
bool removeField(const QModelIndex &index)
Removes the field at index from the model, returns true on success.
bool moveUp(const QModelIndex &index)
Moves down the field at index.
QVariant data(const QModelIndex &index, int role) const override
QList< QgsAggregateMappingModel::Aggregate > mapping() const
Returns a list of Aggregate objects representing the current status of the model.
bool setData(const QModelIndex &index, const QVariant &value, int role) override
QgsExpressionContextGenerator * contextGenerator() const
Returns the context generator with the source fields.
bool moveDown(const QModelIndex &index)
Moves up the field at index.
void setSourceFields(const QgsFields &sourceFields)
Set source fields to sourceFields.
void setMapping(const QList< QgsAggregateMappingModel::Aggregate > &mapping)
Sets the mapping to show in the model.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void setBaseExpressionContextGenerator(const QgsExpressionContextGenerator *generator)
Sets the base expression context generator, which will generate the expression contexts for expressio...
QgsAggregateMappingModel(const QgsFields &sourceFields=QgsFields(), QObject *parent=nullptr)
Constructs a QgsAggregateMappingModel from a set of sourceFields.
Abstract interface for generating an expression context.
A abstract base class for defining QgsExpression functions.
Class for parsing and evaluation of expressions (formerly called "search strings").
static const QList< QgsExpressionFunction * > & Functions()
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
The QgsFieldMappingModel holds mapping information for mapping from one set of QgsFields to another,...
Encapsulate a field in an attribute table or data source.
void setPrecision(int precision)
Set the field precision.
void setName(const QString &name)
Set the field name.
void setLength(int len)
Set the field length.
void setTypeName(const QString &typeName)
Set the field type.
Container of fields for a vector layer.
Represents a vector layer which manages a vector based data sets.
The Aggregate struct holds information about an aggregate column.
QString source
The source expression used as the input for the aggregate calculation.
QString delimiter
Delimiter string.
QString aggregate
Aggregate name.
QgsField field
The field in its current status (it might have been renamed)