Skip to content

Commit

Permalink
Rework API to use composition pattern instead of direct inheritance
Browse files Browse the repository at this point in the history
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 ef25d91
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 56 deletions.
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -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. Creates a configuration widget for an ``item`` of this type. Can return ``None`` if no configuration GUI is required.
%End %End


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


Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@






class QgsCreateAnnotationItemMapTool: QgsMapToolAdvancedDigitizing class QgsCreateAnnotationItemMapToolHandler : QObject
{ {
%Docstring(signature="appended") %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 :py:func:`~takeCreatedItem` implementation to take ownership of the newly created item
whenever this signal is emitted. whenever this signal is emitted.


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


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


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

QgsAnnotationItem *takeCreatedItem() /TransferBack/;
%Docstring %Docstring
Takes the newly created item from the tool, transferring ownership to the caller. 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 void pushCreatedItem( QgsAnnotationItem *item /Transfer/ );
they have a created item ready for clients to take. %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 %End


signals: signals:
Expand All @@ -45,16 +62,40 @@ they have a created item ready for clients to take.
%Docstring %Docstring
Emitted by the tool when a new annotation item has been created. 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 %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 %Docstring
Returns the target layer for newly created items. Returns the handler object for the map tool.
%End %End


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


/************************************************************************ /************************************************************************
Expand Down
10 changes: 5 additions & 5 deletions src/app/qgisapp.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -804,12 +804,12 @@ void QgisApp::annotationItemTypeAdded( int id )


connect( action, &QAction::triggered, this, [this, id]() connect( action, &QAction::triggered, this, [this, id]()
{ {
QgsCreateAnnotationItemMapTool *tool = QgsGui::annotationItemGuiRegistry()->itemMetadata( id )->createMapTool( mMapCanvas, mAdvancedDigitizingDockWidget ); QgsCreateAnnotationItemMapToolInterface *tool = QgsGui::annotationItemGuiRegistry()->itemMetadata( id )->createMapTool( mMapCanvas, mAdvancedDigitizingDockWidget );
mMapCanvas->setMapTool( tool ); mMapCanvas->setMapTool( tool->mapTool() );
connect( tool, &QgsMapTool::deactivated, tool, &QObject::deleteLater ); connect( tool->mapTool(), &QgsMapTool::deactivated, tool->mapTool(), &QObject::deleteLater );
connect( tool, &QgsCreateAnnotationItemMapTool::itemCreated, this, [ = ] connect( tool->handler(), &QgsCreateAnnotationItemMapToolHandler::itemCreated, this, [ = ]
{ {
QgsAnnotationItem *item = tool->takeCreatedItem(); QgsAnnotationItem *item = tool->handler()->takeCreatedItem();
QgsAnnotationLayer *targetLayer = qobject_cast< QgsAnnotationLayer * >( activeLayer() ); QgsAnnotationLayer *targetLayer = qobject_cast< QgsAnnotationLayer * >( activeLayer() );
if ( !targetLayer ) if ( !targetLayer )
targetLayer = QgsProject::instance()->mainAnnotationLayer(); targetLayer = QgsProject::instance()->mainAnnotationLayer();
Expand Down
10 changes: 5 additions & 5 deletions src/gui/annotations/qgsannotationitemguiregistry.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ QgsAnnotationItemBaseWidget *QgsAnnotationItemAbstractGuiMetadata::createItemWid
return nullptr; return nullptr;
} }


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


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


addAnnotationItemGuiMetadata( new QgsAnnotationItemGuiMetadata( QStringLiteral( "linestring" ), addAnnotationItemGuiMetadata( new QgsAnnotationItemGuiMetadata( QStringLiteral( "linestring" ),
QObject::tr( "Line" ), QObject::tr( "Line" ),
QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddImage.svg" ) ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddPolyline.svg" ) ),
[ = ]( QgsAnnotationItem * item )->QgsAnnotationItemBaseWidget * [ = ]( QgsAnnotationItem * item )->QgsAnnotationItemBaseWidget *
{ {
QgsAnnotationLineItemWidget *widget = new QgsAnnotationLineItemWidget( nullptr ); QgsAnnotationLineItemWidget *widget = new QgsAnnotationLineItemWidget( nullptr );
Expand All @@ -217,7 +217,7 @@ void QgsAnnotationItemGuiRegistry::addDefaultItems()
widget->setItem( item ); widget->setItem( item );
return widget; return widget;
}, QString(), Qgis::AnnotationItemGuiFlags(), nullptr, }, QString(), Qgis::AnnotationItemGuiFlags(), nullptr,
[ = ]( QgsMapCanvas * canvas, QgsAdvancedDigitizingDockWidget * cadDockWidget )->QgsCreateAnnotationItemMapTool * [ = ]( QgsMapCanvas * canvas, QgsAdvancedDigitizingDockWidget * cadDockWidget )->QgsCreateAnnotationItemMapToolInterface *
{ {
return new QgsCreatePointTextItemMapTool( canvas, cadDockWidget ); return new QgsCreatePointTextItemMapTool( canvas, cadDockWidget );
} ) ); } ) );
Expand Down
8 changes: 4 additions & 4 deletions src/gui/annotations/qgsannotationitemguiregistry.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
class QgsAnnotationLayer; class QgsAnnotationLayer;
class QgsAnnotationItem; class QgsAnnotationItem;
class QgsAnnotationItemBaseWidget; class QgsAnnotationItemBaseWidget;
class QgsCreateAnnotationItemMapTool; class QgsCreateAnnotationItemMapToolInterface;
class QgsMapCanvas; class QgsMapCanvas;
class QgsAdvancedDigitizingDockWidget; class QgsAdvancedDigitizingDockWidget;


Expand Down Expand Up @@ -112,7 +112,7 @@ class GUI_EXPORT QgsAnnotationItemAbstractGuiMetadata
* *
* May return NULLPTR if no map tool is available for creating the item. * 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. * Creates an instance of the corresponding item type.
Expand Down Expand Up @@ -140,7 +140,7 @@ class GUI_EXPORT QgsAnnotationItemAbstractGuiMetadata
typedef std::function<QgsAnnotationItemBaseWidget *( QgsAnnotationItem * )> QgsAnnotationItemWidgetFunc SIP_SKIP; typedef std::function<QgsAnnotationItemBaseWidget *( QgsAnnotationItem * )> QgsAnnotationItemWidgetFunc SIP_SKIP;


//! Create annotation map tool creation function //! 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 //! Annotation item added to layer callback
typedef std::function<void ( QgsAnnotationItem *, QgsAnnotationLayer *layer )> QgsAnnotationItemAddedToLayerFunc SIP_SKIP; typedef std::function<void ( QgsAnnotationItem *, QgsAnnotationLayer *layer )> QgsAnnotationItemAddedToLayerFunc SIP_SKIP;
Expand Down Expand Up @@ -232,7 +232,7 @@ class GUI_EXPORT QgsAnnotationItemGuiMetadata : public QgsAnnotationItemAbstract


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


protected: protected:
QIcon mIcon; QIcon mIcon;
Expand Down
24 changes: 20 additions & 4 deletions src/gui/annotations/qgscreateannotationitemmaptool.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,17 +16,33 @@
#include "qgscreateannotationitemmaptool.h" #include "qgscreateannotationitemmaptool.h"
#include "qgsmapcanvas.h" #include "qgsmapcanvas.h"
#include "qgsannotationlayer.h" #include "qgsannotationlayer.h"
#include "qgsannotationitem.h"


QgsCreateAnnotationItemMapTool::QgsCreateAnnotationItemMapTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget ) QgsCreateAnnotationItemMapToolHandler::QgsCreateAnnotationItemMapToolHandler( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget, QObject *parent )
: QgsMapToolAdvancedDigitizing( canvas, cadDockWidget ) : 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; return res;
else else
return QgsProject::instance()->mainAnnotationLayer(); return QgsProject::instance()->mainAnnotationLayer();
} }

void QgsCreateAnnotationItemMapToolHandler::pushCreatedItem( QgsAnnotationItem *item )
{
mCreatedItem.reset( item );
emit itemCreated();
}
69 changes: 57 additions & 12 deletions src/gui/annotations/qgscreateannotationitemmaptool.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -23,35 +23,52 @@ class QgsAnnotationItem;
class QgsAnnotationLayer; class QgsAnnotationLayer;


/** /**
* \class QgsCreateAnnotationItemMapTool * \class QgsCreateAnnotationItemMapToolHandler
* \ingroup gui * \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 * takeCreatedItem() implementation to take ownership of the newly created item
* whenever this signal is emitted. * whenever this signal is emitted.
* *
* \since QGIS 3.22 * \since QGIS 3.22
*/ */
class GUI_EXPORT QgsCreateAnnotationItemMapTool: public QgsMapToolAdvancedDigitizing class GUI_EXPORT QgsCreateAnnotationItemMapToolHandler : public QObject
{ {
Q_OBJECT Q_OBJECT


public: 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. * 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 * Ownership of \a item is transferred to the handler.
* they have a created item ready for clients to take. *
* 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: signals:


Expand All @@ -62,13 +79,41 @@ class GUI_EXPORT QgsCreateAnnotationItemMapTool: public QgsMapToolAdvancedDigiti
*/ */
void itemCreated(); 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 #endif // QGSCREATEANNOTATIONITEMMAPTOOL_H
Loading

0 comments on commit ef25d91

Please sign in to comment.