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
This commit is contained in:
Nyall Dawson 2017-07-03 13:57:42 +10:00
parent 97e8d9cf9e
commit c228132cbb
6 changed files with 68 additions and 9 deletions

View File

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

View File

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

View File

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

View File

@ -18,8 +18,10 @@
#include "qgis_core.h"
#include "qgis_sip.h"
#include "qgsapplication.h"
#include "qgspathresolver.h"
#include <QGraphicsItem> //for QGraphicsItem::UserType
#include <QIcon>
#include <functional>
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;

View File

@ -80,19 +80,19 @@
<height>25</height>
</rect>
</property>
<widget class="QMenu" name="menuLayout">
<widget class="QMenu" name="mLayoutMenu">
<property name="title">
<string>&amp;Layout</string>
</property>
<addaction name="mActionClose"/>
</widget>
<widget class="QMenu" name="menuItems">
<widget class="QMenu" name="mItemMenu">
<property name="title">
<string>&amp;Items</string>
</property>
</widget>
<addaction name="menuLayout"/>
<addaction name="menuItems"/>
<addaction name="mLayoutMenu"/>
<addaction name="mItemMenu"/>
</widget>
<action name="mActionClose">
<property name="text">

View File

@ -132,7 +132,7 @@ void TestQgsLayoutItem::registry()
QSignalSpy spyTypeAdded( &registry, &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 );