From c228132cbbc975aee46d97d11eed91f677337231 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 3 Jul 2017 13:57:42 +1000 Subject: [PATCH] Layout designers listen out for new item types in registry and auto create actions for adding new items of the newly registered type This avoids hard-coding in available item types into layout UI classes, and allows designers to handle plugin-supplied item types --- python/core/layout/qgslayoutitemregistry.sip | 6 ++++ src/app/layout/qgslayoutdesignerdialog.cpp | 34 ++++++++++++++++++++ src/app/layout/qgslayoutdesignerdialog.h | 9 ++++++ src/core/layout/qgslayoutitemregistry.h | 18 ++++++++--- src/ui/layout/qgslayoutdesignerbase.ui | 8 ++--- tests/src/core/testqgslayoutitem.cpp | 2 +- 6 files changed, 68 insertions(+), 9 deletions(-) diff --git a/python/core/layout/qgslayoutitemregistry.sip b/python/core/layout/qgslayoutitemregistry.sip index fa69829fa5a..62ff7ed243a 100644 --- a/python/core/layout/qgslayoutitemregistry.sip +++ b/python/core/layout/qgslayoutitemregistry.sip @@ -37,6 +37,12 @@ class QgsLayoutItemAbstractMetadata :rtype: int %End + virtual QIcon icon() const; +%Docstring + Returns an icon representing the layout item type. + :rtype: QIcon +%End + QString visibleName() const; %Docstring Returns a translated, user visible name for the layout item class. diff --git a/src/app/layout/qgslayoutdesignerdialog.cpp b/src/app/layout/qgslayoutdesignerdialog.cpp index 31b0e9217af..f83d435fc9a 100644 --- a/src/app/layout/qgslayoutdesignerdialog.cpp +++ b/src/app/layout/qgslayoutdesignerdialog.cpp @@ -16,6 +16,7 @@ ***************************************************************************/ #include "qgslayoutdesignerdialog.h" +#include "qgslayoutitemregistry.h" #include "qgssettings.h" #include "qgisapp.h" #include "qgslogger.h" @@ -39,6 +40,7 @@ void QgsAppLayoutDesignerInterface::close() QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFlags flags ) : QMainWindow( parent, flags ) , mInterface( new QgsAppLayoutDesignerInterface( this ) ) + , mToolsActionGroup( new QActionGroup( this ) ) { QgsSettings settings; int size = settings.value( QStringLiteral( "IconSize" ), QGIS_ICON_SIZE ).toInt(); @@ -55,6 +57,16 @@ 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 ) + { + itemTypeAdded( typeIt.key(), typeIt.value() ); + } + //..and listen out for new item types + connect( QgsApplication::layoutItemRegistry(), &QgsLayoutItemRegistry::typeAdded, this, &QgsLayoutDesignerDialog::itemTypeAdded ); + restoreWindowState(); } @@ -122,6 +134,23 @@ void QgsLayoutDesignerDialog::closeEvent( QCloseEvent * ) saveWindowState(); } +void QgsLayoutDesignerDialog::itemTypeAdded( int type, const QString &name ) +{ + // 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() ); + mToolsActionGroup->addAction( action ); + mItemMenu->addAction( action ); + mItemToolbar->addAction( action ); + connect( action, &QAction::triggered, this, [this, type]() + { + activateNewItemCreationTool( type ); + } ); +} + void QgsLayoutDesignerDialog::saveWindowState() { QgsSettings settings; @@ -147,4 +176,9 @@ void QgsLayoutDesignerDialog::restoreWindowState() } } +void QgsLayoutDesignerDialog::activateNewItemCreationTool( int type ) +{ + QgsLogger::debug( QStringLiteral( "creating new %1 item " ).arg( QgsApplication::layoutItemRegistry()->itemMetadata( type )->visibleName() ) ); +} + diff --git a/src/app/layout/qgslayoutdesignerdialog.h b/src/app/layout/qgslayoutdesignerdialog.h index 2fba0bd413d..cd5e89a3189 100644 --- a/src/app/layout/qgslayoutdesignerdialog.h +++ b/src/app/layout/qgslayoutdesignerdialog.h @@ -96,18 +96,27 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner virtual void closeEvent( QCloseEvent * ) override; + private slots: + + void itemTypeAdded( int type, const QString &name ); + private: QgsAppLayoutDesignerInterface *mInterface = nullptr; QgsLayout *mLayout = nullptr; + QActionGroup *mToolsActionGroup = nullptr; + + //! Save window state void saveWindowState(); //! Restore the window and toolbar state void restoreWindowState(); + //! Switch to new item creation tool, for a new item of the specified \a type. + void activateNewItemCreationTool( int type ); }; diff --git a/src/core/layout/qgslayoutitemregistry.h b/src/core/layout/qgslayoutitemregistry.h index bc4515111c0..0f41ea1bb0e 100644 --- a/src/core/layout/qgslayoutitemregistry.h +++ b/src/core/layout/qgslayoutitemregistry.h @@ -18,8 +18,10 @@ #include "qgis_core.h" #include "qgis_sip.h" +#include "qgsapplication.h" #include "qgspathresolver.h" #include //for QGraphicsItem::UserType +#include #include class QgsLayout; @@ -51,6 +53,11 @@ class CORE_EXPORT QgsLayoutItemAbstractMetadata */ int type() const { return mType; } + /** + * Returns an icon representing the layout item type. + */ + virtual QIcon icon() const { return QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ); } + /** * Returns a translated, user visible name for the layout item class. */ @@ -112,11 +119,12 @@ class CORE_EXPORT QgsLayoutItemMetadata : public QgsLayoutItemAbstractMetadata * and \a visibleName, and function pointers for the various item and * configuration widget creation functions. */ - QgsLayoutItemMetadata( int type, const QString &visibleName, + QgsLayoutItemMetadata( int type, const QString &visibleName, const QIcon &icon, QgsLayoutItemCreateFunc pfCreate, QgsLayoutItemPathResolverFunc pfPathResolver = nullptr, QgsLayoutItemWidgetFunc pfWidget = nullptr ) : QgsLayoutItemAbstractMetadata( type, visibleName ) + , mIcon( icon ) , mCreateFunc( pfCreate ) , mWidgetFunc( pfWidget ) , mPathResolverFunc( pfPathResolver ) @@ -144,15 +152,17 @@ class CORE_EXPORT QgsLayoutItemMetadata : public QgsLayoutItemAbstractMetadata */ void setWidgetFunction( QgsLayoutItemWidgetFunc function ) { mWidgetFunc = function; } - virtual QgsLayoutItem *createItem( QgsLayout *layout, const QVariantMap &properties ) override { return mCreateFunc ? mCreateFunc( layout, properties ) : nullptr; } - virtual QWidget *createItemWidget() override { return mWidgetFunc ? mWidgetFunc() : nullptr; } - virtual void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) override + 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; } + void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) override { if ( mPathResolverFunc ) mPathResolverFunc( properties, pathResolver, saving ); } protected: + QIcon mIcon; QgsLayoutItemCreateFunc mCreateFunc = nullptr; QgsLayoutItemWidgetFunc mWidgetFunc = nullptr; QgsLayoutItemPathResolverFunc mPathResolverFunc = nullptr; diff --git a/src/ui/layout/qgslayoutdesignerbase.ui b/src/ui/layout/qgslayoutdesignerbase.ui index ff3602a8d9c..5a0088c83aa 100644 --- a/src/ui/layout/qgslayoutdesignerbase.ui +++ b/src/ui/layout/qgslayoutdesignerbase.ui @@ -80,19 +80,19 @@ 25 - + &Layout - + &Items - - + + diff --git a/tests/src/core/testqgslayoutitem.cpp b/tests/src/core/testqgslayoutitem.cpp index 4c321a49099..26c2485e74f 100644 --- a/tests/src/core/testqgslayoutitem.cpp +++ b/tests/src/core/testqgslayoutitem.cpp @@ -132,7 +132,7 @@ void TestQgsLayoutItem::registry() QSignalSpy spyTypeAdded( ®istry, &QgsLayoutItemRegistry::typeAdded ); - QgsLayoutItemMetadata *metadata = new QgsLayoutItemMetadata( 2, QStringLiteral( "my type" ), create, resolve, createWidget ); + QgsLayoutItemMetadata *metadata = new QgsLayoutItemMetadata( 2, QStringLiteral( "my type" ), QIcon(), create, resolve, createWidget ); QVERIFY( registry.addLayoutItemType( metadata ) ); QCOMPARE( spyTypeAdded.count(), 1 ); QCOMPARE( spyTypeAdded.value( 0 ).at( 0 ).toInt(), 2 );