Skip to content
Permalink
Browse files
Rework API to use composition pattern instead of direct inheritance
If we require all annotation item map tools to inherit from
QgsMapToolAdvancedDigitizing, then we lose the flexibility to
subclasss other map tools for annotation item creation (e.g.
QgsMapToolCapture)
  • Loading branch information
nyalldawson committed Sep 8, 2021
1 parent eb58e74 commit ef25d914e6d1801a46ca11a49852e069af5092c2
@@ -70,7 +70,7 @@ Returns an icon representing creation of the annotation item type.
Creates a configuration widget for an ``item`` of this type. Can return ``None`` if no configuration GUI is required.
%End

virtual QgsCreateAnnotationItemMapTool *createMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget ) /TransferBack/;
virtual QgsCreateAnnotationItemMapToolInterface *createMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget ) /TransferBack/;
%Docstring
Creates a map tool for a creating a new item of this type.

@@ -8,13 +8,16 @@



class QgsCreateAnnotationItemMapTool: QgsMapToolAdvancedDigitizing
class QgsCreateAnnotationItemMapToolHandler : QObject
{
%Docstring(signature="appended")

A base class for map tools which create annotation items.
A handler object for map tools which create annotation items.

Clients should connect to the map tool's :py:func:`~itemCreated` signal, and call the
This object is designed to be used by map tools which implement the
:py:class:`QgsCreateAnnotationItemMapToolInterface`, following the composition pattern.

Clients should connect to the handler's :py:func:`~itemCreated` signal, and call the
:py:func:`~takeCreatedItem` implementation to take ownership of the newly created item
whenever this signal is emitted.

@@ -26,17 +29,31 @@ whenever this signal is emitted.
%End
public:

QgsCreateAnnotationItemMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget );
QgsCreateAnnotationItemMapToolHandler( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget, QObject *parent = 0 );
%Docstring
Constructor for QgsCreateAnnotationItemMapTool.
Constructor for QgsCreateAnnotationItemMapToolHandler, with the specified ``parent`` object.
%End

virtual QgsAnnotationItem *takeCreatedItem() = 0 /TransferBack/;
~QgsCreateAnnotationItemMapToolHandler();

QgsAnnotationItem *takeCreatedItem() /TransferBack/;
%Docstring
Takes the newly created item from the tool, transferring ownership to the caller.
%End

QgsAnnotationLayer *targetLayer();
%Docstring
Returns the target layer for newly created items.
%End

Subclasses must implement this method, and ensure that they emit the :py:func:`~QgsCreateAnnotationItemMapTool.itemCreated` signal whenever
they have a created item ready for clients to take.
void pushCreatedItem( QgsAnnotationItem *item /Transfer/ );
%Docstring
Pushes a created ``item`` to the handler.

Ownership of ``item`` is transferred to the handler.

Calling this method causes the object to emit the :py:func:`~QgsCreateAnnotationItemMapToolHandler.itemCreated` signal, and queue the item
ready for collection via a call to :py:func:`~QgsCreateAnnotationItemMapToolHandler.takeCreatedItem`.
%End

signals:
@@ -45,16 +62,40 @@ they have a created item ready for clients to take.
%Docstring
Emitted by the tool when a new annotation item has been created.

Clients should connect to this signal and call :py:func:`~QgsCreateAnnotationItemMapTool.takeCreatedItem` to take the newly created item from the map tool.
Clients should connect to this signal and call :py:func:`~QgsCreateAnnotationItemMapToolHandler.takeCreatedItem` to take the newly created item from the map tool.
%End

protected:
};

class QgsCreateAnnotationItemMapToolInterface
{
%Docstring(signature="appended")

QgsAnnotationLayer *targetLayer();
An interface for map tools which create annotation items.

Clients should connect to the map tool's :py:func:`~QgsCreateAnnotationItemMapToolHandler.itemCreated` signal, and call the
:py:func:`~QgsCreateAnnotationItemMapToolHandler.takeCreatedItem` implementation to take ownership of the newly created item
whenever this signal is emitted.

.. versionadded:: 3.22
%End

%TypeHeaderCode
#include "qgscreateannotationitemmaptool.h"
%End
public:

virtual ~QgsCreateAnnotationItemMapToolInterface();

virtual QgsCreateAnnotationItemMapToolHandler *handler() = 0;
%Docstring
Returns the target layer for newly created items.
Returns the handler object for the map tool.
%End

virtual QgsMapTool *mapTool() = 0;
%Docstring
Returns a reference to the associated map tool.
%End
};

