Skip to content

Commit

Permalink
Expose layers field names to expression widget
Browse files Browse the repository at this point in the history
Fixes #37544
  • Loading branch information
elpaso committed Dec 15, 2021
1 parent 68a1470 commit 9a0c54c
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 23 deletions.
1 change: 1 addition & 0 deletions python/gui/auto_generated/qgsexpressiontreeview.sip.in
Expand Up @@ -68,6 +68,7 @@ Gets the type of expression item, e.g., header, field, ExpressionNode.
static const int ITEM_TYPE_ROLE;
static const int SEARCH_TAGS_ROLE;
static const int ITEM_NAME_ROLE;
static const int LAYER_ID_ROLE;

};

Expand Down
62 changes: 49 additions & 13 deletions src/gui/qgsexpressionbuilderwidget.cpp
Expand Up @@ -507,16 +507,16 @@ void QgsExpressionBuilderWidget::loadFieldsAndValues( const QMap<QString, QStrin
// This is not maintained and setLayer() should be used instead.
}

void QgsExpressionBuilderWidget::fillFieldValues( const QString &fieldName, int countLimit, bool forceUsedValues )
void QgsExpressionBuilderWidget::fillFieldValues( const QString &fieldName, QgsVectorLayer *layer, int countLimit, bool forceUsedValues )
{
// TODO We should really return a error the user of the widget that
// the there is no layer set.
if ( !mLayer )
if ( !layer )
return;

// TODO We should thread this so that we don't hold the user up if the layer is massive.

const QgsFields fields = mLayer->fields();
const QgsFields fields = layer->fields();
int fieldIndex = fields.lookupField( fieldName );

if ( fieldIndex < 0 )
Expand All @@ -534,7 +534,7 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString &fieldName, int
}
else
{
values = qgis::setToList( mLayer->uniqueValues( fieldIndex, countLimit ) );
values = qgis::setToList( layer->uniqueValues( fieldIndex, countLimit ) );
}
std::sort( values.begin(), values.end() );

Expand Down Expand Up @@ -564,7 +564,7 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString &fieldName, int
else
strValue = '\'' + value.toString().replace( '\'', QLatin1String( "''" ) ) + '\'';

QString representedValue = formatter->representValue( mLayer, fieldIndex, setup.config(), QVariant(), value );
QString representedValue = formatter->representValue( layer, fieldIndex, setup.config(), QVariant(), value );
if ( forceRepresentedValue || representedValue != value.toString() )
representedValue = representedValue + QStringLiteral( " [" ) + strValue + ']';

Expand Down Expand Up @@ -852,47 +852,83 @@ void QgsExpressionBuilderWidget::loadSampleValues()
QgsExpressionItem *item = mExpressionTreeView->currentItem();
// TODO We should really return a error the user of the widget that
// the there is no layer set.
if ( !mLayer || !item )
QgsVectorLayer *layer = nullptr;
if ( ! item->data( QgsExpressionItem::LAYER_ID_ROLE ).isNull() )
{
layer = qobject_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( item->data( QgsExpressionItem::LAYER_ID_ROLE ).toString() ) );
}
else
{
layer = mLayer;
}
if ( !layer || !item )
return;

mValueGroupBox->show();
fillFieldValues( item->data( QgsExpressionItem::ITEM_NAME_ROLE ).toString(), 10 );
fillFieldValues( item->data( QgsExpressionItem::ITEM_NAME_ROLE ).toString(), layer, 10 );
}

void QgsExpressionBuilderWidget::loadAllValues()
{
QgsExpressionItem *item = mExpressionTreeView->currentItem();
// TODO We should really return a error the user of the widget that
// the there is no layer set.
if ( !mLayer || !item )
QgsVectorLayer *layer = nullptr;
if ( ! item->data( QgsExpressionItem::LAYER_ID_ROLE ).isNull() )
{
layer = qobject_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( item->data( QgsExpressionItem::LAYER_ID_ROLE ).toString() ) );
}
else
{
layer = mLayer;
}
if ( !layer || !item )
return;

