25#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 |
170 return Qt::ItemFlags();
175 if ( index.isValid() )
177 if ( role == Qt::EditRole )
205 QgsFieldMappingModel::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#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
250 mMapping.swap( row, row + 1 );
252 mMapping.swapItemsAt( row, row + 1 );
261 if ( mExpressionContextGenerator )
262 mExpressionContextGenerator->setSourceFields( mSourceFields );
264 const QStringList usedFields;
272 aggregate.
field.
setTypeName( QgsFieldMappingModel::qgsFieldToTypeName( f ) );
276 aggregate.
aggregate = QStringLiteral(
"sum" );
277 else if ( f.type() == QVariant::String || ( f.type() == QVariant::List && f.subType() == QVariant::String ) )
278 aggregate.
aggregate = QStringLiteral(
"concatenate" );
282 mMapping.push_back( aggregate );
289 return mExpressionContextGenerator.get();
294 mExpressionContextGenerator->setBaseExpressionContextGenerator( generator );
306 for (
auto &agg : mMapping )
308 agg.field.setTypeName( QgsFieldMappingModel::qgsFieldToTypeName( agg.field ) );
315 const int lastRow {
rowCount( QModelIndex( ) ) };
316 beginInsertRows( QModelIndex(), lastRow, lastRow );
323 mMapping.push_back( agg );
329 if ( index.isValid() && index.model() ==
this && index.row() <
rowCount( QModelIndex() ) )
331 beginRemoveRows( QModelIndex(), index.row(), index.row() );
332 mMapping.removeAt( index.row() );
344 return moveUpOrDown( index );
349 return moveUpOrDown( index,
false );
361 QVBoxLayout *verticalLayout =
new QVBoxLayout();
362 verticalLayout->setContentsMargins( 0, 0, 0, 0 );
363 mTableView =
new QTableView();
364 verticalLayout->addWidget( mTableView );
365 setLayout( verticalLayout );
368 mTableView->setModel( mModel );
374 connect( mModel, &QgsAggregateMappingModel::rowsInserted,
this, [ = ] { updateColumns(); } );
375 connect( mModel, &QgsAggregateMappingModel::modelReset,
this, [ = ] { updateColumns(); } );
384 return qobject_cast<QgsAggregateMappingModel *>( mModel );
399 return mTableView->selectionModel();
409 mSourceLayer = layer;
419 mTableView->scrollTo( index );
434 if ( ! mTableView->selectionModel()->hasSelection() )
437 std::list<int> rowsToRemove { selectedRows() };
438 rowsToRemove.reverse();
439 for (
const int row : rowsToRemove )
441 if ( !
model()->removeField(
model()->index( row, 0, QModelIndex() ) ) )
451 if ( ! mTableView->selectionModel()->hasSelection() )
454 const std::list<int> rowsToMoveUp { selectedRows() };
455 for (
const int row : rowsToMoveUp )
457 if ( !
model()->moveUp(
model()->index( row, 0, QModelIndex() ) ) )
467 if ( ! mTableView->selectionModel()->hasSelection() )
470 std::list<int> rowsToMoveDown { selectedRows() };
471 rowsToMoveDown.reverse();
472 for (
const int row : rowsToMoveDown )
474 if ( !
model()->moveDown(
model()->index( row, 0, QModelIndex() ) ) )
482void QgsAggregateMappingWidget::updateColumns()
484 for (
int i = 0; i < mModel->rowCount(); ++i )
491 for (
int i = 0; i < mModel->columnCount(); ++i )
493 mTableView->resizeColumnToContents( i );
497std::list<int> QgsAggregateMappingWidget::selectedRows()
500 if ( mTableView->selectionModel()->hasSelection() )
502 const QModelIndexList constSelection { mTableView->selectionModel()->selectedIndexes() };
503 for (
const QModelIndex &index : constSelection )
505 rows.push_back( index.row() );
520QgsAggregateMappingDelegate::QgsAggregateMappingDelegate( QObject *parent )
521 : QStyledItemDelegate( parent )
525QWidget *QgsAggregateMappingDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex & )
const
528 QComboBox *editor =
new QComboBox( parent );
530 const QStringList aggregateList { aggregates() };
532 for (
const QString &aggregate : aggregateList )
534 editor->addItem( aggregate );
535 editor->setItemData( i, aggregate, Qt::UserRole );
540 qOverload<int >( &QComboBox::currentIndexChanged ),
542 [ = ](
int currentIndex )
544 Q_UNUSED( currentIndex )
545 const_cast< QgsAggregateMappingDelegate *
>( this )->emit commitData( editor );
551void QgsAggregateMappingDelegate::setEditorData( QWidget *editor,
const QModelIndex &index )
const
553 QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
554 if ( ! editorWidget )
557 const QVariant value = index.model()->data( index, Qt::EditRole );
558 editorWidget->setCurrentIndex( editorWidget->findData( value ) );
561void QgsAggregateMappingDelegate::setModelData( QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index )
const
563 QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
564 if ( ! editorWidget )
567 const QVariant currentValue = editorWidget->currentData( );
568 model->setData( index, currentValue, Qt::EditRole );
571const QStringList QgsAggregateMappingDelegate::aggregates()
573 static QStringList sAggregates;
574 static std::once_flag initialized;
575 std::call_once( initialized, [ = ]( )
577 sAggregates << QStringLiteral(
"first_value" )
578 << QStringLiteral(
"last_value" );
583 if ( !function || function->isDeprecated() || function->name().isEmpty() || function->name().at( 0 ) ==
'_' )
586 if ( function->groups().contains( QLatin1String(
"Aggregates" ) ) )
588 if ( function->name() == QLatin1String(
"aggregate" )
589 || function->name() == QLatin1String(
"relation_aggregate" ) )
592 sAggregates.append( function->name() );
595 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)