/************************************************************************
@@ -804,12 +804,12 @@ void QgisApp::annotationItemTypeAdded( int id )

connect( action, &QAction::triggered, this, [this, id]()
{
QgsCreateAnnotationItemMapTool *tool = QgsGui::annotationItemGuiRegistry()->itemMetadata( id )->createMapTool( mMapCanvas, mAdvancedDigitizingDockWidget );
mMapCanvas->setMapTool( tool );
connect( tool, &QgsMapTool::deactivated, tool, &QObject::deleteLater );
connect( tool, &QgsCreateAnnotationItemMapTool::itemCreated, this, [ = ]
QgsCreateAnnotationItemMapToolInterface *tool = QgsGui::annotationItemGuiRegistry()->itemMetadata( id )->createMapTool( mMapCanvas, mAdvancedDigitizingDockWidget );
mMapCanvas->setMapTool( tool->mapTool() );
connect( tool->mapTool(), &QgsMapTool::deactivated, tool->mapTool(), &QObject::deleteLater );
connect( tool->handler(), &QgsCreateAnnotationItemMapToolHandler::itemCreated, this, [ = ]
{
QgsAnnotationItem *item = tool->takeCreatedItem();
QgsAnnotationItem *item = tool->handler()->takeCreatedItem();
QgsAnnotationLayer *targetLayer = qobject_cast< QgsAnnotationLayer * >( activeLayer() );
if ( !targetLayer )
targetLayer = QgsProject::instance()->mainAnnotationLayer();
@@ -34,7 +34,7 @@ QgsAnnotationItemBaseWidget *QgsAnnotationItemAbstractGuiMetadata::createItemWid
return nullptr;
}

QgsCreateAnnotationItemMapTool *QgsAnnotationItemAbstractGuiMetadata::createMapTool( QgsMapCanvas *, QgsAdvancedDigitizingDockWidget * )
QgsCreateAnnotationItemMapToolInterface *QgsAnnotationItemAbstractGuiMetadata::createMapTool( QgsMapCanvas *, QgsAdvancedDigitizingDockWidget * )
{
return nullptr;
}
@@ -74,7 +74,7 @@ void QgsAnnotationItemGuiMetadata::newItemAddedToLayer( QgsAnnotationItem *item,
mAddedToLayerFunc( item, layer );
}

QgsCreateAnnotationItemMapTool *QgsAnnotationItemGuiMetadata::createMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget )
QgsCreateAnnotationItemMapToolInterface *QgsAnnotationItemGuiMetadata::createMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget )
{
return mCreateMapToolFunc ? mCreateMapToolFunc( canvas, cadDockWidget ) : nullptr;
}
@@ -180,7 +180,7 @@ void QgsAnnotationItemGuiRegistry::addDefaultItems()
{
addAnnotationItemGuiMetadata( new QgsAnnotationItemGuiMetadata( QStringLiteral( "polygon" ),
QObject::tr( "Polygon" ),
QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddImage.svg" ) ),
QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddPolygon.svg" ) ),
[ = ]( QgsAnnotationItem * item )->QgsAnnotationItemBaseWidget *
{
QgsAnnotationPolygonItemWidget *widget = new QgsAnnotationPolygonItemWidget( nullptr );
@@ -190,7 +190,7 @@ void QgsAnnotationItemGuiRegistry::addDefaultItems()

addAnnotationItemGuiMetadata( new QgsAnnotationItemGuiMetadata( QStringLiteral( "linestring" ),
QObject::tr( "Line" ),
QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddImage.svg" ) ),
QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddPolyline.svg" ) ),
[ = ]( QgsAnnotationItem * item )->QgsAnnotationItemBaseWidget *
{
QgsAnnotationLineItemWidget *widget = new QgsAnnotationLineItemWidget( nullptr );
@@ -217,7 +217,7 @@ void QgsAnnotationItemGuiRegistry::addDefaultItems()
widget->setItem( item );
return widget;
}, QString(), Qgis::AnnotationItemGuiFlags(), nullptr,
[ = ]( QgsMapCanvas * canvas, QgsAdvancedDigitizingDockWidget * cadDockWidget )->QgsCreateAnnotationItemMapTool *
[ = ]( QgsMapCanvas * canvas, QgsAdvancedDigitizingDockWidget * cadDockWidget )->QgsCreateAnnotationItemMapToolInterface *
{
return new QgsCreatePointTextItemMapTool( canvas, cadDockWidget );
} ) );
@@ -28,7 +28,7 @@
class QgsAnnotationLayer;
class QgsAnnotationItem;
class QgsAnnotationItemBaseWidget;
class QgsCreateAnnotationItemMapTool;
class QgsCreateAnnotationItemMapToolInterface;
class QgsMapCanvas;
class QgsAdvancedDigitizingDockWidget;

@@ -112,7 +112,7 @@ class GUI_EXPORT QgsAnnotationItemAbstractGuiMetadata
*
* May return NULLPTR if no map tool is available for creating the item.
*/
virtual QgsCreateAnnotationItemMapTool *createMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget ) SIP_TRANSFERBACK;
virtual QgsCreateAnnotationItemMapToolInterface *createMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget ) SIP_TRANSFERBACK;

