28#include <QStandardItemModel>
32#include "moc_qgsprocessingaggregatewidgets.cpp"
39 : QAbstractTableModel( parent )
47 if ( role == Qt::DisplayRole )
49 switch ( orientation )
57 return tr(
"Source Expression" );
61 return tr(
"Aggregate Function" );
65 return tr(
"Delimiter" );
77 return tr(
"Length" );
81 return tr(
"Precision" );
102 if ( parent.isValid() )
104 return mMapping.
count();
109 if ( parent.isValid() )
116 if ( index.isValid() )
119 const Aggregate &agg { mMapping.at( index.row() ) };
123 case Qt::DisplayRole:
166 if ( index.isValid() )
168 return Qt::ItemFlags( Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled );
170 return Qt::ItemFlags();
175 if ( index.isValid() )
177 if ( role == Qt::EditRole )
205 setFieldTypeFromName( f.
field, value.toString() );
211 const int length { value.toInt( &ok ) };
219 const int precision { value.toInt( &ok ) };
225 emit dataChanged( index, index );
236bool QgsAggregateMappingModel::moveUpOrDown(
const QModelIndex &index,
bool up )
238 if ( !index.isValid() && index.model() ==
this )
242 const int row { up ? index.row() - 1 : index.row() };
244 if ( row < 0 || row + 1 >=
rowCount( QModelIndex() ) )
248 beginMoveRows( QModelIndex(), row, row, QModelIndex(), row + 2 );
249 mMapping.swapItemsAt( row, row + 1 );
254QString QgsAggregateMappingModel::qgsFieldToTypeName(
const QgsField &field )
257 for (
const QgsVectorDataProvider::NativeType &type : types )
259 if ( type.mType == field.
type() && type.mSubType == field.
subType() )
261 return type.mTypeName;
267void QgsAggregateMappingModel::setFieldTypeFromName(
QgsField &field,
const QString &name )
270 for (
const QgsVectorDataProvider::NativeType &type : types )
272 if ( type.mTypeName == name )
285 if ( mExpressionContextGenerator )
286 mExpressionContextGenerator->setSourceFields( mSourceFields );
299 aggregate.
aggregate = QStringLiteral(
"sum" );
300 else if ( f.type() == QMetaType::Type::QString || ( f.type() == QMetaType::Type::QVariantList && f.subType() == QMetaType::Type::QString ) )
301 aggregate.
aggregate = QStringLiteral(
"concatenate" );
305 mMapping.push_back( aggregate );
312 return mExpressionContextGenerator.get();
317 mExpressionContextGenerator->setBaseExpressionContextGenerator( generator );
329 for (
auto &agg : mMapping )
331 agg.field.setTypeName( qgsFieldToTypeName( agg.field ) );
338 const int lastRow {
rowCount( QModelIndex() ) };
339 beginInsertRows( QModelIndex(), lastRow, lastRow );
346 mMapping.push_back( agg );
352 if ( index.isValid() && index.model() ==
this && index.row() <
rowCount( QModelIndex() ) )
354 beginRemoveRows( QModelIndex(), index.row(), index.row() );
355 mMapping.removeAt( index.row() );
367 return moveUpOrDown( index );
372 return moveUpOrDown( index,
false );
383 QVBoxLayout *verticalLayout =
new QVBoxLayout();
384 verticalLayout->setContentsMargins( 0, 0, 0, 0 );
385 mTableView =
new QTableView();
386 verticalLayout->addWidget( mTableView );
387 setLayout( verticalLayout );
390 mTableView->setModel( mModel );
396 connect( mModel, &QgsAggregateMappingModel::rowsInserted,
this, [
this] { updateColumns(); } );
397 connect( mModel, &QgsAggregateMappingModel::modelReset,
this, [
this] { updateColumns(); } );
406 return qobject_cast<QgsAggregateMappingModel *>( mModel );
421 return mTableView->selectionModel();
431 mSourceLayer = layer;
441 mTableView->scrollTo( index );
456 if ( !mTableView->selectionModel()->hasSelection() )
459 std::list<int> rowsToRemove { selectedRows() };
460 rowsToRemove.reverse();
461 for (
const int row : rowsToRemove )
463 if ( !
model()->removeField(
model()->index( row, 0, QModelIndex() ) ) )
473 if ( !mTableView->selectionModel()->hasSelection() )
476 const std::list<int> rowsToMoveUp { selectedRows() };
477 for (
const int row : rowsToMoveUp )
479 if ( !
model()->moveUp(
model()->index( row, 0, QModelIndex() ) ) )
489 if ( !mTableView->selectionModel()->hasSelection() )
492 std::list<int> rowsToMoveDown { selectedRows() };
493 rowsToMoveDown.reverse();
494 for (
const int row : rowsToMoveDown )
496 if ( !
model()->moveDown(
model()->index( row, 0, QModelIndex() ) ) )
504void QgsAggregateMappingWidget::updateColumns()
506 for (
int i = 0; i < mModel->rowCount(); ++i )
513 for (
int i = 0; i < mModel->columnCount(); ++i )
515 mTableView->resizeColumnToContents( i );
519std::list<int> QgsAggregateMappingWidget::selectedRows()
522 if ( mTableView->selectionModel()->hasSelection() )
524 const QModelIndexList constSelection { mTableView->selectionModel()->selectedIndexes() };
525 for (
const QModelIndex &index : constSelection )
527 rows.push_back( index.row() );
542QgsAggregateMappingDelegate::QgsAggregateMappingDelegate( QObject *parent )
543 : QStyledItemDelegate( parent )
547QWidget *QgsAggregateMappingDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex & )
const
550 QComboBox *editor =
new QComboBox( parent );
552 const QStringList aggregateList { aggregates() };
554 for (
const QString &aggregate : aggregateList )
556 editor->addItem( aggregate );
557 editor->setItemData( i, aggregate, Qt::UserRole );
561 connect( editor, qOverload<int>( &QComboBox::currentIndexChanged ),
this, [
this, editor](
int currentIndex ) {
562 Q_UNUSED( currentIndex )
563 const_cast<QgsAggregateMappingDelegate *
>( this )->emit commitData( editor );
569void QgsAggregateMappingDelegate::setEditorData( QWidget *editor,
const QModelIndex &index )
const
571 QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
575 const QVariant value = index.model()->data( index, Qt::EditRole );
576 editorWidget->setCurrentIndex( editorWidget->findData( value ) );
579void QgsAggregateMappingDelegate::setModelData( QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index )
const
581 QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
585 const QVariant currentValue = editorWidget->currentData();
586 model->setData( index, currentValue, Qt::EditRole );
589const QStringList QgsAggregateMappingDelegate::aggregates()
591 static QStringList sAggregates;
592 static std::once_flag initialized;
593 std::call_once( initialized, []() {
594 sAggregates << QStringLiteral(
"first_value" )
595 << QStringLiteral(
"last_value" );
600 if ( !function || function->isDeprecated() || function->name().isEmpty() || function->name().at( 0 ) ==
'_' )
603 if ( function->groups().contains( QLatin1String(
"Aggregates" ) ) )
605 if ( function->name() == QLatin1String(
"aggregate" )
606 || function->name() == QLatin1String(
"relation_aggregate" ) )
609 sAggregates.append( function->name() );
612 std::sort( sAggregates.begin(), sAggregates.end() );
Holds mapping information for defining sets of aggregates of fields from a QgsFields object.
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.
An abstract base class for defining QgsExpression functions.
Handles 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).
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.
QString typeName() const
Gets the field type.
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.
QString displayName() const
Returns the name to use when displaying this field.
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 dataset.
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).