Skip to content
Permalink
Browse files

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
  • Loading branch information
nyalldawson committed Jul 3, 2017
1 parent 97e8d9c commit c228132cbbc975aee46d97d11eed91f677337231
@@ -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.
@@ -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() ) );
}


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

};

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

0 comments on commit c228132

Please sign in to comment.
You can’t perform that action at this time.