/**
* Creates an instance of the corresponding item type.
@@ -140,7 +140,7 @@ class GUI_EXPORT QgsAnnotationItemAbstractGuiMetadata
typedef std::function<QgsAnnotationItemBaseWidget *( QgsAnnotationItem * )> QgsAnnotationItemWidgetFunc SIP_SKIP;

//! Create annotation map tool creation function
typedef std::function<QgsCreateAnnotationItemMapTool *( QgsMapCanvas *, QgsAdvancedDigitizingDockWidget * )> QgsCreateAnnotationItemMapToolFunc SIP_SKIP;
typedef std::function<QgsCreateAnnotationItemMapToolInterface *( QgsMapCanvas *, QgsAdvancedDigitizingDockWidget * )> QgsCreateAnnotationItemMapToolFunc SIP_SKIP;

//! Annotation item added to layer callback
typedef std::function<void ( QgsAnnotationItem *, QgsAnnotationLayer *layer )> QgsAnnotationItemAddedToLayerFunc SIP_SKIP;
@@ -232,7 +232,7 @@ class GUI_EXPORT QgsAnnotationItemGuiMetadata : public QgsAnnotationItemAbstract

QgsAnnotationItem *createItem() override;
void newItemAddedToLayer( QgsAnnotationItem *item, QgsAnnotationLayer *layer ) override;
QgsCreateAnnotationItemMapTool *createMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget ) override;
QgsCreateAnnotationItemMapToolInterface *createMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget ) override;

protected:
QIcon mIcon;
@@ -16,17 +16,33 @@
#include "qgscreateannotationitemmaptool.h"
#include "qgsmapcanvas.h"
#include "qgsannotationlayer.h"
#include "qgsannotationitem.h"

QgsCreateAnnotationItemMapTool::QgsCreateAnnotationItemMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget )
: QgsMapToolAdvancedDigitizing( canvas, cadDockWidget )
QgsCreateAnnotationItemMapToolHandler::QgsCreateAnnotationItemMapToolHandler( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget, QObject *parent )
: QObject( parent )
, mMapCanvas( canvas )
, mCadDockWidget( cadDockWidget )
{

}

QgsAnnotationLayer *QgsCreateAnnotationItemMapTool::targetLayer()
QgsAnnotationItem *QgsCreateAnnotationItemMapToolHandler::takeCreatedItem()
{
if ( QgsAnnotationLayer *res = qobject_cast< QgsAnnotationLayer * >( canvas()->currentLayer() ) )
return mCreatedItem.release();
}

QgsCreateAnnotationItemMapToolHandler::~QgsCreateAnnotationItemMapToolHandler() = default;

QgsAnnotationLayer *QgsCreateAnnotationItemMapToolHandler::targetLayer()
{
if ( QgsAnnotationLayer *res = qobject_cast< QgsAnnotationLayer * >( mMapCanvas->currentLayer() ) )
return res;
else
return QgsProject::instance()->mainAnnotationLayer();
}

void QgsCreateAnnotationItemMapToolHandler::pushCreatedItem( QgsAnnotationItem *item )
{
mCreatedItem.reset( item );
emit itemCreated();
}
@@ -23,35 +23,52 @@ class QgsAnnotationItem;
class QgsAnnotationLayer;

/**
* \class QgsCreateAnnotationItemMapTool
* \class QgsCreateAnnotationItemMapToolHandler
* \ingroup gui
*
* \brief A base class for map tools which create annotation items.
* \brief A handler object for map tools which create annotation items.
*
* Clients should connect to the map tool's itemCreated() signal, and call the
* This object is designed to be used by map tools which implement the
* QgsCreateAnnotationItemMapToolInterface, following the composition pattern.
*
* Clients should connect to the handler's itemCreated() signal, and call the
* takeCreatedItem() implementation to take ownership of the newly created item
* whenever this signal is emitted.
*
* \since QGIS 3.22
*/
class GUI_EXPORT QgsCreateAnnotationItemMapTool: public QgsMapToolAdvancedDigitizing
class GUI_EXPORT QgsCreateAnnotationItemMapToolHandler : public QObject
{
Q_OBJECT

public:

/**
* Constructor for QgsCreateAnnotationItemMapTool.
* Constructor for QgsCreateAnnotationItemMapToolHandler, with the specified \a parent object.
*/
QgsCreateAnnotationItemMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget );
QgsCreateAnnotationItemMapToolHandler( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget, QObject *parent = nullptr );

