Skip to content

Commit d23abf9

Browse files
committedJul 3, 2017
Add registration of item types to QgsLayoutItemRegistry
1 parent bfb4556 commit d23abf9

File tree

6 files changed

+399
-2
lines changed

6 files changed

+399
-2
lines changed
 

‎python/core/layout/qgslayoutitemregistry.sip

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,70 @@
88

99

1010

11+
class QgsLayoutItemAbstractMetadata
12+
{
13+
%Docstring
14+
Stores metadata about one layout item class.
15+
.. note::
16+
17+
In C++ you can use QgsSymbolLayerMetadata convenience class.
18+
.. versionadded:: 3.0
19+
%End
20+
21+
%TypeHeaderCode
22+
#include "qgslayoutitemregistry.h"
23+
%End
24+
public:
25+
26+
QgsLayoutItemAbstractMetadata( int type, const QString &visibleName );
27+
%Docstring
28+
Constructor for QgsLayoutItemAbstractMetadata with the specified class ``type``
29+
and ``visibleName``.
30+
%End
31+
32+
virtual ~QgsLayoutItemAbstractMetadata();
33+
34+
int type() const;
35+
%Docstring
36+
Returns the unique item type code for the layout item class.
37+
:rtype: int
38+
%End
39+
40+
QString visibleName() const;
41+
%Docstring
42+
Returns a translated, user visible name for the layout item class.
43+
:rtype: str
44+
%End
45+
46+
virtual QgsLayoutItem *createItem( QgsLayout *layout, const QVariantMap &properties ) = 0 /Factory/;
47+
%Docstring
48+
Creates a layout item of this class for a specified ``layout``, given the map of ``properties``.
49+
:rtype: QgsLayoutItem
50+
%End
51+
52+
virtual QWidget *createItemWidget() /Factory/;
53+
%Docstring
54+
Creates a configuration widget for layout items of this type. Can return None if no configuration GUI is required.
55+
:rtype: QWidget
56+
%End
57+
58+
virtual void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving );
59+
%Docstring
60+
Resolve paths in the item's ``properties`` (if there are any paths).
61+
When ``saving`` is true, paths are converted from absolute to relative,
62+
when ``saving`` is false, paths are converted from relative to absolute.
63+
This ensures that paths in project files can be relative, but in item
64+
instances the paths are always absolute.
65+
%End
66+
67+
};
68+
69+
70+
71+
72+
73+
74+
1175
class QgsLayoutItemRegistry : QObject
1276
{
1377
%Docstring
@@ -43,7 +107,49 @@ class QgsLayoutItemRegistry : QObject
43107
QgsApplication.layoutItemRegistry().
44108
%End
45109

110+
~QgsLayoutItemRegistry();
111+
112+
113+
QgsLayoutItemAbstractMetadata *itemMetadata( int type ) const;
114+
%Docstring
115+
Returns the metadata for the specified item ``type``. Returns None if
116+
a corresponding type was not found in the registry.
117+
:rtype: QgsLayoutItemAbstractMetadata
118+
%End
119+
120+
bool addLayoutItemType( QgsLayoutItemAbstractMetadata *metadata /Transfer/ );
121+
%Docstring
122+
Registers a new layout item type. Takes ownership of the metadata instance.
123+
:rtype: bool
124+
%End
125+
126+
QgsLayoutItem *createItem( int type, QgsLayout *layout, const QVariantMap &properties = QVariantMap() ) const /Factory/;
127+
%Docstring
128+
Creates a new instance of a layout item given the item ``type``, target ``layout`` and ``properties``.
129+
:rtype: QgsLayoutItem
130+
%End
131+
132+
QWidget *createItemWidget( int type ) const /Factory/;
133+
%Docstring
134+
Creates a new instance of a layout item configuration widget for the specified item ``type``.
135+
:rtype: QWidget
136+
%End
137+
138+
void resolvePaths( int type, QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) const;
139+
%Docstring
140+
Resolve paths in properties of a particular symbol layer.
141+
This normally means converting relative paths to absolute paths when loading
142+
and converting absolute paths to relative paths when saving.
143+
%End
144+
145+
QMap< int, QString> itemTypes() const;
146+
%Docstring
147+
Returns a map of available item types to translated name.
148+
:rtype: QMap< int, str>
149+
%End
46150

151+
private:
152+
QgsLayoutItemRegistry( const QgsLayoutItemRegistry &rh );
47153
};
48154

