mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-26 00:02:08 -05:00
[Feature] conditional visibility for tabs and groupboxes
This adds a new configuration option to conditionally show or hide tabs and groupboxes in drag and drop designer forms. Configuration is done via a double click in the designer tree in the fields configuration interface. An expression can be entered to control the visibility. The expression will be re-evaluated everytime values in the form change and the tab or groupbox shown/hidden accordingly.
This commit is contained in:
parent
ac41436de3
commit
1882cabea9
@ -28,6 +28,7 @@
|
||||
#include "qgsrelationmanager.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsfieldexpressionwidget.h"
|
||||
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QWidget>
|
||||
@ -72,7 +73,7 @@ QgsFieldsProperties::QgsFieldsProperties( QgsVectorLayer *layer, QWidget* parent
|
||||
// tab and group display
|
||||
mAddItemButton->setEnabled( false );
|
||||
|
||||
mDesignerTree = new DesignerTree( mAttributesTreeFrame );
|
||||
mDesignerTree = new DesignerTree( mLayer, mAttributesTreeFrame );
|
||||
mDesignerListLayout->addWidget( mDesignerTree );
|
||||
mDesignerTree->setHeaderLabels( QStringList() << tr( "Label" ) );
|
||||
|
||||
@ -154,7 +155,7 @@ void QgsFieldsProperties::onAttributeSelectionChanged()
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
QTreeWidgetItem *QgsFieldsProperties::loadAttributeEditorTreeItem( QgsAttributeEditorElement* const widgetDef, QTreeWidgetItem* parent )
|
||||
QTreeWidgetItem* QgsFieldsProperties::loadAttributeEditorTreeItem( QgsAttributeEditorElement* const widgetDef, QTreeWidgetItem* parent )
|
||||
{
|
||||
QTreeWidgetItem* newWidget = nullptr;
|
||||
switch ( widgetDef->type() )
|
||||
@ -187,6 +188,7 @@ QTreeWidgetItem *QgsFieldsProperties::loadAttributeEditorTreeItem( QgsAttributeE
|
||||
|
||||
itemData.setColumnCount( container->columnCount() );
|
||||
itemData.setShowAsGroupBox( container->isGroupBox() );
|
||||
itemData.setVisibilityExpression( container->visibilityExpression() );
|
||||
newWidget = mDesignerTree->addItem( parent, itemData );
|
||||
|
||||
Q_FOREACH ( QgsAttributeEditorElement* wdg, container->children() )
|
||||
@ -865,6 +867,7 @@ QgsAttributeEditorElement* QgsFieldsProperties::createAttributeEditorWidget( QTr
|
||||
QgsAttributeEditorContainer* container = new QgsAttributeEditorContainer( item->text( 0 ), parent );
|
||||
container->setColumnCount( itemData.columnCount() );
|
||||
container->setIsGroupBox( forceGroup ? true : itemData.showAsGroupBox() );
|
||||
container->setVisibilityExpression( itemData.visibilityExpression() );
|
||||
|
||||
for ( int t = 0; t < item->childCount(); t++ )
|
||||
{
|
||||
@ -1092,8 +1095,9 @@ QTreeWidgetItem* DesignerTree::addContainer( QTreeWidgetItem* parent, const QStr
|
||||
return newItem;
|
||||
}
|
||||
|
||||
DesignerTree::DesignerTree( QWidget* parent )
|
||||
DesignerTree::DesignerTree( QgsVectorLayer* layer, QWidget* parent )
|
||||
: QTreeWidget( parent )
|
||||
, mLayer( layer )
|
||||
{
|
||||
connect( this, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( onItemDoubleClicked( QTreeWidgetItem*, int ) ) );
|
||||
}
|
||||
@ -1271,11 +1275,22 @@ void DesignerTree::onItemDoubleClicked( QTreeWidgetItem* item, int column )
|
||||
QCheckBox* showAsGroupBox = nullptr;
|
||||
QLineEdit* title = new QLineEdit( itemData.name() );
|
||||
QSpinBox* columnCount = new QSpinBox();
|
||||
QGroupBox* visibilityExpressionGroupBox = new QGroupBox( tr( "Control visibility by expression " ) );
|
||||
visibilityExpressionGroupBox->setCheckable( true );
|
||||
visibilityExpressionGroupBox->setChecked( itemData.visibilityExpression().enabled() );
|
||||
visibilityExpressionGroupBox->setLayout( new QGridLayout );
|
||||
QgsFieldExpressionWidget* visibilityExpressionWidget = new QgsFieldExpressionWidget;
|
||||
visibilityExpressionWidget->setLayer( mLayer );
|
||||
visibilityExpressionWidget->setExpressionDialogTitle( tr( "Visibility expression" ) );
|
||||
visibilityExpressionWidget->setExpression( itemData.visibilityExpression()->expression() );
|
||||
visibilityExpressionGroupBox->layout()->addWidget( visibilityExpressionWidget );
|
||||
|
||||
columnCount->setRange( 1, 5 );
|
||||
columnCount->setValue( itemData.columnCount() );
|
||||
|
||||
layout->addRow( tr( "Title" ), title );
|
||||
layout->addRow( tr( "Column count" ), columnCount );
|
||||
layout->addWidget( visibilityExpressionGroupBox );
|
||||
|
||||
if ( !item->parent() )
|
||||
{
|
||||
@ -1299,6 +1314,11 @@ void DesignerTree::onItemDoubleClicked( QTreeWidgetItem* item, int column )
|
||||
itemData.setName( title->text() );
|
||||
itemData.setShowLabel( showLabelCheckbox->isChecked() );
|
||||
|
||||
QgsOptionalExpression visibilityExpression;
|
||||
visibilityExpression.setData( QgsExpression( visibilityExpressionWidget->expression() ) );
|
||||
visibilityExpression.setEnabled( visibilityExpressionGroupBox->isChecked() );
|
||||
itemData.setVisibilityExpression( visibilityExpression );
|
||||
|
||||
item->setData( 0, QgsFieldsProperties::DesignerTreeRole, itemData.asQVariant() );
|
||||
item->setText( 0, title->text() );
|
||||
}
|
||||
@ -1369,3 +1389,13 @@ void QgsFieldsProperties::DesignerTreeItemData::setShowLabel( bool showLabel )
|
||||
{
|
||||
mShowLabel = showLabel;
|
||||
}
|
||||
|
||||
QgsOptionalExpression QgsFieldsProperties::DesignerTreeItemData::visibilityExpression() const
|
||||
{
|
||||
return mVisibilityExpression;
|
||||
}
|
||||
|
||||
void QgsFieldsProperties::DesignerTreeItemData::setVisibilityExpression( const QgsOptionalExpression& visibilityExpression )
|
||||
{
|
||||
mVisibilityExpression = visibilityExpression;
|
||||
}
|
||||
|
@ -84,12 +84,16 @@ class APP_EXPORT QgsFieldsProperties : public QWidget, private Ui_QgsFieldsPrope
|
||||
bool showLabel() const;
|
||||
void setShowLabel( bool showLabel );
|
||||
|
||||
QgsOptionalExpression visibilityExpression() const;
|
||||
void setVisibilityExpression( const QgsOptionalExpression& visibilityExpression );
|
||||
|
||||
private:
|
||||
Type mType;
|
||||
QString mName;
|
||||
int mColumnCount;
|
||||
bool mShowAsGroupBox;
|
||||
bool mShowLabel;
|
||||
QgsOptionalExpression mVisibilityExpression;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -265,7 +269,7 @@ class DesignerTree : public QTreeWidget
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DesignerTree( QWidget* parent = nullptr );
|
||||
explicit DesignerTree( QgsVectorLayer* layer, QWidget* parent = nullptr );
|
||||
QTreeWidgetItem* addItem( QTreeWidgetItem* parent, QgsFieldsProperties::DesignerTreeItemData data );
|
||||
QTreeWidgetItem* addContainer( QTreeWidgetItem* parent, const QString& title , int columnCount );
|
||||
|
||||
@ -282,6 +286,9 @@ class DesignerTree : public QTreeWidget
|
||||
|
||||
private slots:
|
||||
void onItemDoubleClicked( QTreeWidgetItem* item, int column );
|
||||
|
||||
private:
|
||||
QgsVectorLayer* mLayer;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE( QgsFieldsProperties::FieldConfig )
|
||||
|
@ -26,6 +26,19 @@ void QgsAttributeEditorContainer::setName( const QString& name )
|
||||
mName = name;
|
||||
}
|
||||
|
||||
QgsOptionalExpression QgsAttributeEditorContainer::visibilityExpression() const
|
||||
{
|
||||
return mVisibilityExpression;
|
||||
}
|
||||
|
||||
void QgsAttributeEditorContainer::setVisibilityExpression( const QgsOptionalExpression& visibilityExpression )
|
||||
{
|
||||
if ( visibilityExpression == mVisibilityExpression )
|
||||
return;
|
||||
|
||||
mVisibilityExpression = visibilityExpression;
|
||||
}
|
||||
|
||||
QList<QgsAttributeEditorElement*> QgsAttributeEditorContainer::findElements( QgsAttributeEditorElement::AttributeEditorType type ) const
|
||||
{
|
||||
QList<QgsAttributeEditorElement*> results;
|
||||
|
@ -17,6 +17,7 @@
|
||||
#define QGSATTRIBUTEEDITORELEMENT_H
|
||||
|
||||
#include "qgsrelation.h"
|
||||
#include "qgsoptionalexpression.h"
|
||||
|
||||
class QgsRelationManager;
|
||||
|
||||
@ -219,6 +220,9 @@ class CORE_EXPORT QgsAttributeEditorContainer : public QgsAttributeEditorElement
|
||||
*/
|
||||
virtual QgsAttributeEditorElement* clone( QgsAttributeEditorElement* parent ) const override;
|
||||
|
||||
QgsOptionalExpression visibilityExpression() const;
|
||||
void setVisibilityExpression( const QgsOptionalExpression& visibilityExpression );
|
||||
|
||||
private:
|
||||
void saveConfiguration( QDomElement& elem ) const override;
|
||||
QString typeIdentifier() const override;
|
||||
@ -226,6 +230,7 @@ class CORE_EXPORT QgsAttributeEditorContainer : public QgsAttributeEditorElement
|
||||
bool mIsGroupBox;
|
||||
QList<QgsAttributeEditorElement*> mChildren;
|
||||
int mColumnCount;
|
||||
QgsOptionalExpression mVisibilityExpression;
|
||||
};
|
||||
|
||||
/** \ingroup core
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "qgseditformconfig.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgsrelationmanager.h"
|
||||
|
||||
//#include "qgseditorwidgetregistry.h"
|
||||
|
||||
QgsAttributeEditorContainer::~QgsAttributeEditorContainer()
|
||||
@ -573,6 +574,15 @@ QgsAttributeEditorElement* QgsEditFormConfig::attributeEditorElementFromDomEleme
|
||||
else
|
||||
container->setIsGroupBox( parent );
|
||||
|
||||
bool visibilityExpressionEnabled = elem.attribute( "visibilityExpressionEnabled" ).toInt( &ok );
|
||||
QgsOptionalExpression visibilityExpression;
|
||||
if ( ok )
|
||||
{
|
||||
visibilityExpression.setEnabled( visibilityExpressionEnabled );
|
||||
visibilityExpression.setData( QgsExpression( elem.attribute( "visibilityExpression" ) ) );
|
||||
}
|
||||
container->setVisibilityExpression( visibilityExpression );
|
||||
|
||||
QDomNodeList childNodeList = elem.childNodes();
|
||||
|
||||
for ( int i = 0; i < childNodeList.size(); i++ )
|
||||
@ -627,6 +637,7 @@ QgsAttributeEditorElement* QgsAttributeEditorContainer::clone( QgsAttributeEdito
|
||||
}
|
||||
element->mIsGroupBox = mIsGroupBox;
|
||||
element->mColumnCount = mColumnCount;
|
||||
element->mVisibilityExpression = mVisibilityExpression;
|
||||
|
||||
return element;
|
||||
}
|
||||
@ -635,6 +646,8 @@ void QgsAttributeEditorContainer::saveConfiguration( QDomElement& elem ) const
|
||||
{
|
||||
elem.setAttribute( "columnCount", mColumnCount );
|
||||
elem.setAttribute( "groupBox", mIsGroupBox ? 1 : 0 );
|
||||
elem.setAttribute( "visibilityExpressionEnabled", mVisibilityExpression.enabled() ? 1 : 0 );
|
||||
elem.setAttribute( "visibilityExpression", mVisibilityExpression->expression() );
|
||||
|
||||
Q_FOREACH ( QgsAttributeEditorElement* child, mChildren )
|
||||
{
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "qgseditorwidgetwrapper.h"
|
||||
#include "qgsrelationmanager.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgstabwidget.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QTextStream>
|
||||
@ -42,7 +43,6 @@
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QScrollArea>
|
||||
#include <QTabWidget>
|
||||
#include <QUiLoader>
|
||||
#include <QMessageBox>
|
||||
#include <QSettings>
|
||||
@ -747,6 +747,14 @@ void QgsAttributeForm::updateConstraints( QgsEditorWidgetWrapper *eww )
|
||||
|
||||
// sync ok button status
|
||||
synchronizeEnabledState();
|
||||
|
||||
mExpressionContext.setFeature( ft );
|
||||
|
||||
// Recheck visibility for all containers which are controlled by this value
|
||||
Q_FOREACH ( ContainerInformation* info, mContainerInformationDependency.value( eww->field().name() ) )
|
||||
{
|
||||
info->apply( &mExpressionContext );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -810,6 +818,15 @@ void QgsAttributeForm::displayInvalidConstraintMessage( const QStringList& f,
|
||||
mInvalidConstraintMessage->setStyleSheet( "QLabel { background-color : #ffc800; }" );
|
||||
}
|
||||
|
||||
void QgsAttributeForm::registerContainerInformation( QgsAttributeForm::ContainerInformation* info )
|
||||
{
|
||||
mContainerVisibilityInformation.append( info );
|
||||
Q_FOREACH ( const QString& col, info->expression.referencedColumns() )
|
||||
{
|
||||
mContainerInformationDependency[ col ].append( info );
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsAttributeForm::currentFormValidConstraints( QStringList &invalidFields,
|
||||
QStringList &descriptions )
|
||||
{
|
||||
@ -1095,7 +1112,7 @@ void QgsAttributeForm::init()
|
||||
}
|
||||
}
|
||||
|
||||
QTabWidget* tabWidget = nullptr;
|
||||
QgsTabWidget* tabWidget = nullptr;
|
||||
|
||||
// Tab layout
|
||||
if ( !formWidget && mLayer->editFormConfig().layout() == QgsEditFormConfig::TabLayout )
|
||||
@ -1117,13 +1134,14 @@ void QgsAttributeForm::init()
|
||||
tabWidget = nullptr;
|
||||
WidgetInfo widgetInfo = createWidgetFromDef( widgDef, formWidget, mLayer, mContext );
|
||||
layout->addWidget( widgetInfo.widget, row, column, 1, 2 );
|
||||
registerContainerInformation( new ContainerInformation( widgetInfo.widget, containerDef->visibilityExpression().data() ) );
|
||||
column += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !tabWidget )
|
||||
{
|
||||
tabWidget = new QTabWidget();
|
||||
tabWidget = new QgsTabWidget();
|
||||
layout->addWidget( tabWidget, row, column, 1, 2 );
|
||||
column += 2;
|
||||
}
|
||||
@ -1131,6 +1149,11 @@ void QgsAttributeForm::init()
|
||||
QWidget* tabPage = new QWidget( tabWidget );
|
||||
|
||||
tabWidget->addTab( tabPage, widgDef->name() );
|
||||
|
||||
if ( containerDef->visibilityExpression().enabled() )
|
||||
{
|
||||
registerContainerInformation( new ContainerInformation( tabWidget, tabPage, containerDef->visibilityExpression().data() ) );
|
||||
}
|
||||
QGridLayout* tabPageLayout = new QGridLayout();
|
||||
tabPage->setLayout( tabPageLayout );
|
||||
|
||||
@ -1595,6 +1618,12 @@ QgsAttributeForm::WidgetInfo QgsAttributeForm::createWidgetFromDef( const QgsAtt
|
||||
{
|
||||
WidgetInfo widgetInfo = createWidgetFromDef( childDef, myContainer, vl, context );
|
||||
|
||||
if ( childDef->type() == QgsAttributeEditorElement::AeTypeContainer )
|
||||
{
|
||||
QgsAttributeEditorContainer* containerDef = static_cast<QgsAttributeEditorContainer*>( childDef );
|
||||
registerContainerInformation( new ContainerInformation( widgetInfo.widget, containerDef->visibilityExpression().data() ) );
|
||||
}
|
||||
|
||||
if ( widgetInfo.labelText.isNull() )
|
||||
{
|
||||
gbLayout->addWidget( widgetInfo.widget, row, column, 1, 2 );
|
||||
@ -1875,3 +1904,22 @@ int QgsAttributeForm::messageTimeout()
|
||||
QSettings settings;
|
||||
return settings.value( "/qgis/messageTimeout", 5 ).toInt();
|
||||
}
|
||||
|
||||
void QgsAttributeForm::ContainerInformation::apply( QgsExpressionContext* expressionContext )
|
||||
{
|
||||
bool newVisibility = expression.evaluate( expressionContext ).toBool();
|
||||
|
||||
if ( newVisibility != isVisible )
|
||||
{
|
||||
if ( tabWidget )
|
||||
{
|
||||
tabWidget->setTabVisible( widget, newVisibility );
|
||||
}
|
||||
else
|
||||
{
|
||||
widget->setVisible( newVisibility );
|
||||
}
|
||||
|
||||
isVisible = newVisibility;
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ class QgsAttributeFormEditorWidget;
|
||||
class QgsMessageBar;
|
||||
class QgsMessageBarItem;
|
||||
class QgsWidgetWrapper;
|
||||
class QgsTabWidget;
|
||||
|
||||
/** \ingroup gui
|
||||
* \class QgsAttributeForm
|
||||
@ -343,6 +344,37 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
|
||||
QWidget* mSearchButtonBox;
|
||||
QList<QgsAttributeFormInterface*> mInterfaces;
|
||||
QMap< int, QgsAttributeFormEditorWidget* > mFormEditorWidgets;
|
||||
QgsExpressionContext mExpressionContext;
|
||||
|
||||
struct ContainerInformation
|
||||
{
|
||||
ContainerInformation( QgsTabWidget* tabWidget, QWidget* widget, QgsExpression expression )
|
||||
: tabWidget( tabWidget )
|
||||
, widget( widget )
|
||||
, expression( expression )
|
||||
, isVisible( true )
|
||||
{}
|
||||
|
||||
ContainerInformation( QWidget* widget, QgsExpression expression )
|
||||
: tabWidget( nullptr )
|
||||
, widget( widget )
|
||||
, expression( expression )
|
||||
, isVisible( true )
|
||||
{}
|
||||
|
||||
QgsTabWidget* tabWidget;
|
||||
QWidget* widget;
|
||||
QgsExpression expression;
|
||||
bool isVisible;
|
||||
|
||||
void apply( QgsExpressionContext* expressionContext );
|
||||
};
|
||||
|
||||
void registerContainerInformation( ContainerInformation* info );
|
||||
|
||||
// Contains information about tabs and groupboxes, their visibility state visibility conditions
|
||||
QVector<ContainerInformation*> mContainerVisibilityInformation;
|
||||
QMap<QString, QVector<ContainerInformation*> > mContainerInformationDependency;
|
||||
|
||||
// Variables below are used for python
|
||||
static int sFormCounter;
|
||||
|
@ -110,6 +110,11 @@ QString QgsFieldExpressionWidget::asExpression() const
|
||||
return isExpression() ? currentText() : QgsExpression::quotedColumnRef( currentText() );
|
||||
}
|
||||
|
||||
QString QgsFieldExpressionWidget::expression() const
|
||||
{
|
||||
return asExpression();
|
||||
}
|
||||
|
||||
bool QgsFieldExpressionWidget::isValidExpression( QString *expressionError ) const
|
||||
{
|
||||
QString temp;
|
||||
@ -200,6 +205,11 @@ void QgsFieldExpressionWidget::setField( const QString &fieldName )
|
||||
currentFieldChanged();
|
||||
}
|
||||
|
||||
void QgsFieldExpressionWidget::setExpression( const QString& expression )
|
||||
{
|
||||
setField( expression );
|
||||
}
|
||||
|
||||
void QgsFieldExpressionWidget::editExpression()
|
||||
{
|
||||
QString currentExpression = currentText();
|
||||
|
@ -91,13 +91,25 @@ class GUI_EXPORT QgsFieldExpressionWidget : public QWidget
|
||||
*/
|
||||
QString currentText() const;
|
||||
|
||||
/** Returns the currently selected field or expression. If a field is currently selected, the returned
|
||||
/**
|
||||
* Returns the currently selected field or expression. If a field is currently selected, the returned
|
||||
* value will be converted to a valid expression referencing this field (ie enclosing the field name with
|
||||
* appropriate quotations).
|
||||
* @note added in QGIS 2.14
|
||||
*/
|
||||
QString asExpression() const;
|
||||
|
||||
/**
|
||||
* Returns the currently selected field or expression. If a field is currently selected, the returned
|
||||
* value will be converted to a valid expression referencing this field (ie enclosing the field name with
|
||||
* appropriate quotations).
|
||||
*
|
||||
* Alias for asExpression()
|
||||
*
|
||||
* @note added in QGIS 3.0
|
||||
*/
|
||||
QString expression() const;
|
||||
|
||||
//! Returns the currently used layer
|
||||
QgsVectorLayer* layer() const;
|
||||
|
||||
@ -132,6 +144,14 @@ class GUI_EXPORT QgsFieldExpressionWidget : public QWidget
|
||||
//! sets the current field or expression in the widget
|
||||
void setField( const QString &fieldName );
|
||||
|
||||
/**
|
||||
* Sets the current expression text and if applicable also the field.
|
||||
* Alias for setField.
|
||||
*
|
||||
* @note Added in QGIS 3.0
|
||||
*/
|
||||
void setExpression( const QString& expression );
|
||||
|
||||
protected slots:
|
||||
//! open the expression dialog to edit the current or add a new expression
|
||||
void editExpression();
|
||||
|
Loading…
x
Reference in New Issue
Block a user