diff --git a/python/core/auto_generated/qgsattributeeditorelement.sip.in b/python/core/auto_generated/qgsattributeeditorelement.sip.in index afc767d3e11..4428dd6f4c9 100644 --- a/python/core/auto_generated/qgsattributeeditorelement.sip.in +++ b/python/core/auto_generated/qgsattributeeditorelement.sip.in @@ -130,12 +130,13 @@ attribute form if it is set to the drag and drop designer. %End public: - QgsAttributeEditorContainer( const QString &name, QgsAttributeEditorElement *parent ); + QgsAttributeEditorContainer( const QString &name, QgsAttributeEditorElement *parent, const QColor &backgroundColor = QColor() ); %Docstring Creates a new attribute editor container :param name: The name to show as title :param parent: The parent. May be another container. +:param backgroundColor: The optional background color of the container. %End @@ -222,6 +223,20 @@ show or hide this container based on an expression incorporating the field value controlled by editor widgets. .. versionadded:: 3.0 +%End + + QColor backgroundColor() const; +%Docstring +backgroundColor + +:return: background color of the container + +.. versionadded:: 3.8 +%End + + void setBackgroundColor( const QColor &backgroundColor ); +%Docstring +Sets the background color to ``backgroundColor`` %End }; diff --git a/python/gui/auto_generated/qgscollapsiblegroupbox.sip.in b/python/gui/auto_generated/qgscollapsiblegroupbox.sip.in index 3c6688c7eca..9763b50b372 100644 --- a/python/gui/auto_generated/qgscollapsiblegroupbox.sip.in +++ b/python/gui/auto_generated/qgscollapsiblegroupbox.sip.in @@ -134,7 +134,7 @@ Holding Shift modifier key when attempting to toggle collapsed state will expand .. note:: - To add Collapsible properties in promoted QtDesigner widgets, you can add the following "Dynamic properties" by clicking on the green + in the propreties palette: + To add Collapsible properties in promoted QtDesigner widgets, you can add the following "Dynamic properties" by clicking on the green + in the properties palette: bool collapsed, bool saveCollapsedState, bool saveCheckedState, QString syncGroup %End diff --git a/src/app/qgsattributesformproperties.cpp b/src/app/qgsattributesformproperties.cpp index 5d3c68792ba..4722ed50256 100644 --- a/src/app/qgsattributesformproperties.cpp +++ b/src/app/qgsattributesformproperties.cpp @@ -21,6 +21,7 @@ #include "qgsfieldcombobox.h" #include "qgsqmlwidgetwrapper.h" #include "qgsapplication.h" +#include "qgscolorbutton.h" QgsAttributesFormProperties::QgsAttributesFormProperties( QgsVectorLayer *layer, QWidget *parent ) : QWidget( parent ) @@ -451,6 +452,7 @@ QTreeWidgetItem *QgsAttributesFormProperties::loadAttributeEditorTreeItem( QgsAt itemData.setColumnCount( container->columnCount() ); itemData.setShowAsGroupBox( container->isGroupBox() ); + itemData.setBackgroundColor( container->backgroundColor() ); itemData.setVisibilityExpression( container->visibilityExpression() ); newWidget = tree->addItem( parent, itemData ); @@ -582,10 +584,11 @@ QgsAttributeEditorElement *QgsAttributesFormProperties::createAttributeEditorWid case DnDTreeItemData::Container: { - QgsAttributeEditorContainer *container = new QgsAttributeEditorContainer( item->text( 0 ), parent ); + QgsAttributeEditorContainer *container = new QgsAttributeEditorContainer( item->text( 0 ), parent, itemData.backgroundColor() ); container->setColumnCount( itemData.columnCount() ); container->setIsGroupBox( forceGroup ? true : itemData.showAsGroupBox() ); container->setVisibilityExpression( itemData.visibilityExpression() ); + container->setBackgroundColor( itemData.backgroundColor( ) ); for ( int t = 0; t < item->childCount(); t++ ) { @@ -1014,6 +1017,7 @@ void DnDTree::onItemDoubleClicked( QTreeWidgetItem *item, int column ) case QgsAttributesFormProperties::DnDTreeItemData::Container: { QDialog dlg; + dlg.setObjectName( QLatin1Literal( "attributeFormPropertiesContainerDialog" ) ); dlg.setWindowTitle( tr( "Configure Container" ) ); QFormLayout *layout = new QFormLayout() ; dlg.setLayout( layout ); @@ -1046,6 +1050,17 @@ void DnDTree::onItemDoubleClicked( QTreeWidgetItem *item, int column ) layout->addRow( showAsGroupBox ); } + QgsCollapsibleGroupBox *styleGroupBox = new QgsCollapsibleGroupBox( tr( "Style" ), layout->widget() ); + styleGroupBox->setObjectName( QLatin1Literal( "attributeFormPropertiesContainerStyle" ) ); + QFormLayout *customizeGroupBoxLayout = new QFormLayout( styleGroupBox ) ; + QgsColorButton *backgroundColorButton = new QgsColorButton( styleGroupBox, tr( "Container Background Color" ) ); + backgroundColorButton->setShowNull( true ); + backgroundColorButton->setColor( itemData.backgroundColor() ); + customizeGroupBoxLayout->addRow( new QLabel( tr( "Background color" ), styleGroupBox ), + backgroundColorButton ); + styleGroupBox->setLayout( customizeGroupBoxLayout ); + layout->addRow( styleGroupBox ); + QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel ); @@ -1060,6 +1075,7 @@ void DnDTree::onItemDoubleClicked( QTreeWidgetItem *item, int column ) itemData.setShowAsGroupBox( showAsGroupBox ? showAsGroupBox->isChecked() : true ); itemData.setName( title->text() ); itemData.setShowLabel( showLabelCheckbox->isChecked() ); + itemData.setBackgroundColor( backgroundColorButton->color() ); QgsOptionalExpression visibilityExpression; visibilityExpression.setData( QgsExpression( visibilityExpressionWidget->expression() ) ); @@ -1379,3 +1395,13 @@ void QgsAttributesFormProperties::DnDTreeItemData::setQmlElementEditorConfigurat mQmlElementEditorConfiguration = qmlElementEditorConfiguration; } +QColor QgsAttributesFormProperties::DnDTreeItemData::backgroundColor() const +{ + return mBackgroundColor; +} + +void QgsAttributesFormProperties::DnDTreeItemData::setBackgroundColor( const QColor &backgroundColor ) +{ + mBackgroundColor = backgroundColor; +} + diff --git a/src/app/qgsattributesformproperties.h b/src/app/qgsattributesformproperties.h index b54a978ce11..3d03e4fb785 100644 --- a/src/app/qgsattributesformproperties.h +++ b/src/app/qgsattributesformproperties.h @@ -88,10 +88,11 @@ class APP_EXPORT QgsAttributesFormProperties : public QWidget, private Ui_QgsAtt //do we need that DnDTreeItemData() = default; - DnDTreeItemData( Type type, const QString &name, const QString &displayName ) + DnDTreeItemData( Type type, const QString &name, const QString &displayName, const QColor &backgroundColor = QColor() ) : mType( type ) , mName( name ) , mDisplayName( displayName ) + , mBackgroundColor( backgroundColor ) {} QString name() const { return mName; } @@ -123,6 +124,9 @@ class APP_EXPORT QgsAttributesFormProperties : public QWidget, private Ui_QgsAtt QmlElementEditorConfiguration qmlElementEditorConfiguration() const; void setQmlElementEditorConfiguration( QmlElementEditorConfiguration qmlElementEditorConfiguration ); + QColor backgroundColor() const; + void setBackgroundColor( const QColor &backgroundColor ); + private: Type mType = Field; QString mName; @@ -134,6 +138,7 @@ class APP_EXPORT QgsAttributesFormProperties : public QWidget, private Ui_QgsAtt QgsOptionalExpression mVisibilityExpression; RelationEditorConfiguration mRelationEditorConfiguration; QmlElementEditorConfiguration mQmlElementEditorConfiguration; + QColor mBackgroundColor; }; diff --git a/src/core/qgsattributeeditorelement.cpp b/src/core/qgsattributeeditorelement.cpp index 8b534ea15b0..4ab73da95e4 100644 --- a/src/core/qgsattributeeditorelement.cpp +++ b/src/core/qgsattributeeditorelement.cpp @@ -39,6 +39,16 @@ void QgsAttributeEditorContainer::setVisibilityExpression( const QgsOptionalExpr mVisibilityExpression = visibilityExpression; } +QColor QgsAttributeEditorContainer::backgroundColor() const +{ + return mBackgroundColor; +} + +void QgsAttributeEditorContainer::setBackgroundColor( const QColor &backgroundColor ) +{ + mBackgroundColor = backgroundColor; +} + QList QgsAttributeEditorContainer::findElements( QgsAttributeEditorElement::AttributeEditorType type ) const { QList results; diff --git a/src/core/qgsattributeeditorelement.h b/src/core/qgsattributeeditorelement.h index 15927a9d0a6..939f09550ac 100644 --- a/src/core/qgsattributeeditorelement.h +++ b/src/core/qgsattributeeditorelement.h @@ -19,6 +19,7 @@ #include "qgis_core.h" #include "qgsrelation.h" #include "qgsoptionalexpression.h" +#include class QgsRelationManager; @@ -173,11 +174,13 @@ class CORE_EXPORT QgsAttributeEditorContainer : public QgsAttributeEditorElement * * \param name The name to show as title * \param parent The parent. May be another container. + * \param backgroundColor The optional background color of the container. */ - QgsAttributeEditorContainer( const QString &name, QgsAttributeEditorElement *parent ) + QgsAttributeEditorContainer( const QString &name, QgsAttributeEditorElement *parent, const QColor &backgroundColor = QColor() ) : QgsAttributeEditorElement( AeTypeContainer, name, parent ) , mIsGroupBox( true ) , mColumnCount( 1 ) + , mBackgroundColor( backgroundColor ) {} @@ -265,6 +268,18 @@ class CORE_EXPORT QgsAttributeEditorContainer : public QgsAttributeEditorElement */ void setVisibilityExpression( const QgsOptionalExpression &visibilityExpression ); + /** + * \brief backgroundColor + * \return background color of the container + * \since QGIS 3.8 + */ + QColor backgroundColor() const; + + /** + * Sets the background color to \a backgroundColor + */ + void setBackgroundColor( const QColor &backgroundColor ); + private: void saveConfiguration( QDomElement &elem ) const override; QString typeIdentifier() const override; @@ -273,6 +288,7 @@ class CORE_EXPORT QgsAttributeEditorContainer : public QgsAttributeEditorElement QList mChildren; int mColumnCount; QgsOptionalExpression mVisibilityExpression; + QColor mBackgroundColor; }; /** diff --git a/src/core/qgseditformconfig.cpp b/src/core/qgseditformconfig.cpp index 9e4ce27daf4..1d700f3b3bd 100644 --- a/src/core/qgseditformconfig.cpp +++ b/src/core/qgseditformconfig.cpp @@ -525,7 +525,9 @@ QgsAttributeEditorElement *QgsEditFormConfig::attributeEditorElementFromDomEleme if ( elem.tagName() == QLatin1String( "attributeEditorContainer" ) ) { - QgsAttributeEditorContainer *container = new QgsAttributeEditorContainer( context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:formcontainers" ).arg( layerId ), elem.attribute( QStringLiteral( "name" ) ) ), parent ); + QColor backgroundColor( elem.attribute( QStringLiteral( "backgroundColor" ), QString() ) ); + QgsAttributeEditorContainer *container = new QgsAttributeEditorContainer( context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:formcontainers" ).arg( layerId ), + elem.attribute( QStringLiteral( "name" ) ) ), parent, backgroundColor ); bool ok; int cc = elem.attribute( QStringLiteral( "columnCount" ) ).toInt( &ok ); if ( !ok ) @@ -625,7 +627,8 @@ void QgsAttributeEditorContainer::saveConfiguration( QDomElement &elem ) const elem.setAttribute( QStringLiteral( "groupBox" ), mIsGroupBox ? 1 : 0 ); elem.setAttribute( QStringLiteral( "visibilityExpressionEnabled" ), mVisibilityExpression.enabled() ? 1 : 0 ); elem.setAttribute( QStringLiteral( "visibilityExpression" ), mVisibilityExpression->expression() ); - + if ( mBackgroundColor.isValid() ) + elem.setAttribute( QStringLiteral( "backgroundColor" ), mBackgroundColor.name( ) ); Q_FOREACH ( QgsAttributeEditorElement *child, mChildren ) { QDomDocument doc = elem.ownerDocument(); diff --git a/src/gui/qgsattributeform.cpp b/src/gui/qgsattributeform.cpp index 8d63e3a8523..208957aa6fe 100644 --- a/src/gui/qgsattributeform.cpp +++ b/src/gui/qgsattributeform.cpp @@ -1707,10 +1707,12 @@ QgsAttributeForm::WidgetInfo QgsAttributeForm::createWidgetFromDef( const QgsAtt if ( columnCount <= 0 ) columnCount = 1; + QString widgetName; QWidget *myContainer = nullptr; if ( container->isGroupBox() ) { QGroupBox *groupBox = new QGroupBox( parent ); + widgetName = QStringLiteral( "QGroupBox" ); if ( container->showLabel() ) groupBox->setTitle( container->name() ); myContainer = groupBox; @@ -1727,15 +1729,23 @@ QgsAttributeForm::WidgetInfo QgsAttributeForm::createWidgetFromDef( const QgsAtt scrollArea->setWidget( myContainer ); scrollArea->setWidgetResizable( true ); scrollArea->setFrameShape( QFrame::NoFrame ); + widgetName = QStringLiteral( "QScrollArea QWidget" ); newWidgetInfo.widget = scrollArea; } else { newWidgetInfo.widget = myContainer; + widgetName = QStringLiteral( "QWidget" ); } } + if ( container->backgroundColor().isValid() ) + { + QString style {QStringLiteral( "background-color: %1;" ).arg( container->backgroundColor().name() )}; + newWidgetInfo.widget->setStyleSheet( style ); + } + QGridLayout *gbLayout = new QGridLayout(); myContainer->setLayout( gbLayout ); diff --git a/src/gui/qgscollapsiblegroupbox.h b/src/gui/qgscollapsiblegroupbox.h index ec2a7cbfceb..2b502a59aa8 100644 --- a/src/gui/qgscollapsiblegroupbox.h +++ b/src/gui/qgscollapsiblegroupbox.h @@ -171,7 +171,7 @@ class GUI_EXPORT QgsCollapsibleGroupBoxBasic : public QGroupBox * Holding Alt modifier key when toggling collapsed state will synchronize the toggling across other collapsible group boxes with the same syncGroup QString value * Holding Shift modifier key when attempting to toggle collapsed state will expand current group box, then collapse any others with the same syncGroup QString value * \see basic class QgsCollapsibleGroupBoxBasic which does not auto-save states - * \note To add Collapsible properties in promoted QtDesigner widgets, you can add the following "Dynamic properties" by clicking on the green + in the propreties palette: + * \note To add Collapsible properties in promoted QtDesigner widgets, you can add the following "Dynamic properties" by clicking on the green + in the properties palette: * bool collapsed, bool saveCollapsedState, bool saveCheckedState, QString syncGroup */ diff --git a/tests/src/python/test_qgseditformconfig.py b/tests/src/python/test_qgseditformconfig.py index 4b91bd465ab..ee983d7a017 100644 --- a/tests/src/python/test_qgseditformconfig.py +++ b/tests/src/python/test_qgseditformconfig.py @@ -20,11 +20,14 @@ from qgis.core import (QgsApplication, QgsVectorLayer, QgsReadWriteContext, QgsEditFormConfig, - QgsFetchedContent) + QgsFetchedContent, + QgsAttributeEditorContainer, + ) from qgis.gui import QgsGui from qgis.testing import start_app, unittest from qgis.PyQt.QtXml import QDomDocument, QDomElement +from qgis.PyQt.QtGui import QColor from utilities import unitTestDataPath import socketserver import threading @@ -84,14 +87,16 @@ class TestQgsEditFormConfig(unittest.TestCase): config.setLayout(QgsEditFormConfig.GeneratedLayout) self.assertEqual(config.layout(), QgsEditFormConfig.GeneratedLayout) - uiLocal = os.path.join(unitTestDataPath(), '/qgis_local_server/layer_attribute_form.ui') + uiLocal = os.path.join( + unitTestDataPath(), '/qgis_local_server/layer_attribute_form.ui') config.setUiForm(uiLocal) self.assertEqual(config.layout(), QgsEditFormConfig.UiFileLayout) config.setLayout(QgsEditFormConfig.GeneratedLayout) self.assertEqual(config.layout(), QgsEditFormConfig.GeneratedLayout) - uiUrl = 'http://localhost:' + str(self.port) + '/qgis_local_server/layer_attribute_form.ui' + uiUrl = 'http://localhost:' + \ + str(self.port) + '/qgis_local_server/layer_attribute_form.ui' config.setUiForm(uiUrl) self.assertEqual(config.layout(), QgsEditFormConfig.UiFileLayout) content = QgsApplication.networkContentFetcherRegistry().fetch(uiUrl) @@ -140,6 +145,19 @@ class TestQgsEditFormConfig(unittest.TestCase): self.assertFalse(config.labelOnTop(0)) self.assertFalse(config.labelOnTop(1)) + def test_backgroundColorSerialize(self): + """Test backgroundColor serialization""" + + layer = self.createLayer() + config = layer.editFormConfig() + color_name = '#ff00ff' + container = QgsAttributeEditorContainer('container name', None, QColor('#ff00ff')) + doc = QDomDocument() + element = container.toDomElement(doc) + config = QgsEditFormConfig() + container2 = config.attributeEditorElementFromDomElement(element, None, self.layer.id()) + self.assertEqual(container2.backgroundColor().name(), color_name) + if __name__ == '__main__': unittest.main()