49155

‎python/core/symbology-ng/qgssymbollayerregistry.sip

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ Create a symbol layer of this type given the map of properties.
6363
Resolve paths in symbol layer's properties (if there are any paths).
6464
When saving is true, paths are converted from absolute to relative,
6565
when saving is false, paths are converted from relative to absolute.
66-
This ensures that paths in project files are absolute, but in symbol layer
66+
This ensures that paths in project files can be relative, but in symbol layer
6767
instances the paths are always absolute
6868
.. versionadded:: 3.0
6969
%End

‎src/core/layout/qgslayoutitemregistry.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,58 @@ QgsLayoutItemRegistry::QgsLayoutItemRegistry( QObject *parent )
2121
{
2222

2323
}
24+
25+
QgsLayoutItemRegistry::~QgsLayoutItemRegistry()
26+
{
27+
qDeleteAll( mMetadata );
28+
}
29+
30+
QgsLayoutItemAbstractMetadata *QgsLayoutItemRegistry::itemMetadata( int type ) const
31+
{
32+
return mMetadata.value( type );
33+
}
34+
35+
bool QgsLayoutItemRegistry::addLayoutItemType( QgsLayoutItemAbstractMetadata *metadata )
36+
{
37+
if ( !metadata || mMetadata.contains( metadata->type() ) )
38+
return false;
39+
40+
mMetadata[metadata->type()] = metadata;
41+
return true;
42+
}
43+
44+
QgsLayoutItem *QgsLayoutItemRegistry::createItem( int type, QgsLayout *layout, const QVariantMap &properties ) const
45+
{
46+
if ( !mMetadata.contains( type ) )
47+
return nullptr;
48+
49+
return mMetadata[type]->createItem( layout, properties );
50+
}
51+
52+
QWidget *QgsLayoutItemRegistry::createItemWidget( int type ) const
53+
{
54+
if ( !mMetadata.contains( type ) )
55+
return nullptr;
56+
57+
return mMetadata[type]->createItemWidget();
58+
}
59+
60+
void QgsLayoutItemRegistry::resolvePaths( int type, QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) const
61+
{
62+
if ( !mMetadata.contains( type ) )
63+
return;
64+
65+
mMetadata[type]->resolvePaths( properties, pathResolver, saving );
66+
67+
}
68+
69+
QMap<int, QString> QgsLayoutItemRegistry::itemTypes() const
70+
{
71+
QMap<int, QString> types;
72+
QMap<int, QgsLayoutItemAbstractMetadata *>::ConstIterator it = mMetadata.constBegin();
73+
for ( ; it != mMetadata.constEnd(); ++it )
74+
{
75+
types.insert( it.key(), it.value()->visibleName() );
76+
}
77+
return types;
78+
}

‎src/core/layout/qgslayoutitemregistry.h

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,152 @@
1717
#define QGSLAYOUTITEMREGISTRY_H
1818

1919
#include "qgis_core.h"
20+
#include "qgis_sip.h"
21+
#include "qgspathresolver.h"
2022
#include <QGraphicsItem> //for QGraphicsItem::UserType
23+
#include <functional>
2124

25+
class QgsLayout;
2226
class QgsLayoutItem;
2327

