When the modify annotation tool is used to select an annotation item,

show a panel in the layer styling dock allowing users to modify
the appearance of the annotation
This commit is contained in:
Nyall Dawson 2021-09-03 17:29:07 +10:00
parent 38b8b82674
commit 48715202f7
12 changed files with 274 additions and 2 deletions

View File

@ -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:

View File

@ -106,6 +106,8 @@ set(QGIS_APP_SRCS
qgsmaptoolsvgannotation.cpp
qgsmaptooltextannotation.cpp
annotations/qgsannotationitempropertieswidget.cpp
decorations/qgsdecorationitem.cpp
decorations/qgsdecorationtitle.cpp
decorations/qgsdecorationtitledialog.cpp

View File

@ -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;
}

View File

@ -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

View File

@ -72,6 +72,7 @@
#include "qgsmaptooleditmeshframe.h"
#include "qgsspinbox.h"
#include "qgssettingsregistrycore.h"
#include "qgsmaptoolmodifyannotation.h"
//
// QgsStreamDigitizingSettingsAction
@ -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();
}

View File

@ -113,7 +113,8 @@ class QgsAppMapTools
ChangeLabelProperties,
ReverseLine,
TrimExtendFeature,
EditMeshFrame
EditMeshFrame,
AnnotationEdit
};
QgsAppMapTools( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDock );

View File

@ -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"
@ -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
@ -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 );

View File

@ -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 )
@ -907,3 +908,8 @@ QList<QgsMapDecoration *> QgisAppInterface::activeDecorations()
{
return qgis->activeDecorations();
}
QgsMapToolModifyAnnotation *QgisAppInterface::modifyAnnotationTool()
{
return qobject_cast< QgsMapToolModifyAnnotation * >( qgis->mMapTools->mapTool( QgsAppMapTools::AnnotationEdit ) );
}

View File

@ -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:

View File

@ -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 )

View File

@ -48,6 +48,7 @@ class QgsPointCloudLayer3DRendererWidget;
class QgsMessageBar;
class QgsVectorTileBasicRendererWidget;
class QgsVectorTileBasicLabelingWidget;
class QgsAnnotationLayer;
class APP_EXPORT QgsLayerStyleManagerWidgetFactory : public QgsMapLayerConfigWidgetFactory
{
@ -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 );

View File

@ -70,6 +70,7 @@ class QgsDevToolWidgetFactory;
class QgsGpsConnection;
class QgsApplicationExitBlockerInterface;
class QgsAbstractMapToolHandler;
class QgsMapToolModifyAnnotation;
/**
* \ingroup gui
@ -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:
/**