Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgslayoutitemregistry.h
3 : : ------------------------
4 : : begin : June 2017
5 : : copyright : (C) 2017 by Nyall Dawson
6 : : email : nyall dot dawson at gmail dot com
7 : : ***************************************************************************/
8 : : /***************************************************************************
9 : : * *
10 : : * This program is free software; you can redistribute it and/or modify *
11 : : * it under the terms of the GNU General Public License as published by *
12 : : * the Free Software Foundation; either version 2 of the License, or *
13 : : * (at your option) any later version. *
14 : : * *
15 : : ***************************************************************************/
16 : : #ifndef QGSLAYOUTITEMREGISTRY_H
17 : : #define QGSLAYOUTITEMREGISTRY_H
18 : :
19 : : #include "qgis_core.h"
20 : : #include "qgis_sip.h"
21 : : #include "qgsapplication.h"
22 : : #include "qgspathresolver.h"
23 : : #include <QGraphicsItem> //for QGraphicsItem::UserType
24 : : #include <QIcon>
25 : : #include <functional>
26 : :
27 : : #include "qgslayoutitem.h" // temporary
28 : :
29 : : class QgsLayout;
30 : : class QgsLayoutView;
31 : : class QgsLayoutItem;
32 : : class QgsFillSymbol;
33 : : class QgsLayoutMultiFrame;
34 : :
35 : : /**
36 : : * \ingroup core
37 : : * \brief Stores metadata about one layout item class.
38 : : *
39 : : * A companion class, QgsLayoutItemAbstractGuiMetadata, handles the
40 : : * GUI behavior of QgsLayoutItems.
41 : : *
42 : : * \note In C++ you can use QgsLayoutItemMetadata convenience class.
43 : : * \since QGIS 3.0
44 : : */
45 : : class CORE_EXPORT QgsLayoutItemAbstractMetadata
46 : : {
47 : : public:
48 : :
49 : : /**
50 : : * Constructor for QgsLayoutItemAbstractMetadata with the specified class \a type
51 : : * and \a visibleName.
52 : : *
53 : : * The optional \a visiblePluralName argument can be used to specify a plural variant of the item type.
54 : : */
55 : 60 : QgsLayoutItemAbstractMetadata( int type, const QString &visibleName, const QString &visiblePluralName = QString() )
56 : 60 : : mType( type )
57 : 60 : , mVisibleName( visibleName )
58 : 60 : , mVisibleNamePlural( visiblePluralName.isEmpty() ? visibleName : visiblePluralName )
59 : 120 : {}
60 : :
61 : 60 : virtual ~QgsLayoutItemAbstractMetadata() = default;
62 : :
63 : : /**
64 : : * Returns the unique item type code for the layout item class.
65 : : */
66 : 180 : int type() const { return mType; }
67 : :
68 : : /**
69 : : * Returns a translated, user visible name for the layout item class.
70 : : * \see visiblePluralName()
71 : : */
72 : 60 : QString visibleName() const { return mVisibleName; }
73 : :
74 : : /**
75 : : * Returns a translated, user visible name for plurals of the layout item class (e.g. "Labels" for a "Label" item).
76 : : * \since QGIS 3.10
77 : : */
78 : 0 : QString visiblePluralName() const { return mVisibleNamePlural; }
79 : :
80 : : /*
81 : : * IMPORTANT: While it seems like /Factory/ would be the correct annotations here, that's not
82 : : * the case.
83 : : * As per Phil Thomson's advice on https://www.riverbankcomputing.com/pipermail/pyqt/2017-July/039450.html:
84 : : *
85 : : * "
86 : : * /Factory/ is used when the instance returned is guaranteed to be new to Python.
87 : : * In this case it isn't because it has already been seen when being returned by QgsProcessingAlgorithm::createInstance()
88 : : * (However for a different sub-class implemented in C++ then it would be the first time it was seen
89 : : * by Python so the /Factory/ on create() would be correct.)
90 : : *
91 : : * You might try using /TransferBack/ on create() instead - that might be the best compromise.
92 : : * "
93 : : */
94 : :
95 : : /**
96 : : * Creates a layout item of this class for a specified \a layout.
97 : : */
98 : : virtual QgsLayoutItem *createItem( QgsLayout *layout ) = 0 SIP_TRANSFERBACK;
99 : :
100 : : /**
101 : : * Resolve paths in the item's \a properties (if there are any paths).
102 : : * When \a saving is TRUE, paths are converted from absolute to relative,
103 : : * when \a saving is FALSE, paths are converted from relative to absolute.
104 : : * This ensures that paths in project files can be relative, but in item
105 : : * instances the paths are always absolute.
106 : : */
107 : 0 : virtual void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving )
108 : : {
109 : 0 : Q_UNUSED( properties )
110 : 0 : Q_UNUSED( pathResolver )
111 : : Q_UNUSED( saving )
112 : 0 : }
113 : :
114 : : private:
115 : :
116 : : int mType = -1;
117 : : QString mVisibleName;
118 : : QString mVisibleNamePlural;
119 : : };
120 : :
121 : : //! Layout item creation function
122 : : typedef std::function<QgsLayoutItem *( QgsLayout * )> QgsLayoutItemCreateFunc SIP_SKIP;
123 : :
124 : : //! Layout item path resolver function
125 : : typedef std::function<void( QVariantMap &, const QgsPathResolver &, bool )> QgsLayoutItemPathResolverFunc SIP_SKIP;
126 : :
127 : : #ifndef SIP_RUN
128 : :
129 : : /**
130 : : * \ingroup core
131 : : * \brief Convenience metadata class that uses static functions to create layout items and their configuration widgets.
132 : : * \note not available in Python bindings
133 : : * \since QGIS 3.0
134 : : */
135 : 120 : class CORE_EXPORT QgsLayoutItemMetadata : public QgsLayoutItemAbstractMetadata
136 : : {
137 : : public:
138 : :
139 : : /**
140 : : * Constructor for QgsLayoutItemMetadata with the specified class \a type
141 : : * and \a visibleName, and function pointers for the various item creation functions.
142 : : *
143 : : * The \a visiblePluralName argument is used to specify a plural variant of the item type.
144 : : */
145 : 60 : QgsLayoutItemMetadata( int type, const QString &visibleName, const QString &visiblePluralName,
146 : : const QgsLayoutItemCreateFunc &pfCreate,
147 : : const QgsLayoutItemPathResolverFunc &pfPathResolver = nullptr )
148 : 60 : : QgsLayoutItemAbstractMetadata( type, visibleName, visiblePluralName )
149 : 60 : , mCreateFunc( pfCreate )
150 : 60 : , mPathResolverFunc( pfPathResolver )
151 : 180 : {}
152 : :
153 : : /**
154 : : * Returns the classes' item creation function.
155 : : */
156 : : QgsLayoutItemCreateFunc createFunction() const { return mCreateFunc; }
157 : :
158 : : /**
159 : : * Returns the classes' path resolver function.
160 : : */
161 : : QgsLayoutItemPathResolverFunc pathResolverFunction() const { return mPathResolverFunc; }
162 : :
163 : 0 : QgsLayoutItem *createItem( QgsLayout *layout ) override { return mCreateFunc ? mCreateFunc( layout ) : nullptr; }
164 : :
165 : 0 : void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) override
166 : : {
167 : 0 : if ( mPathResolverFunc )
168 : 0 : mPathResolverFunc( properties, pathResolver, saving );
169 : 0 : }
170 : :
171 : : protected:
172 : : QgsLayoutItemCreateFunc mCreateFunc = nullptr;
173 : : QgsLayoutItemPathResolverFunc mPathResolverFunc = nullptr;
174 : :
175 : : };
176 : :
177 : : #endif
178 : :
179 : : /**
180 : : * \ingroup core
181 : : * \brief Stores metadata about one layout multiframe class.
182 : : *
183 : : * A companion class, QgsLayoutMultiFrameAbstractGuiMetadata, handles the
184 : : * GUI behavior of QgsLayoutMultiFrames.
185 : : *
186 : : * \note In C++ you can use QgsLayoutMultiFrameMetadata convenience class.
187 : : * \since QGIS 3.0
188 : : */
189 : : class CORE_EXPORT QgsLayoutMultiFrameAbstractMetadata
190 : : {
191 : : public:
192 : :
193 : : /**
194 : : * Constructor for QgsLayoutMultiFrameAbstractMetadata with the specified class \a type
195 : : * and \a visibleName.
196 : : */
197 : 20 : QgsLayoutMultiFrameAbstractMetadata( int type, const QString &visibleName )
198 : 20 : : mType( type )
199 : 20 : , mVisibleName( visibleName )
200 : 40 : {}
201 : :
202 : 20 : virtual ~QgsLayoutMultiFrameAbstractMetadata() = default;
203 : :
204 : : /**
205 : : * Returns the unique item type code for the layout multiframe class.
206 : : */
207 : 60 : int type() const { return mType; }
208 : :
209 : : /**
210 : : * Returns an icon representing the layout multiframe type.
211 : : */
212 : 0 : virtual QIcon icon() const { return QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ); }
213 : :
214 : : /**
215 : : * Returns a translated, user visible name for the layout multiframe class.
216 : : */
217 : 20 : QString visibleName() const { return mVisibleName; }
218 : :
219 : : /*
220 : : * IMPORTANT: While it seems like /Factory/ would be the correct annotations here, that's not
221 : : * the case.
222 : : * As per Phil Thomson's advice on https://www.riverbankcomputing.com/pipermail/pyqt/2017-July/039450.html:
223 : : *
224 : : * "
225 : : * /Factory/ is used when the instance returned is guaranteed to be new to Python.
226 : : * In this case it isn't because it has already been seen when being returned by QgsProcessingAlgorithm::createInstance()
227 : : * (However for a different sub-class implemented in C++ then it would be the first time it was seen
228 : : * by Python so the /Factory/ on create() would be correct.)
229 : : *
230 : : * You might try using /TransferBack/ on create() instead - that might be the best compromise.
231 : : * "
232 : : */
233 : :
234 : : /**
235 : : * Creates a layout multiframe of this class for a specified \a layout.
236 : : */
237 : : virtual QgsLayoutMultiFrame *createMultiFrame( QgsLayout *layout ) = 0 SIP_TRANSFERBACK;
238 : :
239 : : /**
240 : : * Resolve paths in the item's \a properties (if there are any paths).
241 : : * When \a saving is TRUE, paths are converted from absolute to relative,
242 : : * when \a saving is FALSE, paths are converted from relative to absolute.
243 : : * This ensures that paths in project files can be relative, but in item
244 : : * instances the paths are always absolute.
245 : : */
246 : 0 : virtual void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving )
247 : : {
248 : 0 : Q_UNUSED( properties )
249 : 0 : Q_UNUSED( pathResolver )
250 : : Q_UNUSED( saving )
251 : 0 : }
252 : :
253 : : private:
254 : :
255 : : int mType = -1;
256 : : QString mVisibleName;
257 : : };
258 : :
259 : : //! Layout multiframe creation function
260 : : typedef std::function<QgsLayoutMultiFrame *( QgsLayout * )> QgsLayoutMultiFrameCreateFunc SIP_SKIP;
261 : :
262 : : //! Layout multiframe path resolver function
263 : : typedef std::function<void( QVariantMap &, const QgsPathResolver &, bool )> QgsLayoutMultiFramePathResolverFunc SIP_SKIP;
264 : :
265 : : #ifndef SIP_RUN
266 : :
267 : : /**
268 : : * \ingroup core
269 : : * \brief Convenience metadata class that uses static functions to create layout multiframes and their configuration widgets.
270 : : * \note not available in Python bindings
271 : : * \since QGIS 3.0
272 : : */
273 : 40 : class CORE_EXPORT QgsLayoutMultiFrameMetadata : public QgsLayoutMultiFrameAbstractMetadata
274 : : {
275 : : public:
276 : :
277 : : /**
278 : : * Constructor for QgsLayoutMultiFrameMetadata with the specified class \a type
279 : : * and \a visibleName, and function pointers for the various item creation functions.
280 : : */
281 : 20 : QgsLayoutMultiFrameMetadata( int type, const QString &visibleName,
282 : : const QgsLayoutMultiFrameCreateFunc &pfCreate,
283 : : const QgsLayoutMultiFramePathResolverFunc &pfPathResolver = nullptr )
284 : 20 : : QgsLayoutMultiFrameAbstractMetadata( type, visibleName )
285 : 20 : , mCreateFunc( pfCreate )
286 : 20 : , mPathResolverFunc( pfPathResolver )
287 : 60 : {}
288 : :
289 : : /**
290 : : * Returns the classes' multiframe creation function.
291 : : */
292 : : QgsLayoutMultiFrameCreateFunc createFunction() const { return mCreateFunc; }
293 : :
294 : : /**
295 : : * Returns the classes' path resolver function.
296 : : */
297 : : QgsLayoutMultiFramePathResolverFunc pathResolverFunction() const { return mPathResolverFunc; }
298 : :
299 : 0 : QgsLayoutMultiFrame *createMultiFrame( QgsLayout *layout ) override { return mCreateFunc ? mCreateFunc( layout ) : nullptr; }
300 : :
301 : 0 : void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) override
302 : : {
303 : 0 : if ( mPathResolverFunc )
304 : 0 : mPathResolverFunc( properties, pathResolver, saving );
305 : 0 : }
306 : :
307 : : protected:
308 : : QgsLayoutMultiFrameCreateFunc mCreateFunc = nullptr;
309 : : QgsLayoutMultiFramePathResolverFunc mPathResolverFunc = nullptr;
310 : :
311 : : };
312 : :
313 : : #endif
314 : :
315 : :
316 : : /**
317 : : * \ingroup core
318 : : * \class QgsLayoutItemRegistry
319 : : * \brief Registry of available layout item types.
320 : : *
321 : : * QgsLayoutItemRegistry is not usually directly created, but rather accessed through
322 : : * QgsApplication::layoutItemRegistry().
323 : : *
324 : : * A companion class, QgsLayoutItemGuiRegistry, handles the GUI behavior
325 : : * of layout items.
326 : : *
327 : : * \since QGIS 3.0
328 : : */
329 : : class CORE_EXPORT QgsLayoutItemRegistry : public QObject
330 : : {
331 : : Q_OBJECT
332 : :
333 : : public:
334 : :
335 : : //! Item types
336 : : enum ItemType
337 : : {
338 : : LayoutItem = QGraphicsItem::UserType + 100, //!< Base class for items
339 : : LayoutGroup, //!< Grouped item
340 : :
341 : : // known item types
342 : :
343 : : // WARNING!!!! SIP CASTING OF QgsLayoutItem and QgsLayoutMultiFrame DEPENDS on these
344 : : // values, and must be updated if any additional types are added
345 : :
346 : : LayoutPage, //!< Page items
347 : : LayoutMap, //!< Map item
348 : : LayoutPicture, //!< Picture item
349 : : LayoutLabel, //!< Label item
350 : : LayoutLegend, //!< Legend item
351 : : LayoutShape, //!< Shape item
352 : : LayoutPolygon, //!< Polygon shape item
353 : : LayoutPolyline, //!< Polyline shape item
354 : : LayoutScaleBar, //!< Scale bar item
355 : : LayoutFrame, //!< Frame item, part of a QgsLayoutMultiFrame object
356 : :
357 : : // known multi-frame types
358 : :
359 : : // WARNING!!!! SIP CASTING OF QgsLayoutItem and QgsLayoutMultiFrame DEPENDS on these
360 : : // values, and must be updated if any additional types are added
361 : :
362 : : LayoutHtml, //!< Html multiframe item
363 : : LayoutAttributeTable, //!< Attribute table
364 : : LayoutTextTable, //!< Preset text table
365 : :
366 : : Layout3DMap, //!< 3D map item
367 : :
368 : : LayoutManualTable, //!< Manual (fixed) table
369 : : LayoutMarker, //!< Marker item
370 : :
371 : : // item types provided by plugins
372 : : PluginItem = LayoutTextTable + 10000, //!< Starting point for plugin item types
373 : : };
374 : :
375 : : /**
376 : : * Creates a new empty item registry.
377 : : *
378 : : * QgsLayoutItemRegistry is not usually directly created, but rather accessed through
379 : : * QgsApplication::layoutItemRegistry().
380 : : *
381 : : * \see populate()
382 : : */
383 : : QgsLayoutItemRegistry( QObject *parent = nullptr );
384 : :
385 : : ~QgsLayoutItemRegistry() override;
386 : :
387 : : /**
388 : : * Populates the registry with standard item types. If called on a non-empty registry
389 : : * then this will have no effect and will return FALSE.
390 : : */
391 : : bool populate();
392 : :
393 : : //! QgsLayoutItemRegistry cannot be copied.
394 : : QgsLayoutItemRegistry( const QgsLayoutItemRegistry &rh ) = delete;
395 : : //! QgsLayoutItemRegistry cannot be copied.
396 : : QgsLayoutItemRegistry &operator=( const QgsLayoutItemRegistry &rh ) = delete;
397 : :
398 : : /**
399 : : * Returns the metadata for the specified item \a type. Returns NULLPTR if
400 : : * a corresponding type was not found in the registry.
401 : : * \see multiFrameMetadata()
402 : : */
403 : : QgsLayoutItemAbstractMetadata *itemMetadata( int type ) const;
404 : :
405 : : /**
406 : : * Returns the metadata for the specified multiframe \a type. Returns NULLPTR if
407 : : * a corresponding type was not found in the registry.
408 : : * \see itemMetadata()
409 : : */
410 : : QgsLayoutMultiFrameAbstractMetadata *multiFrameMetadata( int type ) const;
411 : :
412 : : /*
413 : : * IMPORTANT: While it seems like /Factory/ would be the correct annotations here, that's not
414 : : * the case.
415 : : * As per Phil Thomson's advice on https://www.riverbankcomputing.com/pipermail/pyqt/2017-July/039450.html:
416 : : *
417 : : * "
418 : : * /Factory/ is used when the instance returned is guaranteed to be new to Python.
419 : : * In this case it isn't because it has already been seen when being returned by QgsProcessingAlgorithm::createInstance()
420 : : * (However for a different sub-class implemented in C++ then it would be the first time it was seen
421 : : * by Python so the /Factory/ on create() would be correct.)
422 : : *
423 : : * You might try using /TransferBack/ on create() instead - that might be the best compromise.
424 : : * "
425 : : */
426 : :
427 : : /**
428 : : * Registers a new layout item type. Takes ownership of the metadata instance.
429 : : * \see addLayoutMultiFrameType()
430 : : */
431 : : bool addLayoutItemType( QgsLayoutItemAbstractMetadata *metadata SIP_TRANSFER );
432 : :
433 : : /**
434 : : * Registers a new layout multiframe type. Takes ownership of the metadata instance.
435 : : * \see addLayoutItemType()
436 : : */
437 : : bool addLayoutMultiFrameType( QgsLayoutMultiFrameAbstractMetadata *metadata SIP_TRANSFER );
438 : :
439 : : /**
440 : : * Creates a new instance of a layout item given the item \a type, and target \a layout.
441 : : * \see createMultiFrame()
442 : : */
443 : : QgsLayoutItem *createItem( int type, QgsLayout *layout ) const SIP_TRANSFERBACK;
444 : :
445 : : /**
446 : : * Creates a new instance of a layout multiframe given the multiframe \a type, and target \a layout.
447 : : * \see createItem()
448 : : */
449 : : QgsLayoutMultiFrame *createMultiFrame( int type, QgsLayout *layout ) const SIP_TRANSFERBACK;
450 : :
451 : : /**
452 : : * Resolve paths in properties of a particular symbol layer.
453 : : * This normally means converting relative paths to absolute paths when loading
454 : : * and converting absolute paths to relative paths when saving.
455 : : */
456 : : void resolvePaths( int type, QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) const;
457 : :
458 : : /**
459 : : * Returns a map of available item types to translated name.
460 : : */
461 : : QMap< int, QString> itemTypes() const;
462 : :
463 : : signals:
464 : :
465 : : /**
466 : : * Emitted whenever a new item type is added to the registry, with the specified
467 : : * \a type and visible \a name.
468 : : */
469 : : void typeAdded( int type, const QString &name );
470 : :
471 : : /**
472 : : * Emitted whenever a new multiframe type is added to the registry, with the specified
473 : : * \a type and visible \a name.
474 : : */
475 : : void multiFrameTypeAdded( int type, const QString &name );
476 : :
477 : : private:
478 : : #ifdef SIP_RUN
479 : : QgsLayoutItemRegistry( const QgsLayoutItemRegistry &rh );
480 : : #endif
481 : :
482 : : QMap<int, QgsLayoutItemAbstractMetadata *> mMetadata;
483 : : QMap<int, QgsLayoutMultiFrameAbstractMetadata *> mMultiFrameMetadata;
484 : :
485 : : };
486 : :
487 : : #if 0
488 : : #ifndef SIP_RUN
489 : : ///@cond TEMPORARY
490 : : //simple item for testing
491 : : #ifdef ANDROID
492 : : // For some reason, the Android NDK toolchain requires this to link properly.
493 : : // Note to self: Please try to remove this again once Qt ships their libs built with gcc-5
494 : : class CORE_EXPORT TestLayoutItem : public QgsLayoutItem
495 : : #else
496 : : class TestLayoutItem : public QgsLayoutItem
497 : : #endif
498 : : {
499 : : Q_OBJECT
500 : :
501 : : public:
502 : :
503 : : TestLayoutItem( QgsLayout *layout );
504 : : ~TestLayoutItem() = default;
505 : :
506 : : //implement pure virtual methods
507 : : int type() const override { return QgsLayoutItemRegistry::LayoutItem + 1002; }
508 : : void draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle = nullptr ) override;
509 : :
510 : : private:
511 : : QColor mColor;
512 : : QgsFillSymbol *mShapeStyleSymbol = nullptr;
513 : : };
514 : : ///@endcond
515 : : #endif
516 : : #endif
517 : :
518 : : #endif //QGSLAYOUTITEMREGISTRY_H
519 : :
520 : :
521 : :
|