28+
/**
29+
* \ingroup core
30+
* \brief Stores metadata about one layout item class.
31+
* \note In C++ you can use QgsSymbolLayerMetadata convenience class.
32+
* \since QGIS 3.0
33+
*/
34+
class CORE_EXPORT QgsLayoutItemAbstractMetadata
35+
{
36+
public:
37+
38+
/**
39+
* Constructor for QgsLayoutItemAbstractMetadata with the specified class \a type
40+
* and \a visibleName.
41+
*/
42+
QgsLayoutItemAbstractMetadata( int type, const QString &visibleName )
43+
: mType( type )
44+
, mVisibleName( visibleName )
45+
{}
46+
47+
virtual ~QgsLayoutItemAbstractMetadata() = default;
48+
49+
/**
50+
* Returns the unique item type code for the layout item class.
51+
*/
52+
int type() const { return mType; }
53+
54+
/**
55+
* Returns a translated, user visible name for the layout item class.
56+
*/
57+
QString visibleName() const { return mVisibleName; }
58+
59+
/**
60+
* Creates a layout item of this class for a specified \a layout, given the map of \a properties.
61+
*/
62+
virtual QgsLayoutItem *createItem( QgsLayout *layout, const QVariantMap &properties ) = 0 SIP_FACTORY;
63+
64+
/**
65+
* Creates a configuration widget for layout items of this type. Can return nullptr if no configuration GUI is required.
66+
*/
67+
virtual QWidget *createItemWidget() SIP_FACTORY { return nullptr; }
68+
69+
/**
70+
* Resolve paths in the item's \a properties (if there are any paths).
71+
* When \a saving is true, paths are converted from absolute to relative,
72+
* when \a saving is false, paths are converted from relative to absolute.
73+
* This ensures that paths in project files can be relative, but in item
74+
* instances the paths are always absolute.
75+
*/
76+
virtual void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving )
77+
{
78+
Q_UNUSED( properties );
79+
Q_UNUSED( pathResolver );
80+
Q_UNUSED( saving );
81+
}
82+
83+
private:
84+
85+
int mType = -1;
86+
QString mVisibleName;
87+
};
88+
89+
//! Layout item creation function
90+
typedef std::function<QgsLayoutItem *( QgsLayout *, const QVariantMap & )> QgsLayoutItemCreateFunc SIP_SKIP;
91+
92+
//! Layout item configuration widget creation function
93+
typedef std::function<QWidget *()> QgsLayoutItemWidgetFunc SIP_SKIP;
94+
95+
//! Layout item path resolver function
96+
typedef std::function<void( QVariantMap &, const QgsPathResolver &, bool )> QgsLayoutItemPathResolverFunc SIP_SKIP;
97+
98+
#ifndef SIP_RUN
99+
100+
/**
101+
* \ingroup core
102+
* Convenience metadata class that uses static functions to create layout items and their configuration widgets.
103+
* \since QGIS 3.0
104+
* \note not available in Python bindings
105+
*/
106+
class CORE_EXPORT QgsLayoutItemMetadata : public QgsLayoutItemAbstractMetadata
107+
{
108+
public:
109+
110+
/**
111+
* Constructor for QgsLayoutItemMetadata with the specified class \a type
112+
* and \a visibleName, and function pointers for the various item and
113+
* configuration widget creation functions.
114+
*/
115+
QgsLayoutItemMetadata( int type, const QString &visibleName,
116+
QgsLayoutItemCreateFunc pfCreate,
117+
QgsLayoutItemPathResolverFunc pfPathResolver = nullptr,
118+
QgsLayoutItemWidgetFunc pfWidget = nullptr )
119+
: QgsLayoutItemAbstractMetadata( type, visibleName )
120+
, mCreateFunc( pfCreate )
121+
, mWidgetFunc( pfWidget )
122+
, mPathResolverFunc( pfPathResolver )
123+
{}
124+
125+
/**
126+
* Returns the classes' item creation function.
127+
*/
128+
QgsLayoutItemCreateFunc createFunction() const { return mCreateFunc; }
129+
130+
/**
131+
* Returns the classes' configuration widget creation function.
132+
* \see setWidgetFunction()
133+
*/
134+
QgsLayoutItemWidgetFunc widgetFunction() const { return mWidgetFunc; }
135+
136+
/**
137+
* Returns the classes' path resolver function.
138+
*/
139+
QgsLayoutItemPathResolverFunc pathResolverFunction() const { return mPathResolverFunc; }
140+
141+
/**
142+
* Sets the classes' configuration widget creation \a function.
143+
* \see widgetFunction()
144+
*/
145+
void setWidgetFunction( QgsLayoutItemWidgetFunc function ) { mWidgetFunc = function; }
146+
147+
virtual QgsLayoutItem *createItem( QgsLayout *layout, const QVariantMap &properties ) override { return mCreateFunc ? mCreateFunc( layout, properties ) : nullptr; }
148+
virtual QWidget *createItemWidget() override { return mWidgetFunc ? mWidgetFunc() : nullptr; }
149+
virtual void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) override
150+
{
151+
if ( mPathResolverFunc )
152+
mPathResolverFunc( properties, pathResolver, saving );
153+
}
154+
155+
protected:
156+
QgsLayoutItemCreateFunc mCreateFunc = nullptr;
157+
QgsLayoutItemWidgetFunc mWidgetFunc = nullptr;
158+
QgsLayoutItemPathResolverFunc mPathResolverFunc = nullptr;
159+
160+
};
161+
162+
#endif
163+
164+
165+
24166
/**
25167
* \ingroup core
26168
* \class QgsLayoutItemRegistry
@@ -57,8 +199,52 @@ class CORE_EXPORT QgsLayoutItemRegistry : public QObject
57199
*/
58200
QgsLayoutItemRegistry( QObject *parent = nullptr );
59201

