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() );