Skip to content

Commit

Permalink
When the modify annotation tool is used to select an annotation item,
Browse files Browse the repository at this point in the history
show a panel in the layer styling dock allowing users to modify
the appearance of the annotation
  • Loading branch information
nyalldawson committed Sep 7, 2021
1 parent 38b8b82 commit 4871520
Show file tree
Hide file tree
Showing 12 changed files with 274 additions and 2 deletions.
7 changes: 7 additions & 0 deletions python/gui/auto_generated/qgisinterface.sip.in
Expand Up @@ -1569,6 +1569,13 @@ Any existing GPS connection used by the widget will be disconnect and replaced w
is automatically registered within the :py:func:`QgsApplication.gpsConnectionRegistry()`.

.. versionadded:: 3.16
%End

virtual QgsMapToolModifyAnnotation *modifyAnnotationTool() = 0;
%Docstring
Returns the map tool used for modifying annotation layers.

.. versionadded:: 3.22
%End

signals:
Expand Down
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Expand Up @@ -106,6 +106,8 @@ set(QGIS_APP_SRCS
qgsmaptoolsvgannotation.cpp
qgsmaptooltextannotation.cpp

annotations/qgsannotationitempropertieswidget.cpp

decorations/qgsdecorationitem.cpp
decorations/qgsdecorationtitle.cpp
decorations/qgsdecorationtitledialog.cpp
Expand Down
153 changes: 153 additions & 0 deletions src/app/annotations/qgsannotationitempropertieswidget.cpp
@@ -0,0 +1,153 @@
/***************************************************************************
qgsannotationitempropertieswidget.cpp
---------------------
begin : December 2020
copyright : (C) 2020 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 "qgsannotationitempropertieswidget.h"
#include "qgsstyle.h"
#include "qgsapplication.h"
#include "qgsmaplayer.h"
#include "qgsannotationlayer.h"
#include "qgsannotationitemwidget.h"
#include "qgsannotationitem.h"
#include "qgsgui.h"
#include "qgsannotationitemguiregistry.h"
#include <QStackedWidget>
#include <QHBoxLayout>

QgsAnnotationItemPropertiesWidget::QgsAnnotationItemPropertiesWidget( QgsAnnotationLayer *layer, QgsMapCanvas *canvas, QWidget *parent )
: QgsMapLayerConfigWidget( layer, canvas, parent )
{
mStack = new QStackedWidget();

setDockMode( true );

QHBoxLayout *l = new QHBoxLayout();
l->setContentsMargins( 0, 0, 0, 0 );
l->addWidget( mStack );
setLayout( l );

syncToLayer( layer );
}

void QgsAnnotationItemPropertiesWidget::syncToLayer( QgsMapLayer *layer )
{
if ( layer == mLayer )
return;

mLayer = qobject_cast< QgsAnnotationLayer * >( layer );
if ( !mLayer )
return;

// check context
setItemId( mContext.annotationId() );
}

void QgsAnnotationItemPropertiesWidget::setContext( const QgsMapLayerConfigWidgetContext &context )
{
QgsMapLayerConfigWidget::setContext( context );
setItemId( context.annotationId() );
}

void QgsAnnotationItemPropertiesWidget::setDockMode( bool dockMode )
{
QgsMapLayerConfigWidget::setDockMode( dockMode );
if ( mItemWidget )
mItemWidget->setDockMode( dockMode );
}

void QgsAnnotationItemPropertiesWidget::apply()
{
if ( !mLayer )
return;

mLayer->triggerRepaint();
}

void QgsAnnotationItemPropertiesWidget::onChanged()
{
// set the annotation layer's item's properties to match the widget
std::unique_ptr< QgsAnnotationItem > newItem( mItemWidget->createItem() );

mLayer->replaceItem( mContext.annotationId(), newItem.release() );
}

void QgsAnnotationItemPropertiesWidget::setItemId( const QString &itemId )
{
// try to retrieve matching item
bool setItem = false;
if ( QgsAnnotationItem *item = mLayer->item( itemId ) )
{
if ( mItemWidget )
{
setItem = mItemWidget->setItem( item );
}

if ( !setItem )
{
// create new item
mItemWidget = QgsGui::annotationItemGuiRegistry()->createItemWidget( item );

if ( mItemWidget )
{
setItem = true;

QWidget *prevWidget = mStack->currentWidget();
mStack->removeWidget( prevWidget );
delete prevWidget;

mStack->addWidget( mItemWidget );
connect( mItemWidget, &QgsAnnotationItemBaseWidget::itemChanged, this, &QgsAnnotationItemPropertiesWidget::onChanged );
mItemWidget->setDockMode( dockMode() );
connect( mItemWidget, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
}
}
}

if ( !setItem )
{
// show a "no item" widget
}
}

//
// QgsAnnotationItemPropertiesWidgetFactory
//

QgsAnnotationItemPropertiesWidgetFactory::QgsAnnotationItemPropertiesWidgetFactory( QObject *parent )
: QObject( parent )
{
setIcon( QgsApplication::getThemeIcon( QStringLiteral( "propertyicons/symbology.svg" ) ) );
setTitle( tr( "Annotation" ) );
}

QgsMapLayerConfigWidget *QgsAnnotationItemPropertiesWidgetFactory::createWidget( QgsMapLayer *layer, QgsMapCanvas *canvas, bool, QWidget *parent ) const
{
return new QgsAnnotationItemPropertiesWidget( qobject_cast< QgsAnnotationLayer * >( layer ), canvas, parent );
}

bool QgsAnnotationItemPropertiesWidgetFactory::supportLayerPropertiesDialog() const
{
return false;
}

bool QgsAnnotationItemPropertiesWidgetFactory::supportsStyleDock() const
{
return true;
}

bool QgsAnnotationItemPropertiesWidgetFactory::supportsLayer( QgsMapLayer *layer ) const
{
return layer->type() == QgsMapLayerType::AnnotationLayer;
}

68 changes: 68 additions & 0 deletions src/app/annotations/qgsannotationitempropertieswidget.h
@@ -0,0 +1,68 @@
/***************************************************************************
qgsannotationitempropertieswidget.h
---------------------
begin : September 2021
copyright : (C) 2021 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 QGSANNOTATIONITEMPROPERTIESWIDGET_H
#define QGSANNOTATIONITEMPROPERTIESWIDGET_H

#include "qgsmaplayerconfigwidget.h"
#include "qgsmaplayerconfigwidgetfactory.h"

class QgsAnnotationLayer;
class QgsAnnotationItemBaseWidget;
class QStackedWidget;

class QgsAnnotationItemPropertiesWidget : public QgsMapLayerConfigWidget
{
Q_OBJECT
public:

QgsAnnotationItemPropertiesWidget( QgsAnnotationLayer *layer, QgsMapCanvas *canvas, QWidget *parent );

void syncToLayer( QgsMapLayer *layer ) override;
void setContext( const QgsMapLayerConfigWidgetContext &context ) override;
void setDockMode( bool dockMode ) override;

public slots:
void apply() override;

private slots:

void onChanged();
private:

void setItemId( const QString &itemId );

QStackedWidget *mStack = nullptr;
QgsAnnotationLayer *mLayer = nullptr;
QgsAnnotationItemBaseWidget *mItemWidget = nullptr;

};


class QgsAnnotationItemPropertiesWidgetFactory : public QObject, public QgsMapLayerConfigWidgetFactory
{
Q_OBJECT
public:
explicit QgsAnnotationItemPropertiesWidgetFactory( QObject *parent = nullptr );

QgsMapLayerConfigWidget *createWidget( QgsMapLayer *layer, QgsMapCanvas *canvas, bool dockWidget, QWidget *parent ) const override;
bool supportLayerPropertiesDialog() const override;
bool supportsStyleDock() const override;
bool supportsLayer( QgsMapLayer *layer ) const override;
};



#endif // QGSANNOTATIONITEMPROPERTIESWIDGET_H
2 changes: 2 additions & 0 deletions src/app/maptools/qgsappmaptools.cpp
Expand Up @@ -72,6 +72,7 @@
#include "qgsmaptooleditmeshframe.h"
#include "qgsspinbox.h"
#include "qgssettingsregistrycore.h"
#include "qgsmaptoolmodifyannotation.h"

//
// QgsStreamDigitizingSettingsAction
Expand Down Expand Up @@ -178,6 +179,7 @@ QgsAppMapTools::QgsAppMapTools( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockW
mTools.insert( Tool::RotateLabel, new QgsMapToolRotateLabel( canvas, cadDock ) );
mTools.insert( Tool::ChangeLabelProperties, new QgsMapToolChangeLabelProperties( canvas, cadDock ) );
mTools.insert( Tool::EditMeshFrame, new QgsMapToolEditMeshFrame( canvas ) );
mTools.insert( Tool::AnnotationEdit, new QgsMapToolModifyAnnotation( canvas, cadDock ) );

mStreamDigitizingSettingsAction = new QgsStreamDigitizingSettingsAction();
}
Expand Down
3 changes: 2 additions & 1 deletion src/app/maptools/qgsappmaptools.h
Expand Up @@ -113,7 +113,8 @@ class QgsAppMapTools
ChangeLabelProperties,
ReverseLine,
TrimExtendFeature,
EditMeshFrame
EditMeshFrame,
AnnotationEdit
};

QgsAppMapTools( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDock );
Expand Down
7 changes: 7 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -104,6 +104,9 @@
#include "qgsprovidersublayersdialog.h"
#include "qgsmaplayerfactory.h"
#include "qgsbrowserwidget.h"
#include "annotations/qgsannotationitempropertieswidget.h"
#include "qgsmaptoolmodifyannotation.h"
#include "qgsannotationlayer.h"

#include "qgsanalysis.h"
#include "qgsgeometrycheckregistry.h"
Expand Down Expand Up @@ -1338,6 +1341,7 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
registerMapLayerPropertiesFactory( new QgsPointCloudLayer3DRendererWidgetFactory( this ) );
#endif
registerMapLayerPropertiesFactory( new QgsPointCloudElevationPropertiesWidgetFactory( this ) );
registerMapLayerPropertiesFactory( new QgsAnnotationItemPropertiesWidgetFactory( this ) );

activateDeactivateLayerRelatedActions( nullptr ); // after members were created

Expand Down Expand Up @@ -1661,6 +1665,9 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
updateCrsStatusBar();
endProfile();

connect( qobject_cast< QgsMapToolModifyAnnotation * >( mMapTools->mapTool( QgsAppMapTools::AnnotationEdit ) ), &QgsMapToolModifyAnnotation::itemSelected,
mMapStyleWidget, &QgsLayerStylingWidget::setAnnotationItem );

// request notification of FileOpen events (double clicking a file icon in Mac OS X Finder)
// should come after fileNewBlank to ensure project is properly set up to receive any data source files
QgsApplication::setFileOpenEventReceiver( this );
Expand Down
8 changes: 7 additions & 1 deletion src/app/qgisappinterface.cpp
Expand Up @@ -47,7 +47,8 @@
#include "qgslocatorwidget.h"
#include "qgslocator.h"
#include "qgsmessagebar.h"

#include "qgsappmaptools.h"
#include "qgsmaptoolmodifyannotation.h"

QgisAppInterface::QgisAppInterface( QgisApp *_qgis )
: qgis( _qgis )
Expand Down Expand Up @@ -907,3 +908,8 @@ QList<QgsMapDecoration *> QgisAppInterface::activeDecorations()
{
return qgis->activeDecorations();
}

QgsMapToolModifyAnnotation *QgisAppInterface::modifyAnnotationTool()
{
return qobject_cast< QgsMapToolModifyAnnotation * >( qgis->mMapTools->mapTool( QgsAppMapTools::AnnotationEdit ) );
}
1 change: 1 addition & 0 deletions src/app/qgisappinterface.h
Expand Up @@ -322,6 +322,7 @@ class APP_EXPORT QgisAppInterface : public QgisInterface
QgsLayerTreeRegistryBridge::InsertionPoint layerTreeInsertionPoint() override;
void setGpsPanelConnection( QgsGpsConnection *connection ) override;
QList<QgsMapDecoration *> activeDecorations() override;
virtual QgsMapToolModifyAnnotation *modifyAnnotationTool() override;

private slots:

Expand Down
11 changes: 11 additions & 0 deletions src/app/qgslayerstylingwidget.cpp
Expand Up @@ -700,6 +700,17 @@ void QgsLayerStylingWidget::setCurrentPage( QgsLayerStylingWidget::Page page )
}
}

void QgsLayerStylingWidget::setAnnotationItem( QgsAnnotationLayer *layer, const QString &itemId )
{
mContext.setAnnotationId( itemId );
setLayer( layer );

if ( QgsMapLayerConfigWidget *configWidget = qobject_cast< QgsMapLayerConfigWidget * >( mWidgetStack->mainPanel() ) )
{
configWidget->setContext( mContext );
}
}

void QgsLayerStylingWidget::layerAboutToBeRemoved( QgsMapLayer *layer )
{
if ( layer == mCurrentLayer )
Expand Down
6 changes: 6 additions & 0 deletions src/app/qgslayerstylingwidget.h
Expand Up @@ -48,6 +48,7 @@ class QgsPointCloudLayer3DRendererWidget;
class QgsMessageBar;
class QgsVectorTileBasicRendererWidget;
class QgsVectorTileBasicLabelingWidget;
class QgsAnnotationLayer;

class APP_EXPORT QgsLayerStyleManagerWidgetFactory : public QgsMapLayerConfigWidgetFactory
{
Expand Down Expand Up @@ -129,6 +130,11 @@ class APP_EXPORT QgsLayerStylingWidget : public QWidget, private Ui::QgsLayerSty
*/
void setCurrentPage( QgsLayerStylingWidget::Page page );

/**
* Sets an annotation item to show in the widget.
*/
void setAnnotationItem( QgsAnnotationLayer *layer, const QString &itemId );

private slots:

void layerAboutToBeRemoved( QgsMapLayer *layer );
Expand Down
8 changes: 8 additions & 0 deletions src/gui/qgisinterface.h
Expand Up @@ -70,6 +70,7 @@ class QgsDevToolWidgetFactory;
class QgsGpsConnection;
class QgsApplicationExitBlockerInterface;
class QgsAbstractMapToolHandler;
class QgsMapToolModifyAnnotation;

/**
* \ingroup gui
Expand Down Expand Up @@ -1311,6 +1312,13 @@ class GUI_EXPORT QgisInterface : public QObject
*/
virtual void setGpsPanelConnection( QgsGpsConnection *connection ) = 0;

/**
* Returns the map tool used for modifying annotation layers.
*
* \since QGIS 3.22
*/
virtual QgsMapToolModifyAnnotation *modifyAnnotationTool() = 0;

signals:

/**
Expand Down

0 comments on commit 4871520

Please sign in to comment.