mValueGroupBox->show();
fillFieldValues( item->data( QgsExpressionItem::ITEM_NAME_ROLE ).toString(), -1 );
fillFieldValues( item->data( QgsExpressionItem::ITEM_NAME_ROLE ).toString(), layer, -1 );
}

void QgsExpressionBuilderWidget::loadSampleUsedValues()
{
QgsExpressionItem *item = mExpressionTreeView->currentItem();
// TODO We should really return a error the user of the widget that
// the there is no layer set.
if ( !mLayer || !item )
QgsVectorLayer *layer = nullptr;
if ( ! item->data( QgsExpressionItem::LAYER_ID_ROLE ).isNull() )
{
layer = qobject_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( item->data( QgsExpressionItem::LAYER_ID_ROLE ).toString() ) );
}
else
{
layer = mLayer;
}
if ( !layer || !item )
return;

mValueGroupBox->show();
fillFieldValues( item->data( QgsExpressionItem::ITEM_NAME_ROLE ).toString(), 10, true );
fillFieldValues( item->data( QgsExpressionItem::ITEM_NAME_ROLE ).toString(), layer, 10, true );
}

void QgsExpressionBuilderWidget::loadAllUsedValues()
{
QgsExpressionItem *item = mExpressionTreeView->currentItem();
// TODO We should really return a error the user of the widget that
// the there is no layer set.
if ( !mLayer || !item )
QgsVectorLayer *layer = nullptr;
if ( ! item->data( QgsExpressionItem::LAYER_ID_ROLE ).isNull() )
{
layer = qobject_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( item->data( QgsExpressionItem::LAYER_ID_ROLE ).toString() ) );
}
else
{
layer = mLayer;
}
if ( !layer || !item )
return;

mValueGroupBox->show();
fillFieldValues( item->data( QgsExpressionItem::ITEM_NAME_ROLE ).toString(), -1, true );
fillFieldValues( item->data( QgsExpressionItem::ITEM_NAME_ROLE ).toString(), layer, -1, true );
}

void QgsExpressionBuilderWidget::txtPython_textChanged()
Expand Down
2 changes: 1 addition & 1 deletion src/gui/qgsexpressionbuilderwidget.h
Expand Up @@ -419,7 +419,7 @@ class GUI_EXPORT QgsExpressionBuilderWidget : public QWidget, private Ui::QgsExp
void clearFunctionMarkers();
void clearErrors();
void runPythonCode( const QString &code );
void fillFieldValues( const QString &fieldName, int countLimit, bool forceUsedValues = false );
void fillFieldValues( const QString &fieldName, QgsVectorLayer *layer, int countLimit, bool forceUsedValues = false );
QString getFunctionHelp( QgsExpressionFunction *function );
QString loadFunctionHelp( QgsExpressionItem *functionName );
QString helpStylesheet() const;
Expand Down
26 changes: 24 additions & 2 deletions src/gui/qgsexpressiontreeview.cpp
Expand Up @@ -323,7 +323,7 @@ void QgsExpressionTreeView::updateFunctionTree()
loadExpressionContext();
}

