Split layout item registry into two separate registries

Instead of relying on forward declared c++ classes from
gui in QgsLayoutItemRegistry, instead create a
QgsLayoutItemGuiRegistry which handles registration
of all the GUI specific behavior relating to layout items.

Remove all GUI related code from QgsLayoutItemRegistry.

This creates a cleaner split between core/gui code, and
given that there'll be a lot of gui specific behavior
which needs to be handled by a registry it makes sense
to keep this isolated in gui.

It also plays nicer with the sip bindings, which can't
handle forward declared gui classes in core.
This commit is contained in:
Nyall Dawson 2017-07-07 12:17:37 +10:00
parent 0307cac325
commit cf488d34a4
18 changed files with 580 additions and 229 deletions

View File

@ -13,9 +13,13 @@ class QgsLayoutItemAbstractMetadata
{
%Docstring
Stores metadata about one layout item class.
A companion class, QgsLayoutItemAbstractGuiMetadata, handles the
GUI behavior of QgsLayoutItems.
.. note::
In C++ you can use QgsSymbolLayerMetadata convenience class.
In C++ you can use QgsLayoutItemMetadata convenience class.
.. versionadded:: 3.0
%End
@ -56,13 +60,6 @@ class QgsLayoutItemAbstractMetadata
:rtype: QgsLayoutItem
%End
virtual QWidget *createItemWidget() /Factory/;
%Docstring
Creates a configuration widget for layout items of this type. Can return None if no configuration GUI is required.
:rtype: QWidget
%End
virtual void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving );
%Docstring
Resolve paths in the item's ``properties`` (if there are any paths).
@ -79,8 +76,6 @@ class QgsLayoutItemAbstractMetadata
class QgsLayoutItemRegistry : QObject
{
%Docstring
@ -89,6 +84,9 @@ class QgsLayoutItemRegistry : QObject
QgsLayoutItemRegistry is not usually directly created, but rather accessed through
QgsApplication.layoutItemRegistry().
A companion class, QgsLayoutItemGuiRegistry, handles the GUI behavior
of layout items.
.. versionadded:: 3.0
%End
@ -147,13 +145,6 @@ class QgsLayoutItemRegistry : QObject
:rtype: QgsLayoutItem
%End
QWidget *createItemWidget( int type ) const /Factory/;
%Docstring
Creates a new instance of a layout item configuration widget for the specified item ``type``.
:rtype: QWidget
%End
void resolvePaths( int type, QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) const;
%Docstring
Resolve paths in properties of a particular symbol layer.

View File

@ -42,7 +42,6 @@
%Include editorwidgets/core/qgseditorwidgetautoconf.sip
%Include layertree/qgslayertreeembeddedconfigwidget.sip
%Include layertree/qgslayertreeembeddedwidgetregistry.sip
%Include layout/qgslayoutitemregistryguiutils.sip
%Include layout/qgslayoutviewmouseevent.sip
%Include layout/qgslayoutviewrubberband.sip
%Include locator/qgslocatorcontext.sip
@ -278,6 +277,7 @@
%Include layertree/qgslayertreeview.sip
%Include layertree/qgslayertreeviewdefaultactions.sip
%Include layout/qgslayoutdesignerinterface.sip
%Include layout/qgslayoutitemguiregistry.sip
%Include layout/qgslayoutview.sip
%Include layout/qgslayoutviewtool.sip
%Include layout/qgslayoutviewtooladditem.sip

View File

@ -0,0 +1,154 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/layout/qgslayoutitemguiregistry.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsLayoutItemAbstractGuiMetadata
{
%Docstring
Stores GUI metadata about one layout item class.
This is a companion to QgsLayoutItemAbstractMetadata, storing only
the components related to the GUI behavior of a layout item.
.. note::
In C++ you can use QgsLayoutItemGuiMetadata convenience class.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutitemguiregistry.h"
%End
public:
QgsLayoutItemAbstractGuiMetadata( int type );
%Docstring
Constructor for QgsLayoutItemAbstractGuiMetadata with the specified class ``type``.
%End
virtual ~QgsLayoutItemAbstractGuiMetadata();
int type() const;
%Docstring
Returns the unique item type code for the layout item class.
:rtype: int
%End
virtual QIcon creationIcon() const;
%Docstring
Returns an icon representing creation of the layout item type.
:rtype: QIcon
%End
virtual QWidget *createItemWidget() /Factory/;
%Docstring
Creates a configuration widget for layout items of this type. Can return None if no configuration GUI is required.
:rtype: QWidget
%End
virtual QgsLayoutViewRubberBand *createRubberBand( QgsLayoutView *view ) /Factory/;
%Docstring
Creates a rubber band for use when creating layout items of this type. Can return None if no rubber band
should be created. The default behavior is to create a rectangular rubber band.
:rtype: QgsLayoutViewRubberBand
%End
};
class QgsLayoutItemGuiRegistry : QObject
{
%Docstring
Registry of available layout item GUI behavior.
QgsLayoutItemGuiRegistry is not usually directly created, but rather accessed through
QgsGui.layoutItemGuiRegistry().
This acts as a companion to QgsLayoutItemRegistry, handling only
the components related to the GUI behavior of layout items.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutitemguiregistry.h"
%End
public:
QgsLayoutItemGuiRegistry( QObject *parent = 0 );
%Docstring
Creates a new empty item GUI registry.
QgsLayoutItemGuiRegistry is not usually directly created, but rather accessed through
QgsGui.layoutItemGuiRegistry().
.. seealso:: populate()
%End
~QgsLayoutItemGuiRegistry();
bool populate();
%Docstring
Populates the registry with standard item types. If called on a non-empty registry
then this will have no effect and will return false.
:rtype: bool
%End
QgsLayoutItemAbstractGuiMetadata *itemMetadata( int type ) const;
%Docstring
Returns the metadata for the specified item ``type``. Returns None if
a corresponding type was not found in the registry.
:rtype: QgsLayoutItemAbstractGuiMetadata
%End
bool addLayoutItemGuiMetadata( QgsLayoutItemAbstractGuiMetadata *metadata /Transfer/ );
%Docstring
Registers the gui metadata for a new layout item type. Takes ownership of the metadata instance.
:rtype: bool
%End
QWidget *createItemWidget( int type ) const /Factory/;
%Docstring
Creates a new instance of a layout item configuration widget for the specified item ``type``.
:rtype: QWidget
%End
QList< int > itemTypes() const;
%Docstring
Returns a list of available item types handled by the registry.
:rtype: list of int
%End
signals:
void typeAdded( int type );
%Docstring
Emitted whenever a new item type is added to the registry, with the specified
``type``.
%End
private:
QgsLayoutItemGuiRegistry( const QgsLayoutItemGuiRegistry &rh );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/layout/qgslayoutitemguiregistry.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -56,6 +56,12 @@ class QgsGui
:rtype: QgsMapLayerActionRegistry
%End
static QgsLayoutItemGuiRegistry *layoutItemGuiRegistry();
%Docstring
Returns the global layout item GUI registry, used for registering the GUI behavior of layout items.
:rtype: QgsLayoutItemGuiRegistry
%End
~QgsGui();
private:

View File

@ -26,6 +26,8 @@
#include "qgslayoutviewtoolpan.h"
#include "qgslayoutviewtoolzoom.h"
#include "qgslayoutviewtoolselect.h"
#include "qgsgui.h"
#include "qgslayoutitemguiregistry.h"
QgsAppLayoutDesignerInterface::QgsAppLayoutDesignerInterface( QgsLayoutDesignerDialog *dialog )
: QgsLayoutDesignerInterface( dialog )
@ -89,14 +91,12 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
connect( mActionClose, &QAction::triggered, this, &QWidget::close );
// populate with initial items...
QMap< int, QString> types = QgsApplication::layoutItemRegistry()->itemTypes();
QMap< int, QString>::const_iterator typeIt = types.constBegin();
for ( ; typeIt != types.constEnd(); ++typeIt )
Q_FOREACH ( int type, QgsGui::layoutItemGuiRegistry()->itemTypes() )
{
itemTypeAdded( typeIt.key(), typeIt.value() );
itemTypeAdded( type );
}
//..and listen out for new item types
connect( QgsApplication::layoutItemRegistry(), &QgsLayoutItemRegistry::typeAdded, this, &QgsLayoutDesignerDialog::itemTypeAdded );
connect( QgsGui::layoutItemGuiRegistry(), &QgsLayoutItemGuiRegistry::typeAdded, this, &QgsLayoutDesignerDialog::itemTypeAdded );
mAddItemTool = new QgsLayoutViewToolAddItem( mView );
mPanTool = new QgsLayoutViewToolPan( mView );
@ -192,14 +192,15 @@ void QgsLayoutDesignerDialog::closeEvent( QCloseEvent * )
saveWindowState();
}
void QgsLayoutDesignerDialog::itemTypeAdded( int type, const QString &name )
void QgsLayoutDesignerDialog::itemTypeAdded( int type )
{
QString name = QgsApplication::layoutItemRegistry()->itemMetadata( type )->visibleName();
// update UI for new item type
QAction *action = new QAction( tr( "Add %1" ).arg( name ), this );
action->setToolTip( tr( "Adds a new %1 to the layout" ).arg( name ) );
action->setCheckable( true );
action->setData( type );
action->setIcon( QgsApplication::layoutItemRegistry()->itemMetadata( type )->icon() );
action->setIcon( QgsGui::layoutItemGuiRegistry()->itemMetadata( type )->creationIcon() );
mToolsActionGroup->addAction( action );
mItemMenu->addAction( action );
mToolsToolbar->addAction( action );

View File

@ -115,7 +115,7 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
private slots:
void itemTypeAdded( int type, const QString &name );
void itemTypeAdded( int type );
private:

View File

@ -65,25 +65,6 @@ QgsLayoutItem *QgsLayoutItemRegistry::createItem( int type, QgsLayout *layout, c
return mMetadata[type]->createItem( layout, properties );
}
QWidget *QgsLayoutItemRegistry::createItemWidget( int type ) const
{
if ( !mMetadata.contains( type ) )
return nullptr;
return mMetadata[type]->createItemWidget();
}
QgsLayoutViewRubberBand *QgsLayoutItemRegistry::createItemRubberBand( int type, QgsLayoutView *view ) const
{
if ( mRubberBandFunctions.contains( type ) )
return mRubberBandFunctions.value( type )( view );
if ( !mMetadata.contains( type ) )
return nullptr;
return mMetadata[type]->createRubberBand( view );
}
void QgsLayoutItemRegistry::resolvePaths( int type, QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) const
{
if ( !mMetadata.contains( type ) )

View File

@ -29,12 +29,15 @@
class QgsLayout;
class QgsLayoutView;
class QgsLayoutItem;
class QgsLayoutViewRubberBand;
/**
* \ingroup core
* \brief Stores metadata about one layout item class.
* \note In C++ you can use QgsSymbolLayerMetadata convenience class.
*
* A companion class, QgsLayoutItemAbstractGuiMetadata, handles the
* GUI behavior of QgsLayoutItems.
*
* \note In C++ you can use QgsLayoutItemMetadata convenience class.
* \since QGIS 3.0
*/
class CORE_EXPORT QgsLayoutItemAbstractMetadata
@ -72,19 +75,6 @@ class CORE_EXPORT QgsLayoutItemAbstractMetadata
*/
virtual QgsLayoutItem *createItem( QgsLayout *layout, const QVariantMap &properties ) = 0 SIP_FACTORY;
/**
* Creates a configuration widget for layout items of this type. Can return nullptr if no configuration GUI is required.
*/
virtual QWidget *createItemWidget() SIP_FACTORY { return nullptr; }
/**
* Creates a rubber band for use when creating layout items of this type. Can return nullptr if no rubber band
* should be created.
* \note not available in Python bindings. Python item subclasses must use QgsLayoutItemRegistryGuiUtils
* to override the default rubber band creation function.
*/
virtual QgsLayoutViewRubberBand *createRubberBand( QgsLayoutView *view ) SIP_SKIP { Q_UNUSED( view ); return nullptr; }
/**
* Resolve paths in the item's \a properties (if there are any paths).
* When \a saving is true, paths are converted from absolute to relative,
@ -108,12 +98,6 @@ class CORE_EXPORT QgsLayoutItemAbstractMetadata
//! Layout item creation function
typedef std::function<QgsLayoutItem *( QgsLayout *, const QVariantMap & )> QgsLayoutItemCreateFunc SIP_SKIP;
//! Layout item configuration widget creation function
typedef std::function<QWidget *()> QgsLayoutItemWidgetFunc SIP_SKIP;
//! Layout rubber band creation function
typedef std::function<QgsLayoutViewRubberBand *( QgsLayoutView * )> QgsLayoutItemRubberBandFunc SIP_SKIP;
//! Layout item path resolver function
typedef std::function<void( QVariantMap &, const QgsPathResolver &, bool )> QgsLayoutItemPathResolverFunc SIP_SKIP;
@ -131,17 +115,14 @@ class CORE_EXPORT QgsLayoutItemMetadata : public QgsLayoutItemAbstractMetadata
/**
* Constructor for QgsLayoutItemMetadata with the specified class \a type
* and \a visibleName, and function pointers for the various item and
* configuration widget creation functions.
* and \a visibleName, and function pointers for the various item creation functions.
*/
QgsLayoutItemMetadata( int type, const QString &visibleName, const QIcon &icon,
QgsLayoutItemCreateFunc pfCreate,
QgsLayoutItemPathResolverFunc pfPathResolver = nullptr,
QgsLayoutItemWidgetFunc pfWidget = nullptr )
QgsLayoutItemPathResolverFunc pfPathResolver = nullptr )
: QgsLayoutItemAbstractMetadata( type, visibleName )
, mIcon( icon )
, mCreateFunc( pfCreate )
, mWidgetFunc( pfWidget )
, mPathResolverFunc( pfPathResolver )
{}
@ -150,39 +131,13 @@ class CORE_EXPORT QgsLayoutItemMetadata : public QgsLayoutItemAbstractMetadata
*/
QgsLayoutItemCreateFunc createFunction() const { return mCreateFunc; }
/**
* Returns the classes' configuration widget creation function.
* \see setWidgetFunction()
*/
QgsLayoutItemWidgetFunc widgetFunction() const { return mWidgetFunc; }
/**
* Returns the classes' path resolver function.
*/
QgsLayoutItemPathResolverFunc pathResolverFunction() const { return mPathResolverFunc; }
/**
* Sets the classes' configuration widget creation \a function.
* \see widgetFunction()
*/
void setWidgetFunction( QgsLayoutItemWidgetFunc function ) { mWidgetFunc = function; }
/**
* Returns the classes' rubber band creation function.
* \see setRubberBandCreationFunction()
*/
QgsLayoutItemRubberBandFunc rubberBandCreationFunction() const { return mRubberBandFunc; }
/**
* Sets the classes' rubber band creation \a function.
* \see rubberBandCreationFunction()
*/
void setRubberBandCreationFunction( QgsLayoutItemRubberBandFunc function ) { mRubberBandFunc = function; }
QIcon icon() const override { return mIcon.isNull() ? QgsLayoutItemAbstractMetadata::icon() : mIcon; }
QgsLayoutItem *createItem( QgsLayout *layout, const QVariantMap &properties ) override { return mCreateFunc ? mCreateFunc( layout, properties ) : nullptr; }
QWidget *createItemWidget() override { return mWidgetFunc ? mWidgetFunc() : nullptr; }
QgsLayoutViewRubberBand *createRubberBand( QgsLayoutView *view ) override { return mRubberBandFunc ? mRubberBandFunc( view ) : nullptr; }
void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) override
{
@ -193,8 +148,6 @@ class CORE_EXPORT QgsLayoutItemMetadata : public QgsLayoutItemAbstractMetadata
protected:
QIcon mIcon;
QgsLayoutItemCreateFunc mCreateFunc = nullptr;
QgsLayoutItemWidgetFunc mWidgetFunc = nullptr;
QgsLayoutItemRubberBandFunc mRubberBandFunc = nullptr;
QgsLayoutItemPathResolverFunc mPathResolverFunc = nullptr;
};
@ -211,6 +164,9 @@ class CORE_EXPORT QgsLayoutItemMetadata : public QgsLayoutItemAbstractMetadata
* QgsLayoutItemRegistry is not usually directly created, but rather accessed through
* QgsApplication::layoutItemRegistry().
*
* A companion class, QgsLayoutItemGuiRegistry, handles the GUI behavior
* of layout items.
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsLayoutItemRegistry : public QObject
@ -251,7 +207,7 @@ class CORE_EXPORT QgsLayoutItemRegistry : public QObject
//! QgsLayoutItemRegistry cannot be copied.
QgsLayoutItemRegistry( const QgsLayoutItemRegistry &rh ) = delete;
//! QgsLayoutItemRegistryQgsLayoutItemRegistry cannot be copied.
//! QgsLayoutItemRegistry cannot be copied.
QgsLayoutItemRegistry &operator=( const QgsLayoutItemRegistry &rh ) = delete;
/**
@ -270,17 +226,6 @@ class CORE_EXPORT QgsLayoutItemRegistry : public QObject
*/
QgsLayoutItem *createItem( int type, QgsLayout *layout, const QVariantMap &properties = QVariantMap() ) const SIP_FACTORY;
/**
* Creates a new instance of a layout item configuration widget for the specified item \a type.
*/
QWidget *createItemWidget( int type ) const SIP_FACTORY;
/**
* Creates a new rubber band item for the specified item \a type and destination \a view.
* \note not available from Python bindings
*/
QgsLayoutViewRubberBand *createItemRubberBand( int type, QgsLayoutView *view ) const SIP_SKIP;
/**
* Resolve paths in properties of a particular symbol layer.
* This normally means converting relative paths to absolute paths when loading
@ -308,10 +253,6 @@ class CORE_EXPORT QgsLayoutItemRegistry : public QObject
QMap<int, QgsLayoutItemAbstractMetadata *> mMetadata;
QMap<int, QgsLayoutItemRubberBandFunc > mRubberBandFunctions;
friend class QgsLayoutItemRegistryGuiUtils;
};
#ifndef SIP_RUN

View File

@ -158,7 +158,7 @@ SET(QGIS_GUI_SRCS
layertree/qgslayertreeview.cpp
layertree/qgslayertreeviewdefaultactions.cpp
layout/qgslayoutitemregistryguiutils.cpp
layout/qgslayoutitemguiregistry.cpp
layout/qgslayoutview.cpp
layout/qgslayoutviewmouseevent.cpp
layout/qgslayoutviewrubberband.cpp
@ -633,6 +633,7 @@ SET(QGIS_GUI_MOC_HDRS
layertree/qgslayertreeviewdefaultactions.h
layout/qgslayoutdesignerinterface.h
layout/qgslayoutitemguiregistry.h
layout/qgslayoutview.h
layout/qgslayoutviewtool.h
layout/qgslayoutviewtooladditem.h
@ -735,7 +736,6 @@ SET(QGIS_GUI_HDRS
layertree/qgslayertreeembeddedconfigwidget.h
layertree/qgslayertreeembeddedwidgetregistry.h
layout/qgslayoutitemregistryguiutils.h
layout/qgslayoutviewmouseevent.h
layout/qgslayoutviewrubberband.h

View File

@ -0,0 +1,87 @@
/***************************************************************************
qgslayoutitemregistry.cpp
-------------------------
begin : June 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgslayoutitemguiregistry.h"
#include "qgslayoutviewrubberband.h"
#include <QPainter>
QgsLayoutViewRubberBand *QgsLayoutItemAbstractGuiMetadata::createRubberBand( QgsLayoutView *view )
{
return new QgsLayoutViewRectangularRubberBand( view );
}
QgsLayoutItemGuiRegistry::QgsLayoutItemGuiRegistry( QObject *parent )
: QObject( parent )
{
}
QgsLayoutItemGuiRegistry::~QgsLayoutItemGuiRegistry()
{
qDeleteAll( mMetadata );
}
bool QgsLayoutItemGuiRegistry::populate()
{
if ( !mMetadata.isEmpty() )
return false;
// add temporary item to register
auto createRubberBand = ( []( QgsLayoutView * view )->QgsLayoutViewRubberBand *
{
return new QgsLayoutViewRectangularRubberBand( view );
} );
addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( 101, QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddLabel.svg" ) ), nullptr, createRubberBand ) );
return true;
}
QgsLayoutItemAbstractGuiMetadata *QgsLayoutItemGuiRegistry::itemMetadata( int type ) const
{
return mMetadata.value( type );
}
bool QgsLayoutItemGuiRegistry::addLayoutItemGuiMetadata( QgsLayoutItemAbstractGuiMetadata *metadata )
{
if ( !metadata || mMetadata.contains( metadata->type() ) )
return false;
mMetadata[metadata->type()] = metadata;
emit typeAdded( metadata->type() );
return true;
}
QWidget *QgsLayoutItemGuiRegistry::createItemWidget( int type ) const
{
if ( !mMetadata.contains( type ) )
return nullptr;
return mMetadata[type]->createItemWidget();
}
QgsLayoutViewRubberBand *QgsLayoutItemGuiRegistry::createItemRubberBand( int type, QgsLayoutView *view ) const
{
if ( !mMetadata.contains( type ) )
return nullptr;
return mMetadata[type]->createRubberBand( view );
}
QList<int> QgsLayoutItemGuiRegistry::itemTypes() const
{
return mMetadata.keys();
}

View File

@ -0,0 +1,241 @@
/***************************************************************************
qgslayoutitemguiregistry.h
--------------------------
begin : June 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSLAYOUTITEMGUIREGISTRY_H
#define QGSLAYOUTITEMGUIREGISTRY_H
#include "qgis_gui.h"
#include "qgis_sip.h"
#include "qgsapplication.h"
#include "qgspathresolver.h"
#include <QGraphicsItem> //for QGraphicsItem::UserType
#include <QIcon>
#include <functional>
#include "qgslayoutitem.h" // temporary
class QgsLayout;
class QgsLayoutView;
class QgsLayoutItem;
class QgsLayoutViewRubberBand;
/**
* \ingroup gui
* \brief Stores GUI metadata about one layout item class.
*
* This is a companion to QgsLayoutItemAbstractMetadata, storing only
* the components related to the GUI behavior of a layout item.
*
* \note In C++ you can use QgsLayoutItemGuiMetadata convenience class.
* \since QGIS 3.0
*/
class GUI_EXPORT QgsLayoutItemAbstractGuiMetadata
{
public:
/**
* Constructor for QgsLayoutItemAbstractGuiMetadata with the specified class \a type.
*/
QgsLayoutItemAbstractGuiMetadata( int type )
: mType( type )
{}
virtual ~QgsLayoutItemAbstractGuiMetadata() = default;
/**
* Returns the unique item type code for the layout item class.
*/
int type() const { return mType; }
/**
* Returns an icon representing creation of the layout item type.
*/
virtual QIcon creationIcon() const { return QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ); }
/**
* Creates a configuration widget for layout items of this type. Can return nullptr if no configuration GUI is required.
*/
virtual QWidget *createItemWidget() SIP_FACTORY { return nullptr; }
/**
* Creates a rubber band for use when creating layout items of this type. Can return nullptr if no rubber band
* should be created. The default behavior is to create a rectangular rubber band.
*/
virtual QgsLayoutViewRubberBand *createRubberBand( QgsLayoutView *view ) SIP_FACTORY;
private:
int mType = -1;
};
//! Layout item configuration widget creation function
typedef std::function<QWidget *()> QgsLayoutItemWidgetFunc SIP_SKIP;
//! Layout rubber band creation function
typedef std::function<QgsLayoutViewRubberBand *( QgsLayoutView * )> QgsLayoutItemRubberBandFunc SIP_SKIP;
#ifndef SIP_RUN
/**
* \ingroup gui
* Convenience metadata class that uses static functions to handle layout item GUI behavior.
* \since QGIS 3.0
* \note not available in Python bindings
*/
class CORE_EXPORT QgsLayoutItemGuiMetadata : public QgsLayoutItemAbstractGuiMetadata
{
public:
/**
* Constructor for QgsLayoutItemGuiMetadata with the specified class \a type
* and \a creationIcon, and function pointers for the various
* configuration widget creation functions.
*/
QgsLayoutItemGuiMetadata( int type, const QIcon &creationIcon,
QgsLayoutItemWidgetFunc pfWidget = nullptr,
QgsLayoutItemRubberBandFunc pfRubberBand = nullptr )
: QgsLayoutItemAbstractGuiMetadata( type )
, mIcon( creationIcon )
, mWidgetFunc( pfWidget )
, mRubberBandFunc( pfRubberBand )
{}
/**
* Returns the classes' configuration widget creation function.
* \see setWidgetFunction()
*/
QgsLayoutItemWidgetFunc widgetFunction() const { return mWidgetFunc; }
/**
* Sets the classes' configuration widget creation \a function.
* \see widgetFunction()
*/
void setWidgetFunction( QgsLayoutItemWidgetFunc function ) { mWidgetFunc = function; }
/**
* Returns the classes' rubber band creation function.
* \see setRubberBandCreationFunction()
*/
QgsLayoutItemRubberBandFunc rubberBandCreationFunction() const { return mRubberBandFunc; }
/**
* Sets the classes' rubber band creation \a function.
* \see rubberBandCreationFunction()
*/
void setRubberBandCreationFunction( QgsLayoutItemRubberBandFunc function ) { mRubberBandFunc = function; }
QIcon creationIcon() const override { return mIcon.isNull() ? QgsLayoutItemAbstractGuiMetadata::creationIcon() : mIcon; }
QWidget *createItemWidget() override { return mWidgetFunc ? mWidgetFunc() : nullptr; }
QgsLayoutViewRubberBand *createRubberBand( QgsLayoutView *view ) override { return mRubberBandFunc ? mRubberBandFunc( view ) : nullptr; }
protected:
QIcon mIcon;
QgsLayoutItemWidgetFunc mWidgetFunc = nullptr;
QgsLayoutItemRubberBandFunc mRubberBandFunc = nullptr;
};
#endif
/**
* \ingroup core
* \class QgsLayoutItemGuiRegistry
* \brief Registry of available layout item GUI behavior.
*
* QgsLayoutItemGuiRegistry is not usually directly created, but rather accessed through
* QgsGui::layoutItemGuiRegistry().
*
* This acts as a companion to QgsLayoutItemRegistry, handling only
* the components related to the GUI behavior of layout items.
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsLayoutItemGuiRegistry : public QObject
{
Q_OBJECT
public:
/**
* Creates a new empty item GUI registry.
*
* QgsLayoutItemGuiRegistry is not usually directly created, but rather accessed through
* QgsGui::layoutItemGuiRegistry().
*
* \see populate()
*/
QgsLayoutItemGuiRegistry( QObject *parent = nullptr );
~QgsLayoutItemGuiRegistry();
/**
* Populates the registry with standard item types. If called on a non-empty registry
* then this will have no effect and will return false.
*/
bool populate();
//! QgsLayoutItemGuiRegistry cannot be copied.
QgsLayoutItemGuiRegistry( const QgsLayoutItemGuiRegistry &rh ) = delete;
//! QgsLayoutItemGuiRegistry cannot be copied.
QgsLayoutItemGuiRegistry &operator=( const QgsLayoutItemGuiRegistry &rh ) = delete;
/**
* Returns the metadata for the specified item \a type. Returns nullptr if
* a corresponding type was not found in the registry.
*/
QgsLayoutItemAbstractGuiMetadata *itemMetadata( int type ) const;
/**
* Registers the gui metadata for a new layout item type. Takes ownership of the metadata instance.
*/
bool addLayoutItemGuiMetadata( QgsLayoutItemAbstractGuiMetadata *metadata SIP_TRANSFER );
/**
* Creates a new instance of a layout item configuration widget for the specified item \a type.
*/
QWidget *createItemWidget( int type ) const SIP_FACTORY;
/**
* Creates a new rubber band item for the specified item \a type and destination \a view.
* \note not available from Python bindings
*/
QgsLayoutViewRubberBand *createItemRubberBand( int type, QgsLayoutView *view ) const SIP_SKIP;
/**
* Returns a list of available item types handled by the registry.
*/
QList< int > itemTypes() const;
signals:
/**
* Emitted whenever a new item type is added to the registry, with the specified
* \a type.
*/
void typeAdded( int type );
private:
#ifdef SIP_RUN
QgsLayoutItemGuiRegistry( const QgsLayoutItemGuiRegistry &rh );
#endif
QMap<int, QgsLayoutItemAbstractGuiMetadata *> mMetadata;
};
#endif //QGSLAYOUTITEMGUIREGISTRY_H