202+
~QgsLayoutItemRegistry();
203+
204+
//! QgsLayoutItemRegistry cannot be copied.
205+
QgsLayoutItemRegistry( const QgsLayoutItemRegistry &rh ) = delete;
206+
//! QgsLayoutItemRegistryQgsLayoutItemRegistry cannot be copied.
207+
QgsLayoutItemRegistry &operator=( const QgsLayoutItemRegistry &rh ) = delete;
208+
209+
/**
210+
* Returns the metadata for the specified item \a type. Returns nullptr if
211+
* a corresponding type was not found in the registry.
212+
*/
213+
QgsLayoutItemAbstractMetadata *itemMetadata( int type ) const;
214+
215+
/**
216+
* Registers a new layout item type. Takes ownership of the metadata instance.
217+
*/
218+
bool addLayoutItemType( QgsLayoutItemAbstractMetadata *metadata SIP_TRANSFER );
219+
220+
/**
221+
* Creates a new instance of a layout item given the item \a type, target \a layout and \a properties.
222+
*/
223+
QgsLayoutItem *createItem( int type, QgsLayout *layout, const QVariantMap &properties = QVariantMap() ) const SIP_FACTORY;
224+
225+
/**
226+
* Creates a new instance of a layout item configuration widget for the specified item \a type.
227+
*/
228+
QWidget *createItemWidget( int type ) const SIP_FACTORY;
229+
230+
/**
231+
* Resolve paths in properties of a particular symbol layer.
232+
* This normally means converting relative paths to absolute paths when loading
233+
* and converting absolute paths to relative paths when saving.
234+
*/
235+
void resolvePaths( int type, QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) const;
236+
237+
/**
238+
* Returns a map of available item types to translated name.
239+
*/
240+
QMap< int, QString> itemTypes() const;
60241

61242
private:
243+
#ifdef SIP_RUN
244+
QgsLayoutItemRegistry( const QgsLayoutItemRegistry &rh );
245+
#endif
246+
247+
QMap<int, QgsLayoutItemAbstractMetadata *> mMetadata;
62248

