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 static_cast<int>( agg.field.type() );
 
  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           f.
field.
setType( 
static_cast<QVariant::Type
>( value.toInt( ) ) );
 
  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   QStringList usedFields;
 
  274       aggregate.
aggregate = QStringLiteral( 
"sum" );
 
  275     else if ( f.type() == QVariant::String || ( f.type() == QVariant::List && f.subType() == QVariant::String ) )
 
  276       aggregate.
aggregate = QStringLiteral( 
"concatenate" );
 
  280     mMapping.push_back( aggregate );
 
  287   return mExpressionContextGenerator.get();
 
  292   mExpressionContextGenerator->setBaseExpressionContextGenerator( generator );
 
  309   const int lastRow { 
rowCount( QModelIndex( ) ) };
 
  310   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 );
 
  354   QVBoxLayout *verticalLayout = 
new QVBoxLayout();
 
  355   verticalLayout->setContentsMargins( 0, 0, 0, 0 );
 
  356   mTableView = 
new QTableView();
 
  357   verticalLayout->addWidget( mTableView );
 
  358   setLayout( verticalLayout );
 
  361   mTableView->setModel( mModel );
 
  367   connect( mModel, &QgsAggregateMappingModel::rowsInserted, 
this, [ = ] { updateColumns(); } );
 
  368   connect( mModel, &QgsAggregateMappingModel::modelReset, 
this, [ = ] { updateColumns(); } );
 
  377   return qobject_cast<QgsAggregateMappingModel *>( mModel );
 
  392   return mTableView->selectionModel();
 
  402   mSourceLayer = layer;
 
  412   mTableView->scrollTo( index );
 
  427   if ( ! mTableView->selectionModel()->hasSelection() )
 
  430   std::list<int> rowsToRemove { selectedRows() };
 
  431   rowsToRemove.reverse();
 
  432   for ( 
int row : rowsToRemove )
 
  434     if ( ! 
model()->removeField( 
model()->index( row, 0, QModelIndex() ) ) )
 
  444   if ( ! mTableView->selectionModel()->hasSelection() )
 
  447   const std::list<int> rowsToMoveUp { selectedRows() };
 
  448   for ( 
int row : rowsToMoveUp )
 
  450     if ( ! 
model()->moveUp( 
model()->index( row, 0, QModelIndex() ) ) )
 
  460   if ( ! mTableView->selectionModel()->hasSelection() )
 
  463   std::list<int> rowsToMoveDown { selectedRows() };
 
  464   rowsToMoveDown.reverse();
 
  465   for ( 
int row : rowsToMoveDown )
 
  467     if ( ! 
model()->moveDown( 
model()->index( row, 0, QModelIndex() ) ) )
 
  475 void QgsAggregateMappingWidget::updateColumns()
 
  477   for ( 
int i = 0; i < mModel->rowCount(); ++i )
 
  484   for ( 
int i = 0; i < mModel->columnCount(); ++i )
 
  486     mTableView->resizeColumnToContents( i );
 
  490 std::list<int> QgsAggregateMappingWidget::selectedRows()
 
  493   if ( mTableView->selectionModel()->hasSelection() )
 
  495     const QModelIndexList constSelection { mTableView->selectionModel()->selectedIndexes() };
 
  496     for ( 
const QModelIndex &index : constSelection )
 
  498       rows.push_back( index.row() );
 
  512 QgsAggregateMappingWidget::AggregateDelegate::AggregateDelegate( QObject *parent )
 
  513   : QStyledItemDelegate( parent )
 
  517 QWidget *QgsAggregateMappingWidget::AggregateDelegate::createEditor( QWidget *parent, 
const QStyleOptionViewItem &option, 
const QModelIndex & )
 const 
  520   QComboBox *editor = 
new QComboBox( parent );
 
  522   const QStringList aggregateList { QgsAggregateMappingWidget::AggregateDelegate::aggregates() };
 
  524   for ( 
const QString &aggregate : aggregateList )
 
  526     editor->addItem( aggregate );
 
  527     editor->setItemData( i, aggregate, Qt::UserRole );
 
  532            qgis::overload<int >::of( &QComboBox::currentIndexChanged ),
 
  534            [ = ]( 
int currentIndex )
 
  536     Q_UNUSED( currentIndex )
 
  537     const_cast< QgsAggregateMappingWidget::AggregateDelegate *
>( this )->emit commitData( editor );
 
  543 void QgsAggregateMappingWidget::AggregateDelegate::setEditorData( QWidget *editor, 
const QModelIndex &index )
 const 
  545   QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
 
  546   if ( ! editorWidget )
 
  549   const QVariant value = index.model()->data( index, Qt::EditRole );
 
  550   editorWidget->setCurrentIndex( editorWidget->findData( value ) );
 
  553 void QgsAggregateMappingWidget::AggregateDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, 
const QModelIndex &index )
 const 
  555   QComboBox *editorWidget { qobject_cast<QComboBox *>( editor ) };
 
  556   if ( ! editorWidget )
 
  559   const QVariant currentValue = editorWidget->currentData( );
 
  560   model->setData( index, currentValue, Qt::EditRole );
 
  563 const QStringList QgsAggregateMappingWidget::AggregateDelegate::aggregates()
 
  565   static QStringList sAggregates;
 
  566   static std::once_flag initialized;
 
  567   std::call_once( initialized, [ = ]( )
 
  569     sAggregates << QStringLiteral( 
"first_value" );
 
  574       if ( !
function || function->isDeprecated() || function->name().isEmpty() || function->name().at( 0 ) == 
'_' )
 
  577       if ( function->groups().contains( QLatin1String( 
"Aggregates" ) ) )
 
  579         if ( function->name() == QLatin1String( 
"aggregate" )
 
  580              || function->name() == QLatin1String( 
"relation_aggregate" ) )
 
  583         sAggregates.append( function->name() );
 
  586       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 QVariant::Type casted to (int)
@ 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 setType(QVariant::Type type)
Set variant 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)