View File

@ -1,27 +0,0 @@
/***************************************************************************
qgslayoutitemregistryguiutils.h
-------------------------------
Date : July 2017
Copyright : (C) 2017 Nyall Dawson
Email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgslayoutitemregistryguiutils.h"
#include "qgslayoutviewrubberband.h"
void QgsLayoutItemRegistryGuiUtils::setItemRubberBandPrototype( int type, QgsLayoutViewRubberBand *prototype )
{
auto create = [prototype]( QgsLayoutView * view )->QgsLayoutViewRubberBand *
{
return prototype->create( view );
};
QgsApplication::layoutItemRegistry()->mRubberBandFunctions.insert( type, create );
}

View File

@ -1,50 +0,0 @@
/***************************************************************************
qgslayoutitemregistryguiutils.h
-------------------------------
Date : July 2017
Copyright : (C) 2017 Nyall Dawson
Email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSLAYOUTITEMREGISTRYGUIUTILS_H
#define QGSLAYOUTITEMREGISTRYGUIUTILS_H
#include "qgis_gui.h"
#include "qgis_sip.h"
#include "qgslayoutitemregistry.h"
class QgsLayoutViewRubberBand;
/**
* \ingroup gui
* A group of static utilities for working with the gui based portions of
* QgsLayoutItemRegistry.
*
* This class is designed to allow Python item subclasses to override the
* default GUI based QgsLayoutItemAbstractMetadata methods, which
* cannot be directly overridden from Python subclasses.
*
* \since QGIS 3.0
*/
class GUI_EXPORT QgsLayoutItemRegistryGuiUtils
{
public:
/**
* Sets a \a prototype for the rubber bands for the layout item with specified \a type.
* Python subclasses of QgsLayoutItem must call this method to register their prototypes,
* as the usual c++ QgsLayoutItemAbstractMetadata are not accessible via the Python bindings.
*/
static void setItemRubberBandPrototype( int type, QgsLayoutViewRubberBand *prototype SIP_TRANSFER );
};
#endif // QGSLAYOUTITEMREGISTRYGUIUTILS_H

