diff --git a/python/core/layout/qgslayoutobject.sip b/python/core/layout/qgslayoutobject.sip index f98934c4c4e..225c74fcd6e 100644 --- a/python/core/layout/qgslayoutobject.sip +++ b/python/core/layout/qgslayoutobject.sip @@ -21,6 +21,63 @@ class QgsLayoutObject: QObject %End public: + enum DataDefinedProperty + { + NoProperty, + AllProperties, + TestProperty, + //composer + PresetPaperSize, + PaperWidth, + PaperHeight, + NumPages, + PaperOrientation, + //general + PageNumber, + PositionX, + PositionY, + ItemWidth, + ItemHeight, + ItemRotation, + Transparency, + Opacity, + BlendMode, + ExcludeFromExports, + FrameColor, + BackgroundColor, + //composer + MapRotation, + MapScale, + MapXMin, + MapYMin, + MapXMax, + MapYMax, + MapAtlasMargin, + MapLayers, + MapStylePreset, + //composer + PictureSource, + PictureSvgBackgroundColor, + PictureSvgStrokeColor, + PictureSvgStrokeWidth, + //html + SourceUrl, + //legend + LegendTitle, + LegendColumnCount, + //scalebar + ScalebarFillColor, + ScalebarFillColor2, + ScalebarLineColor, + ScalebarLineWidth, + }; + + static const QgsPropertiesDefinition &propertyDefinitions(); +%Docstring + Returns the layout object property definitions. + :rtype: QgsPropertiesDefinition +%End + QgsLayoutObject( QgsLayout *layout ); %Docstring Constructor for QgsLayoutObject, with the specified parent ``layout``. @@ -38,9 +95,67 @@ class QgsLayoutObject: QObject :rtype: QgsLayout %End + QgsPropertyCollection &dataDefinedProperties(); +%Docstring + Returns a reference to the object's property collection, used for data defined overrides. +.. seealso:: setDataDefinedProperties() + :rtype: QgsPropertyCollection +%End + + + void setDataDefinedProperties( const QgsPropertyCollection &collection ); +%Docstring + Sets the objects's property collection, used for data defined overrides. + \param collection property collection. Existing properties will be replaced. +.. seealso:: dataDefinedProperties() +%End + + + void setCustomProperty( const QString &key, const QVariant &value ); +%Docstring + Set a custom property for the object. + \param key property key. If a property with the same key already exists it will be overwritten. + \param value property value +.. seealso:: customProperty() +.. seealso:: removeCustomProperty() +.. seealso:: customProperties() +%End + + QVariant customProperty( const QString &key, const QVariant &defaultValue = QVariant() ) const; +%Docstring + Read a custom property from the object. + \param key property key + \param defaultValue default value to return if property with matching key does not exist + :return: value of matching property +.. seealso:: setCustomProperty() +.. seealso:: removeCustomProperty() +.. seealso:: customProperties() + :rtype: QVariant +%End + + void removeCustomProperty( const QString &key ); +%Docstring + Remove a custom property from the object. + \param key property key +.. seealso:: setCustomProperty() +.. seealso:: customProperty() +.. seealso:: customProperties() +%End + + QStringList customProperties() const; +%Docstring + Return list of keys stored in custom properties for the object. +.. seealso:: setCustomProperty() +.. seealso:: customProperty() +.. seealso:: removeCustomProperty() + :rtype: list of str +%End + protected: + + }; /************************************************************************ diff --git a/src/core/layout/qgslayoutobject.cpp b/src/core/layout/qgslayoutobject.cpp index 188186729c9..1ee14df8d55 100644 --- a/src/core/layout/qgslayoutobject.cpp +++ b/src/core/layout/qgslayoutobject.cpp @@ -20,8 +20,93 @@ #include "qgslayout.h" #include "qgslayoutobject.h" + +QgsPropertiesDefinition QgsLayoutObject::sPropertyDefinitions; + +void QgsLayoutObject::initPropertyDefinitions() +{ + if ( !sPropertyDefinitions.isEmpty() ) + return; + + sPropertyDefinitions = QgsPropertiesDefinition + { + { QgsLayoutObject::TestProperty, QgsPropertyDefinition( "dataDefinedProperty", QgsPropertyDefinition::DataTypeString, "invalid property", QString() ) }, + { + QgsLayoutObject::PresetPaperSize, QgsPropertyDefinition( "dataDefinedPaperSize", QgsPropertyDefinition::DataTypeString, QObject::tr( "Paper size" ), QObject::tr( "string " ) + QLatin1String( "[A5|A4|A3|A2|A1|A0" + "B5|B4|B3|B2|B1|B0" + "Legal|Ansi A|Ansi B|Ansi C|Ansi D|Ansi E" + "Arch A|Arch B|Arch C|Arch D|Arch E|Arch E1]" + ) ) + }, + { QgsLayoutObject::PaperWidth, QgsPropertyDefinition( "dataDefinedPaperWidth", QObject::tr( "Page width" ), QgsPropertyDefinition::DoublePositive ) }, + { QgsLayoutObject::PaperHeight, QgsPropertyDefinition( "dataDefinedPaperHeight", QObject::tr( "Page height" ), QgsPropertyDefinition::DoublePositive ) }, + { QgsLayoutObject::NumPages, QgsPropertyDefinition( "dataDefinedNumPages", QObject::tr( "Number of pages" ), QgsPropertyDefinition::IntegerPositive ) }, + { QgsLayoutObject::PaperOrientation, QgsPropertyDefinition( "dataDefinedPaperOrientation", QgsPropertyDefinition::DataTypeString, QObject::tr( "Symbol size" ), QObject::tr( "string " ) + QLatin1String( "[portrait|landscape]" ) ) }, + { QgsLayoutObject::PageNumber, QgsPropertyDefinition( "dataDefinedPageNumber", QObject::tr( "Page number" ), QgsPropertyDefinition::IntegerPositive ) }, + { QgsLayoutObject::PositionX, QgsPropertyDefinition( "dataDefinedPositionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double ) }, + { QgsLayoutObject::PositionY, QgsPropertyDefinition( "dataDefinedPositionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double ) }, + { QgsLayoutObject::ItemWidth, QgsPropertyDefinition( "dataDefinedWidth", QObject::tr( "Width" ), QgsPropertyDefinition::DoublePositive ) }, + { QgsLayoutObject::ItemHeight, QgsPropertyDefinition( "dataDefinedHeight", QObject::tr( "Height" ), QgsPropertyDefinition::DoublePositive ) }, + { QgsLayoutObject::ItemRotation, QgsPropertyDefinition( "dataDefinedRotation", QObject::tr( "Rotation angle" ), QgsPropertyDefinition::Rotation ) }, + { QgsLayoutObject::Transparency, QgsPropertyDefinition( "dataDefinedTransparency", QObject::tr( "Transparency" ), QgsPropertyDefinition::Opacity ) }, + { QgsLayoutObject::Opacity, QgsPropertyDefinition( "dataDefinedOpacity", QObject::tr( "Opacity" ), QgsPropertyDefinition::Opacity ) }, + { QgsLayoutObject::BlendMode, QgsPropertyDefinition( "dataDefinedBlendMode", QObject::tr( "Blend mode" ), QgsPropertyDefinition::BlendMode ) }, + { QgsLayoutObject::ExcludeFromExports, QgsPropertyDefinition( "dataDefinedExcludeExports", QObject::tr( "Exclude item from exports" ), QgsPropertyDefinition::Boolean ) }, + { QgsLayoutObject::FrameColor, QgsPropertyDefinition( "dataDefinedFrameColor", QObject::tr( "Frame color" ), QgsPropertyDefinition::ColorWithAlpha ) }, + { QgsLayoutObject::BackgroundColor, QgsPropertyDefinition( "dataDefinedBackgroundColor", QObject::tr( "Background color" ), QgsPropertyDefinition::ColorWithAlpha ) }, + { QgsLayoutObject::MapRotation, QgsPropertyDefinition( "dataDefinedMapRotation", QObject::tr( "Map rotation" ), QgsPropertyDefinition::Rotation ) }, + { QgsLayoutObject::MapScale, QgsPropertyDefinition( "dataDefinedMapScale", QObject::tr( "Map scale" ), QgsPropertyDefinition::DoublePositive ) }, + { QgsLayoutObject::MapXMin, QgsPropertyDefinition( "dataDefinedMapXMin", QObject::tr( "Extent minimum X" ), QgsPropertyDefinition::Double ) }, + { QgsLayoutObject::MapYMin, QgsPropertyDefinition( "dataDefinedMapYMin", QObject::tr( "Extent minimum Y" ), QgsPropertyDefinition::Double ) }, + { QgsLayoutObject::MapXMax, QgsPropertyDefinition( "dataDefinedMapXMax", QObject::tr( "Extent maximum X" ), QgsPropertyDefinition::Double ) }, + { QgsLayoutObject::MapYMax, QgsPropertyDefinition( "dataDefinedMapYMax", QObject::tr( "Extent maximum Y" ), QgsPropertyDefinition::Double ) }, + { QgsLayoutObject::MapAtlasMargin, QgsPropertyDefinition( "dataDefinedMapAtlasMargin", QObject::tr( "Atlas margin" ), QgsPropertyDefinition::DoublePositive ) }, + { QgsLayoutObject::MapLayers, QgsPropertyDefinition( "dataDefinedMapLayers", QgsPropertyDefinition::DataTypeString, QObject::tr( "Symbol size" ), tr( "list of map layer names separated by | characters" ) ) }, + { QgsLayoutObject::MapStylePreset, QgsPropertyDefinition( "dataDefinedMapStylePreset", QgsPropertyDefinition::DataTypeString, QObject::tr( "Symbol size" ), tr( "list of map layer names separated by | characters" ) ) }, + { QgsLayoutObject::PictureSource, QgsPropertyDefinition( "dataDefinedSource", QObject::tr( "Picture source (URL)" ), QgsPropertyDefinition::String ) }, + { QgsLayoutObject::SourceUrl, QgsPropertyDefinition( "dataDefinedSourceUrl", QObject::tr( "Source URL" ), QgsPropertyDefinition::String ) }, + { QgsLayoutObject::PictureSvgBackgroundColor, QgsPropertyDefinition( "dataDefinedSvgBackgroundColor", QObject::tr( "SVG background color" ), QgsPropertyDefinition::ColorWithAlpha ) }, + { QgsLayoutObject::PictureSvgStrokeColor, QgsPropertyDefinition( "dataDefinedSvgStrokeColor", QObject::tr( "SVG stroke color" ), QgsPropertyDefinition::ColorWithAlpha ) }, + { QgsLayoutObject::PictureSvgStrokeWidth, QgsPropertyDefinition( "dataDefinedSvgStrokeWidth", QObject::tr( "SVG stroke width" ), QgsPropertyDefinition::StrokeWidth ) }, + { QgsLayoutObject::LegendTitle, QgsPropertyDefinition( "dataDefinedLegendTitle", QObject::tr( "Legend title" ), QgsPropertyDefinition::String ) }, + { QgsLayoutObject::LegendColumnCount, QgsPropertyDefinition( "dataDefinedLegendColumns", QObject::tr( "Number of columns" ), QgsPropertyDefinition::IntegerPositiveGreaterZero ) }, + { QgsLayoutObject::ScalebarFillColor, QgsPropertyDefinition( "dataDefinedScalebarFill", QObject::tr( "Fill color" ), QgsPropertyDefinition::ColorWithAlpha ) }, + { QgsLayoutObject::ScalebarFillColor2, QgsPropertyDefinition( "dataDefinedScalebarFill2", QObject::tr( "Secondary fill color" ), QgsPropertyDefinition::ColorWithAlpha ) }, + { QgsLayoutObject::ScalebarLineColor, QgsPropertyDefinition( "dataDefinedScalebarLineColor", QObject::tr( "Line color" ), QgsPropertyDefinition::ColorWithAlpha ) }, + { QgsLayoutObject::ScalebarLineWidth, QgsPropertyDefinition( "dataDefinedScalebarLineWidth", QObject::tr( "Line width" ), QgsPropertyDefinition::StrokeWidth ) }, + }; +} + +const QgsPropertiesDefinition &QgsLayoutObject::propertyDefinitions() +{ + QgsLayoutObject::initPropertyDefinitions(); + return sPropertyDefinitions; +} + QgsLayoutObject::QgsLayoutObject( QgsLayout *layout ) : QObject( nullptr ) , mLayout( layout ) { + initPropertyDefinitions(); +} + + +void QgsLayoutObject::setCustomProperty( const QString &key, const QVariant &value ) +{ + mCustomProperties.setValue( key, value ); +} + +QVariant QgsLayoutObject::customProperty( const QString &key, const QVariant &defaultValue ) const +{ + return mCustomProperties.value( key, defaultValue ); +} + +void QgsLayoutObject::removeCustomProperty( const QString &key ) +{ + mCustomProperties.remove( key ); +} + +QStringList QgsLayoutObject::customProperties() const +{ + return mCustomProperties.keys(); } diff --git a/src/core/layout/qgslayoutobject.h b/src/core/layout/qgslayoutobject.h index b9d26483b00..bdedcbb418e 100644 --- a/src/core/layout/qgslayoutobject.h +++ b/src/core/layout/qgslayoutobject.h @@ -19,6 +19,8 @@ #include "qgis_core.h" #include "qgis_sip.h" +#include "qgspropertycollection.h" +#include "qgsobjectcustomproperties.h" #include #include #include @@ -36,6 +38,64 @@ class CORE_EXPORT QgsLayoutObject: public QObject Q_OBJECT public: + /** Data defined properties for different item types + */ + enum DataDefinedProperty + { + NoProperty = 0, //!< No property + AllProperties, //!< All properties for item + TestProperty, //!< Dummy property with no effect on item + //composer page properties + PresetPaperSize, //!< Preset paper size for composition + PaperWidth, //!< Paper width + PaperHeight, //!< Paper height + NumPages, //!< Number of pages in composition + PaperOrientation, //!< Paper orientation + //general composer item properties + PageNumber, //!< Page number for item placement + PositionX, //!< X position on page + PositionY, //!< Y position on page + ItemWidth, //!< Width of item + ItemHeight, //!< Height of item + ItemRotation, //!< Rotation of item + Transparency, //!< Item transparency (deprecated) + Opacity, //!< Item opacity + BlendMode, //!< Item blend mode + ExcludeFromExports, //!< Exclude item from exports + FrameColor, //!< Item frame color + BackgroundColor, //!< Item background color + //composer map + MapRotation, //!< Map rotation + MapScale, //!< Map scale + MapXMin, //!< Map extent x minimum + MapYMin, //!< Map extent y minimum + MapXMax, //!< Map extent x maximum + MapYMax, //!< Map extent y maximum + MapAtlasMargin, //!< Map atlas margin + MapLayers, //!< Map layer set + MapStylePreset, //!< Layer and style map theme + //composer picture + PictureSource, //!< Picture source url + PictureSvgBackgroundColor, //!< SVG background color + PictureSvgStrokeColor, //!< SVG stroke color + PictureSvgStrokeWidth, //!< SVG stroke width + //html item + SourceUrl, //!< Html source url + //legend item + LegendTitle, //!< Legend title + LegendColumnCount, //!< Legend column count + //scalebar item + ScalebarFillColor, //!< Scalebar fill color + ScalebarFillColor2, //!< Scalebar secondary fill color + ScalebarLineColor, //!< Scalebar line color + ScalebarLineWidth, //!< Scalebar line width + }; + + /** + * Returns the layout object property definitions. + */ + static const QgsPropertiesDefinition &propertyDefinitions(); + /** * Constructor for QgsLayoutObject, with the specified parent \a layout. * \note While ownership of a QgsLayoutObject is not passed to the layout, @@ -54,12 +114,80 @@ class CORE_EXPORT QgsLayoutObject: public QObject */ QgsLayout *layout() { return mLayout; } + /** + * Returns a reference to the object's property collection, used for data defined overrides. + * \see setDataDefinedProperties() + */ + QgsPropertyCollection &dataDefinedProperties() { return mDataDefinedProperties; } + + /** + * Returns a reference to the object's property collection, used for data defined overrides. + * \see setDataDefinedProperties() + */ + const QgsPropertyCollection &dataDefinedProperties() const { return mDataDefinedProperties; } SIP_SKIP + + /** + * Sets the objects's property collection, used for data defined overrides. + * \param collection property collection. Existing properties will be replaced. + * \see dataDefinedProperties() + */ + void setDataDefinedProperties( const QgsPropertyCollection &collection ) { mDataDefinedProperties = collection; } + + + /** + * Set a custom property for the object. + * \param key property key. If a property with the same key already exists it will be overwritten. + * \param value property value + * \see customProperty() + * \see removeCustomProperty() + * \see customProperties() + */ + void setCustomProperty( const QString &key, const QVariant &value ); + + /** + * Read a custom property from the object. + * \param key property key + * \param defaultValue default value to return if property with matching key does not exist + * \returns value of matching property + * \see setCustomProperty() + * \see removeCustomProperty() + * \see customProperties() + */ + QVariant customProperty( const QString &key, const QVariant &defaultValue = QVariant() ) const; + + /** + * Remove a custom property from the object. + * \param key property key + * \see setCustomProperty() + * \see customProperty() + * \see customProperties() + */ + void removeCustomProperty( const QString &key ); + + /** + * Return list of keys stored in custom properties for the object. + * \see setCustomProperty() + * \see customProperty() + * \see removeCustomProperty() + */ + QStringList customProperties() const; + protected: QgsLayout *mLayout = nullptr; + QgsPropertyCollection mDataDefinedProperties; + + //! Custom properties for object + QgsObjectCustomProperties mCustomProperties; + private: + //! Property definitions + static QgsPropertiesDefinition sPropertyDefinitions; + + static void initPropertyDefinitions(); + friend class TestQgsLayoutObject; }; diff --git a/tests/src/core/testqgslayoutobject.cpp b/tests/src/core/testqgslayoutobject.cpp index efc268ce4c9..927ca58a717 100644 --- a/tests/src/core/testqgslayoutobject.cpp +++ b/tests/src/core/testqgslayoutobject.cpp @@ -30,6 +30,7 @@ class TestQgsLayoutObject: public QObject void cleanup();// will be called after every testfunction. void creation(); //test creation of QgsLayoutObject void layout(); //test fetching layout from QgsLayoutObject + void customProperties(); private: QgsLayout *mLayout = nullptr; @@ -81,5 +82,34 @@ void TestQgsLayoutObject::layout() delete object; } +void TestQgsLayoutObject::customProperties() +{ + QgsLayoutObject *object = new QgsLayoutObject( mLayout ); + + QCOMPARE( object->customProperty( "noprop", "defaultval" ).toString(), QString( "defaultval" ) ); + QVERIFY( object->customProperties().isEmpty() ); + object->setCustomProperty( QStringLiteral( "testprop" ), "testval" ); + QCOMPARE( object->customProperty( "testprop", "defaultval" ).toString(), QString( "testval" ) ); + QCOMPARE( object->customProperties().length(), 1 ); + QCOMPARE( object->customProperties().at( 0 ), QString( "testprop" ) ); + + //test no crash + object->removeCustomProperty( QStringLiteral( "badprop" ) ); + + object->removeCustomProperty( QStringLiteral( "testprop" ) ); + QVERIFY( object->customProperties().isEmpty() ); + QCOMPARE( object->customProperty( "noprop", "defaultval" ).toString(), QString( "defaultval" ) ); + + object->setCustomProperty( QStringLiteral( "testprop1" ), "testval1" ); + object->setCustomProperty( QStringLiteral( "testprop2" ), "testval2" ); + QStringList keys = object->customProperties(); + QCOMPARE( keys.length(), 2 ); + QVERIFY( keys.contains( "testprop1" ) ); + QVERIFY( keys.contains( "testprop2" ) ); + + delete object; +} + + QGSTEST_MAIN( TestQgsLayoutObject ) #include "testqgslayoutobject.moc"