~QgsCreateAnnotationItemMapToolHandler() override;

/**
* Takes the newly created item from the tool, transferring ownership to the caller.
*/
QgsAnnotationItem *takeCreatedItem() SIP_TRANSFERBACK;

/**
* Returns the target layer for newly created items.
*/
QgsAnnotationLayer *targetLayer();

/**
* Pushes a created \a item to the handler.
*
* Subclasses must implement this method, and ensure that they emit the itemCreated() signal whenever
* they have a created item ready for clients to take.
* Ownership of \a item is transferred to the handler.
*
* Calling this method causes the object to emit the itemCreated() signal, and queue the item
* ready for collection via a call to takeCreatedItem().
*/
virtual QgsAnnotationItem *takeCreatedItem() = 0 SIP_TRANSFERBACK;
void pushCreatedItem( QgsAnnotationItem *item SIP_TRANSFER );

signals:

@@ -62,13 +79,41 @@ class GUI_EXPORT QgsCreateAnnotationItemMapTool: public QgsMapToolAdvancedDigiti
*/
void itemCreated();

protected:
private:

QgsMapCanvas *mMapCanvas = nullptr;
QgsAdvancedDigitizingDockWidget *mCadDockWidget = nullptr;
std::unique_ptr< QgsAnnotationItem > mCreatedItem;

};

/**
* \class QgsCreateAnnotationItemMapToolInterface
* \ingroup gui
*
* \brief An interface for map tools which create annotation items.
*
* Clients should connect to the map tool's itemCreated() signal, and call the
* takeCreatedItem() implementation to take ownership of the newly created item
* whenever this signal is emitted.
*
* \since QGIS 3.22
*/
class GUI_EXPORT QgsCreateAnnotationItemMapToolInterface
{
public:

virtual ~QgsCreateAnnotationItemMapToolInterface() = default;

/**
* Returns the target layer for newly created items.
* Returns the handler object for the map tool.
*/
QgsAnnotationLayer *targetLayer();
virtual QgsCreateAnnotationItemMapToolHandler *handler() = 0;

/**
* Returns a reference to the associated map tool.
*/
virtual QgsMapTool *mapTool() = 0;
};

#endif // QGSCREATEANNOTATIONITEMMAPTOOL_H

0 comments on commit ef25d91

Please sign in to comment.