17#include "moc_qgsprocessingaggregatewidgets.cpp"
26#include <QStandardItemModel>
37 : QAbstractTableModel( parent )
38 , mExpressionContextGenerator( new
QgsFieldMappingModel::ExpressionContextGenerator( sourceFields ) )
45 if ( role == Qt::DisplayRole )
47 switch ( orientation )
55 return tr(
"Source Expression" );
59 return tr(
"Aggregate Function" );
63 return tr(
"Delimiter" );
75 return tr(
"Length" );
79 return tr(
"Precision" );
100 if ( parent.isValid() )
102 return mMapping.count();
107 if ( parent.isValid() )
114 if ( index.isValid() )
117 const Aggregate &agg { mMapping.at( index.row() ) };
121 case Qt::DisplayRole:
132 return agg.aggregate;
136 return agg.delimiter;
140 return agg.field.displayName();
144 return agg.field.typeName();
148 return agg.field.length();
152 return agg.field.precision();
164 if ( index.isValid() )
166 return Qt::ItemFlags( Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled );
168 return Qt::ItemFlags();
173 if ( index.isValid() )
175 if ( role == Qt::EditRole )
203 setFieldTypeFromName( f.
field, value.toString() );
209 const int length { value.toInt( &ok ) };
217 const int precision { value.toInt( &ok ) };
223 emit dataChanged( index, index );
234bool QgsAggregateMappingModel::moveUpOrDown(
const QModelIndex &index,
bool up )
236 if ( !index.isValid() && index.model() ==
this )
240 const int row { up ? index.row() - 1 : index.row() };
242 if ( row < 0 || row + 1 >=
rowCount( QModelIndex() ) )
246 beginMoveRows( QModelIndex(), row, row, QModelIndex(), row + 2 );
247 mMapping.swapItemsAt( row, row + 1 );
252QString QgsAggregateMappingModel::qgsFieldToTypeName(
const QgsField &field )
257 if ( type.mType == field.
type() && type.mSubType == field.
subType() )
259 return type.mTypeName;
265void QgsAggregateMappingModel::setFieldTypeFromName(
QgsField &field,
const QString &name )
270 if ( type.mTypeName == name )
283 if ( mExpressionContextGenerator )
284 mExpressionContextGenerator->setSourceFields( mSourceFields );
297 aggregate.
aggregate = QStringLiteral(
"sum" );
298 else if ( f.type() == QMetaType::Type::QString || ( f.type() == QMetaType::Type::QVariantList && f.subType() == QMetaType::Type::QString ) )
299 aggregate.
aggregate = QStringLiteral(
"concatenate" );
303 mMapping.push_back( aggregate );
310 return mExpressionContextGenerator.get();
315 mExpressionContextGenerator->setBaseExpressionContextGenerator( generator );
327 for (
auto &agg : mMapping )
329 agg.field.setTypeName( qgsFieldToTypeName( agg.field ) );
336 const int lastRow {
rowCount( QModelIndex() ) };
337 beginInsertRows( QModelIndex(), lastRow, lastRow );
344 mMapping.push_back( agg );
350 if ( index.isValid() && index.model() ==
this && index.row() <
rowCount( QModelIndex() ) )
352 beginRemoveRows( QModelIndex(), index.row(), index.row() );
353 mMapping.removeAt( index.row() );
365 return moveUpOrDown( index );
370 return moveUpOrDown( index,
false );
381 QVBoxLayout *verticalLayout =
new QVBoxLayout();
382 verticalLayout->setContentsMargins( 0, 0, 0, 0 );
383 mTableView =
new QTableView();
384 verticalLayout->addWidget( mTableView );
385 setLayout( verticalLayout );
388 mTableView->setModel( mModel );
394 connect( mModel, &QgsAggregateMappingModel::rowsInserted,
this, [=] { updateColumns(); } );
395 connect( mModel, &QgsAggregateMappingModel::modelReset,
this, [=] { updateColumns(); } );
404 return qobject_cast<QgsAggregateMappingModel *>( mModel );
419 return mTableView->selectionModel();
429 mSourceLayer = layer;
439 mTableView->scrollTo( index );
454 if ( !mTableView->selectionModel()->hasSelection() )
457 std::list<int> rowsToRemove { selectedRows() };
458 rowsToRemove.reverse();
459 for (
const int row : rowsToRemove )
471 if ( !mTableView->selectionModel()->hasSelection() )
474 const std::list<int> rowsToMoveUp { selectedRows() };
475 for (
const int row : rowsToMoveUp )
487 if ( !mTableView->selectionModel()->hasSelection() )
490 std::list<int> rowsToMoveDown { selectedRows() };
491 rowsToMoveDown.reverse();
492 for (
const int row : rowsToMoveDown )
502void QgsAggregateMappingWidget::updateColumns()
504 for (
int i = 0; i < mModel->rowCount(); ++i )
511 for (
int i = 0; i < mModel->columnCount(); ++i )
513 mTableView->resizeColumnToContents( i );
517std::list<int> QgsAggregateMappingWidget::selectedRows()
520 if ( mTableView->selectionModel()->hasSelection() )
522 const QModelIndexList constSelection { mTableView->selectionModel()->selectedIndexes() };
523 for (
const QModelIndex &index : constSelection )
525 rows.push_back( index.row() );
540QgsAggregateMappingDelegate::QgsAggregateMappingDelegate( QObject *parent )
541 : QStyledItemDelegate( parent )
545QWidget *QgsAggregateMappingDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex & )
const
548 QComboBox *editor =
new QComboBox( parent );
550 const QStringList aggregateList { aggregates() };
552 for (
const QString &aggregate : aggregateList )
554 editor->addItem( aggregate );
555 editor->setItemData( i, aggregate, Qt::UserRole );
559 connect( editor, qOverload<int>( &QComboBox::currentIndexChanged ),
this, [=](
int currentIndex ) {
560 Q_UNUSED( currentIndex )
561 const_cast<QgsAggregateMappingDelegate *
>( this )->emit commitData( editor );
567void QgsAggregateMappingDelegate::setEditorData( QWidget *editor,
const QModelIndex &index )
const
569 QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
573 const QVariant value = index.model()->data( index, Qt::EditRole );
574 editorWidget->setCurrentIndex( editorWidget->findData( value ) );
577void QgsAggregateMappingDelegate::setModelData( QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index )
const
579 QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
583 const QVariant currentValue = editorWidget->currentData();
584 model->setData( index, currentValue, Qt::EditRole );
587const QStringList QgsAggregateMappingDelegate::aggregates()
589 static QStringList sAggregates;
590 static std::once_flag initialized;
591 std::call_once( initialized, [=]() {
592 sAggregates << QStringLiteral(
"first_value" )
593 << QStringLiteral(
"last_value" );
598 if ( !function || function->isDeprecated() || function->name().isEmpty() || function->name().at( 0 ) ==
'_' )
601 if ( function->groups().contains( QLatin1String(
"Aggregates" ) ) )
603 if ( function->name() == QLatin1String(
"aggregate" )
604 || function->name() == QLatin1String(
"relation_aggregate" ) )
607 sAggregates.append( function->name() );
610 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,...
static const QList< QgsVectorDataProvider::NativeType > supportedDataTypes()
Returns a static list of supported data types.
Encapsulate a field in an attribute table or data source.
void setPrecision(int precision)
Set the field precision.
void setSubType(QMetaType::Type subType)
If the field is a collection, set its element's type.
void setName(const QString &name)
Set the field name.
void setType(QMetaType::Type type)
Set variant type.
void setLength(int len)
Set the field length.
QMetaType::Type subType() const
If the field is a collection, gets its element's type.
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)