63249
};
64250

‎src/core/symbology-ng/qgssymbollayerregistry.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class CORE_EXPORT QgsSymbolLayerAbstractMetadata
5555
/** Resolve paths in symbol layer's properties (if there are any paths).
5656
* When saving is true, paths are converted from absolute to relative,
5757
* when saving is false, paths are converted from relative to absolute.
58-
* This ensures that paths in project files are absolute, but in symbol layer
58+
* This ensures that paths in project files can be relative, but in symbol layer
5959
* instances the paths are always absolute
6060
* \since QGIS 3.0
6161
*/

‎tests/src/core/testqgslayoutitem.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
***************************************************************************/
1717

1818
#include "qgslayoutitem.h"
19+
#include "qgslayoutitemregistry.h"
1920
#include "qgslayout.h"
2021
#include "qgsmultirenderchecker.h"
2122
#include "qgstest.h"
@@ -33,6 +34,7 @@ class TestQgsLayoutItem: public QObject
3334
void init();// will be called before each testfunction is executed.
3435
void cleanup();// will be called after every testfunction.
3536
void creation(); //test creation of QgsLayoutItem
37+
void registry();
3638

3739
private:
3840

@@ -103,6 +105,54 @@ void TestQgsLayoutItem::creation()
103105
delete item;
104106
}
105107

108+
void TestQgsLayoutItem::registry()
109+
{
110+
// test QgsLayoutItemRegistry
111+
QgsLayoutItemRegistry registry;
112+
113+
// empty registry
114+
QVERIFY( !registry.itemMetadata( -1 ) );
115+
QVERIFY( registry.itemTypes().isEmpty() );
116+
QVERIFY( !registry.createItem( 1, nullptr ) );
117+
QVERIFY( !registry.createItemWidget( 1 ) );
118+
119+
auto create = []( QgsLayout * layout, const QVariantMap & )->QgsLayoutItem*
120+
{
121+
return new TestItem( layout );
122+
};
123+
auto createWidget = []()->QWidget*
124+
{
125+
return new QWidget();
126+
};
127+
auto resolve = []( QVariantMap & props, const QgsPathResolver &, bool )
128+
{
129+
props.clear();
130+
};
131+
QgsLayoutItemMetadata *metadata = new QgsLayoutItemMetadata( 2, QStringLiteral( "my type" ), create, resolve, createWidget );
132+
QVERIFY( registry.addLayoutItemType( metadata ) );
133+
// duplicate type id
134+
QVERIFY( !registry.addLayoutItemType( metadata ) );
135+
136+
//retrieve metadata
137+
QVERIFY( !registry.itemMetadata( -1 ) );
138+
QCOMPARE( registry.itemMetadata( 2 )->visibleName(), QStringLiteral( "my type" ) );
139+
QCOMPARE( registry.itemTypes().count(), 1 );
140+
QCOMPARE( registry.itemTypes().value( 2 ), QStringLiteral( "my type" ) );
141+
QgsLayoutItem *item = registry.createItem( 2, nullptr );
142+
QVERIFY( item );
143+
QVERIFY( dynamic_cast< TestItem *>( item ) );
144+
delete item;
145+
QWidget *config = registry.createItemWidget( 2 );
146+
QVERIFY( config );
147+
delete config;
148+
QVariantMap props;
149+
props.insert( QStringLiteral( "a" ), 5 );
150+
registry.resolvePaths( 1, props, QgsPathResolver(), true );
151+
QCOMPARE( props.size(), 1 );
152+
registry.resolvePaths( 2, props, QgsPathResolver(), true );
153+
QVERIFY( props.isEmpty() );
154+
}
155+
106156
bool TestQgsLayoutItem::renderCheck( QString testName, QImage &image, int mismatchCount )
107157
{
108158
mReport += "<h2>" + testName + "</h2>\n";

0 commit comments

Comments
 (0)
Please sign in to comment.