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 QgsFieldMappingModel::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 );
255 if ( mExpressionContextGenerator )
256 mExpressionContextGenerator->setSourceFields( mSourceFields );
265 aggregate.
field.
setTypeName( QgsFieldMappingModel::qgsFieldToTypeName( f ) );
269 aggregate.
aggregate = QStringLiteral(
"sum" );
270 else if ( f.type() == QMetaType::Type::QString || ( f.type() == QMetaType::Type::QVariantList && f.subType() == QMetaType::Type::QString ) )
271 aggregate.
aggregate = QStringLiteral(
"concatenate" );
275 mMapping.push_back( aggregate );
282 return mExpressionContextGenerator.get();
287 mExpressionContextGenerator->setBaseExpressionContextGenerator( generator );
299 for (
auto &agg : mMapping )
301 agg.field.setTypeName( QgsFieldMappingModel::qgsFieldToTypeName( agg.field ) );
308 const int lastRow {
rowCount( QModelIndex() ) };
309 beginInsertRows( QModelIndex(), lastRow, lastRow );
316 mMapping.push_back( agg );
322 if ( index.isValid() && index.model() ==
this && index.row() <
rowCount( QModelIndex() ) )
324 beginRemoveRows( QModelIndex(), index.row(), index.row() );
325 mMapping.removeAt( index.row() );
337 return moveUpOrDown( index );
342 return moveUpOrDown( index,
false );
353 QVBoxLayout *verticalLayout =
new QVBoxLayout();
354 verticalLayout->setContentsMargins( 0, 0, 0, 0 );
355 mTableView =
new QTableView();
356 verticalLayout->addWidget( mTableView );
357 setLayout( verticalLayout );
360 mTableView->setModel( mModel );
366 connect( mModel, &QgsAggregateMappingModel::rowsInserted,
this, [=] { updateColumns(); } );
367 connect( mModel, &QgsAggregateMappingModel::modelReset,
this, [=] { updateColumns(); } );
376 return qobject_cast<QgsAggregateMappingModel *>( mModel );
391 return mTableView->selectionModel();
401 mSourceLayer = layer;
411 mTableView->scrollTo( index );
426 if ( !mTableView->selectionModel()->hasSelection() )
429 std::list<int> rowsToRemove { selectedRows() };
430 rowsToRemove.reverse();
431 for (
const int row : rowsToRemove )
443 if ( !mTableView->selectionModel()->hasSelection() )
446 const std::list<int> rowsToMoveUp { selectedRows() };
447 for (
const int row : rowsToMoveUp )
459 if ( !mTableView->selectionModel()->hasSelection() )
462 std::list<int> rowsToMoveDown { selectedRows() };
463 rowsToMoveDown.reverse();
464 for (
const int row : rowsToMoveDown )
474void QgsAggregateMappingWidget::updateColumns()
476 for (
int i = 0; i < mModel->rowCount(); ++i )
483 for (
int i = 0; i < mModel->columnCount(); ++i )
485 mTableView->resizeColumnToContents( i );
489std::list<int> QgsAggregateMappingWidget::selectedRows()
492 if ( mTableView->selectionModel()->hasSelection() )
494 const QModelIndexList constSelection { mTableView->selectionModel()->selectedIndexes() };
495 for (
const QModelIndex &index : constSelection )
497 rows.push_back( index.row() );
512QgsAggregateMappingDelegate::QgsAggregateMappingDelegate( QObject *parent )
513 : QStyledItemDelegate( parent )
517QWidget *QgsAggregateMappingDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex & )
const
520 QComboBox *editor =
new QComboBox( parent );
522 const QStringList aggregateList { aggregates() };
524 for (
const QString &aggregate : aggregateList )
526 editor->addItem( aggregate );
527 editor->setItemData( i, aggregate, Qt::UserRole );
531 connect( editor, qOverload<int>( &QComboBox::currentIndexChanged ),
this, [=](
int currentIndex ) {
532 Q_UNUSED( currentIndex )
533 const_cast<QgsAggregateMappingDelegate *
>( this )->emit commitData( editor );
539void QgsAggregateMappingDelegate::setEditorData( QWidget *editor,
const QModelIndex &index )
const
541 QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
545 const QVariant value = index.model()->data( index, Qt::EditRole );
546 editorWidget->setCurrentIndex( editorWidget->findData( value ) );
549void QgsAggregateMappingDelegate::setModelData( QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index )
const
551 QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
555 const QVariant currentValue = editorWidget->currentData();
556 model->setData( index, currentValue, Qt::EditRole );
559const QStringList QgsAggregateMappingDelegate::aggregates()
561 static QStringList sAggregates;
562 static std::once_flag initialized;
563 std::call_once( initialized, [=]() {
564 sAggregates << QStringLiteral(
"first_value" )
565 << QStringLiteral(
"last_value" );
570 if ( !function || function->isDeprecated() || function->name().isEmpty() || function->name().at( 0 ) ==
'_' )
573 if ( function->groups().contains( QLatin1String(
"Aggregates" ) ) )
575 if ( function->name() == QLatin1String(
"aggregate" )
576 || function->name() == QLatin1String(
"relation_aggregate" ) )
579 sAggregates.append( function->name() );
582 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)