View File

@ -22,6 +22,8 @@
#include "qgslayoutviewmouseevent.h"
#include "qgslogger.h"
#include "qgslayoutviewrubberband.h"
#include "qgsgui.h"
#include "qgslayoutitemguiregistry.h"
#include <QGraphicsRectItem>
#include <QPen>
#include <QBrush>
@ -49,7 +51,7 @@ void QgsLayoutViewToolAddItem::layoutPressEvent( QgsLayoutViewMouseEvent *event
mDrawing = true;
mMousePressStartPos = event->pos();
mRubberBand.reset( QgsApplication::layoutItemRegistry()->createItemRubberBand( mItemType, view() ) );
mRubberBand.reset( QgsGui::layoutItemGuiRegistry()->createItemRubberBand( mItemType, view() ) );
if ( mRubberBand )
{
mRubberBand->start( event->layoutPoint(), event->modifiers() );

View File

@ -20,6 +20,7 @@
#include "qgslayertreeembeddedwidgetregistry.h"
#include "qgsmaplayeractionregistry.h"
#include "qgslayoutitemregistry.h"
#include "qgslayoutitemguiregistry.h"
#include "qgslayoutviewrubberband.h"
#ifdef Q_OS_MACX
#include "qgsmacnative.h"
@ -59,8 +60,14 @@ QgsMapLayerActionRegistry *QgsGui::mapLayerActionRegistry()
return instance()->mMapLayerActionRegistry;
}
QgsLayoutItemGuiRegistry *QgsGui::layoutItemGuiRegistry()
{
return instance()->mLayoutItemGuiRegistry;
}
QgsGui::~QgsGui()
{
delete mLayoutItemGuiRegistry;
delete mLayerTreeEmbeddedWidgetRegistry;
delete mEditorWidgetRegistry;
delete mMapLayerActionRegistry;
@ -80,13 +87,6 @@ QgsGui::QgsGui()
mShortcutsManager = new QgsShortcutsManager();
mLayerTreeEmbeddedWidgetRegistry = new QgsLayerTreeEmbeddedWidgetRegistry();
mMapLayerActionRegistry = new QgsMapLayerActionRegistry();
QgsLayoutItemAbstractMetadata *abstractMetadata = QgsApplication::layoutItemRegistry()->itemMetadata( 101 );
QgsLayoutItemMetadata *metadata = dynamic_cast<QgsLayoutItemMetadata *>( abstractMetadata );
metadata->setRubberBandCreationFunction( []( QgsLayoutView * view )->QgsLayoutViewRubberBand *
{
return new QgsLayoutViewRectangularRubberBand( view );
} );
mLayoutItemGuiRegistry = new QgsLayoutItemGuiRegistry();
mLayoutItemGuiRegistry->populate();
}

View File

@ -26,6 +26,7 @@ class QgsShortcutsManager;
class QgsLayerTreeEmbeddedWidgetRegistry;
class QgsMapLayerActionRegistry;
class QgsNative;
class QgsLayoutItemGuiRegistry;
/**
* \ingroup gui
@ -75,6 +76,11 @@ class GUI_EXPORT QgsGui
*/
static QgsMapLayerActionRegistry *mapLayerActionRegistry();
/**
* Returns the global layout item GUI registry, used for registering the GUI behavior of layout items.
*/
static QgsLayoutItemGuiRegistry *layoutItemGuiRegistry();
~QgsGui();
private:
@ -86,6 +92,7 @@ class GUI_EXPORT QgsGui
QgsShortcutsManager *mShortcutsManager = nullptr;
QgsLayerTreeEmbeddedWidgetRegistry *mLayerTreeEmbeddedWidgetRegistry = nullptr;
QgsMapLayerActionRegistry *mMapLayerActionRegistry = nullptr;
QgsLayoutItemGuiRegistry *mLayoutItemGuiRegistry = nullptr;
#ifdef SIP_RUN
QgsGui( const QgsGui &other );

View File

@ -115,16 +115,11 @@ void TestQgsLayoutItem::registry()
QVERIFY( !registry.itemMetadata( -1 ) );
QVERIFY( registry.itemTypes().isEmpty() );
QVERIFY( !registry.createItem( 1, nullptr ) );
QVERIFY( !registry.createItemWidget( 1 ) );
auto create = []( QgsLayout * layout, const QVariantMap & )->QgsLayoutItem*
{
return new TestItem( layout );
};
auto createWidget = []()->QWidget*
{
return new QWidget();
};
auto resolve = []( QVariantMap & props, const QgsPathResolver &, bool )
{
props.clear();
@ -132,7 +127,7 @@ void TestQgsLayoutItem::registry()
QSignalSpy spyTypeAdded( &registry, &QgsLayoutItemRegistry::typeAdded );
QgsLayoutItemMetadata *metadata = new QgsLayoutItemMetadata( 2, QStringLiteral( "my type" ), QIcon(), create, resolve, createWidget );
QgsLayoutItemMetadata *metadata = new QgsLayoutItemMetadata( 2, QStringLiteral( "my type" ), QIcon(), create, resolve );
QVERIFY( registry.addLayoutItemType( metadata ) );
QCOMPARE( spyTypeAdded.count(), 1 );
QCOMPARE( spyTypeAdded.value( 0 ).at( 0 ).toInt(), 2 );
@ -150,9 +145,6 @@ void TestQgsLayoutItem::registry()
QVERIFY( item );
QVERIFY( dynamic_cast< TestItem *>( item ) );
delete item;
QWidget *config = registry.createItemWidget( 2 );
QVERIFY( config );
delete config;
QVariantMap props;
props.insert( QStringLiteral( "a" ), 5 );
registry.resolvePaths( 1, props, QgsPathResolver(), true );

View File

@ -20,8 +20,10 @@
#include "qgslayoutviewmouseevent.h"
#include "qgslayoutitem.h"
#include "qgslayoutviewrubberband.h"
#include "qgslayoutitemregistryguiutils.h"
#include "qgslayoutitemregistry.h"
#include "qgslayoutitemguiregistry.h"
#include "qgstestutils.h"
#include "qgsgui.h"
#include <QtTest/QSignalSpy>
class TestQgsLayoutView: public QObject
@ -35,7 +37,7 @@ class TestQgsLayoutView: public QObject
void basic();
void tool();
void events();
void registryUtils();
void guiRegistry();
void rubberBand();
private:
@ -246,12 +248,22 @@ QString mReport;
bool renderCheck( QString testName, QImage &image, int mismatchCount );
void TestQgsLayoutView::registryUtils()
void TestQgsLayoutView::guiRegistry()
{
// test QgsLayoutItemGuiRegistry
QgsLayoutItemGuiRegistry registry;
// empty registry
QVERIFY( !registry.itemMetadata( -1 ) );
QVERIFY( registry.itemTypes().isEmpty() );
QVERIFY( !registry.createItemWidget( 1 ) );
QSignalSpy spyTypeAdded( &registry, &QgsLayoutItemGuiRegistry::typeAdded );
// add a dummy item to registry
auto create = []( QgsLayout * layout, const QVariantMap & )->QgsLayoutItem*
auto createWidget = []()->QWidget*
{
return new TestItem( layout );
return new QWidget();
};
auto createRubberBand = []( QgsLayoutView * view )->QgsLayoutViewRubberBand *
@ -259,25 +271,38 @@ void TestQgsLayoutView::registryUtils()
return new QgsLayoutViewRectangularRubberBand( view );
};
QgsLayoutItemMetadata *metadata = new QgsLayoutItemMetadata( 2, QStringLiteral( "my type" ), QIcon(), create );
metadata->setRubberBandCreationFunction( createRubberBand );
QVERIFY( QgsApplication::layoutItemRegistry()->addLayoutItemType( metadata ) );
QgsLayoutItemGuiMetadata *metadata = new QgsLayoutItemGuiMetadata( 2, QIcon(), createWidget, createRubberBand );
QVERIFY( registry.addLayoutItemGuiMetadata( metadata ) );
QCOMPARE( spyTypeAdded.count(), 1 );
QCOMPARE( spyTypeAdded.value( 0 ).at( 0 ).toInt(), 2 );
// duplicate type id
QVERIFY( !registry.addLayoutItemGuiMetadata( metadata ) );
QCOMPARE( spyTypeAdded.count(), 1 );
//retrieve metadata
QVERIFY( !registry.itemMetadata( -1 ) );
QVERIFY( registry.itemMetadata( 2 ) );
QCOMPARE( registry.itemTypes().count(), 1 );
QCOMPARE( registry.itemTypes().value( 0 ), 2 );
QWidget *widget = registry.createItemWidget( 2 );
QVERIFY( widget );
delete widget;
QgsLayoutView *view = new QgsLayoutView();
//should use metadata's method
QgsLayoutViewRubberBand *band = QgsApplication::layoutItemRegistry()->createItemRubberBand( 2, view );
QgsLayoutViewRubberBand *band = registry.createItemRubberBand( 2, view );
QVERIFY( band );
QVERIFY( dynamic_cast< QgsLayoutViewRectangularRubberBand * >( band ) );
QCOMPARE( band->view(), view );
delete band;
//manually register a prototype
QgsLayoutItemRegistryGuiUtils::setItemRubberBandPrototype( 2, new QgsLayoutViewEllipticalRubberBand() );
band = QgsApplication::layoutItemRegistry()->createItemRubberBand( 2, view );
QVERIFY( band );
QVERIFY( dynamic_cast< QgsLayoutViewEllipticalRubberBand * >( band ) );
QCOMPARE( band->view(), view );
//test populate
QgsLayoutItemGuiRegistry reg2;
QVERIFY( reg2.itemTypes().isEmpty() );
QVERIFY( reg2.populate() );
QVERIFY( !reg2.itemTypes().isEmpty() );
QVERIFY( !reg2.populate() );
}
void TestQgsLayoutView::rubberBand()