void QgsExpressionTreeView::registerItem( const QString &group,
QgsExpressionItem *QgsExpressionTreeView::registerItem( const QString &group,
const QString &label,
const QString &expressionText,
const QString &helpText,
Expand Down Expand Up @@ -366,6 +366,7 @@ void QgsExpressionTreeView::registerItem( const QString &group,
topLevelItem->setFont( font );
mModel->appendRow( topLevelItem );
}
return item;
}

void QgsExpressionTreeView::registerItemForAllGroups( const QStringList &groups, const QString &label, const QString &expressionText, const QString &helpText, QgsExpressionItem::ItemType type, bool highlightedItem, int sortOrder, const QStringList &tags )
Expand Down Expand Up @@ -414,7 +415,28 @@ void QgsExpressionTreeView::loadLayers()
for ( ; layerIt != layers.constEnd(); ++layerIt )
{
QIcon icon = QgsIconUtils::iconForLayer( layerIt.value() );
registerItem( QStringLiteral( "Map Layers" ), layerIt.value()->name(), QStringLiteral( "'%1'" ).arg( layerIt.key() ), formatLayerHelp( layerIt.value() ), QgsExpressionItem::ExpressionNode, false, 99, icon );
QgsExpressionItem *parentItem = registerItem( QStringLiteral( "Map Layers" ), layerIt.value()->name(), QStringLiteral( "'%1'" ).arg( layerIt.key() ), formatLayerHelp( layerIt.value() ), QgsExpressionItem::ExpressionNode, false, 99, icon );
loadLayerFields( qobject_cast<QgsVectorLayer *>( layerIt.value() ), parentItem );
}

}

void QgsExpressionTreeView::loadLayerFields( QgsVectorLayer *layer, QgsExpressionItem *parentItem )
{
const QgsFields fields { layer->fields() };
for ( int fieldIdx = 0; fieldIdx < layer->fields().count(); ++fieldIdx )
{
const QgsField field = fields.at( fieldIdx );
QIcon icon = fields.iconForField( fieldIdx );
const QString label { field.displayNameWithAlias() };
QgsExpressionItem *item = new QgsExpressionItem( label, " '" + field.name() + "' ", QString(), QgsExpressionItem::Field );
item->setData( label, Qt::UserRole );
item->setData( 99, QgsExpressionItem::CUSTOM_SORT_ROLE );
item->setData( QStringList(), QgsExpressionItem::SEARCH_TAGS_ROLE );
item->setData( field.name(), QgsExpressionItem::ITEM_NAME_ROLE );
item->setData( layer->id(), QgsExpressionItem::LAYER_ID_ROLE );
item->setIcon( icon );
parentItem->appendRow( item );
}
}

Expand Down
17 changes: 10 additions & 7 deletions src/gui/qgsexpressiontreeview.h
Expand Up @@ -98,6 +98,8 @@ class GUI_EXPORT QgsExpressionItem : public QStandardItem
static const int SEARCH_TAGS_ROLE = Qt::UserRole + 3;
//! Item name role
static const int ITEM_NAME_ROLE = Qt::UserRole + 4;
//! Layer ID role \since QGIS 3.24
static const int LAYER_ID_ROLE = Qt::UserRole + 5;

private:
QString mExpressionText;
Expand Down Expand Up @@ -318,13 +320,13 @@ class GUI_EXPORT QgsExpressionTreeView : public QTreeView
* \param tags tags to find function
* \param name name of the item
*/
void registerItem( const QString &group, const QString &label, const QString &expressionText,
const QString &helpText = QString(),
QgsExpressionItem::ItemType type = QgsExpressionItem::ExpressionNode,
bool highlightedItem = false, int sortOrder = 1,
const QIcon &icon = QIcon(),
const QStringList &tags = QStringList(),
const QString &name = QString() );
QgsExpressionItem *registerItem( const QString &group, const QString &label, const QString &expressionText,
const QString &helpText = QString(),
QgsExpressionItem::ItemType type = QgsExpressionItem::ExpressionNode,
bool highlightedItem = false, int sortOrder = 1,
const QIcon &icon = QIcon(),
const QStringList &tags = QStringList(),
const QString &name = QString() );

/**
* Registers a node item for the expression builder, adding multiple items when the function exists in multiple groups
Expand All @@ -345,6 +347,7 @@ class GUI_EXPORT QgsExpressionTreeView : public QTreeView
void loadExpressionContext();
void loadRelations();
void loadLayers();
void loadLayerFields( QgsVectorLayer *layer, QgsExpressionItem *parentItem );
void loadFieldNames();

/**
Expand Down

0 comments on commit 9a0c54c

Please sign in to comment.