Add method to specify item groups for item classes in QgsLayoutItemGuiRegistry

This allows the designer dialog to group the corresponding item
actions together (i.e. grouping all basic shape creation actions
together), but without any hardcoded special handling so that
plugin based items can also be grouped.
This commit is contained in:
Nyall Dawson 2017-07-18 12:36:16 +10:00
parent de2626d65c
commit 7f066672b3
6 changed files with 228 additions and 9 deletions

View File

@ -28,9 +28,11 @@ class QgsLayoutItemAbstractGuiMetadata
%End
public:
QgsLayoutItemAbstractGuiMetadata( int type );
QgsLayoutItemAbstractGuiMetadata( int type, const QString &groupId = QString() );
%Docstring
Constructor for QgsLayoutItemAbstractGuiMetadata with the specified class ``type``.
An optional ``groupId`` can be set, which allows grouping of related layout item classes. See QgsLayoutItemGuiMetadata for details.
%End
virtual ~QgsLayoutItemAbstractGuiMetadata();
@ -41,6 +43,12 @@ class QgsLayoutItemAbstractGuiMetadata
:rtype: int
%End
QString groupId() const;
%Docstring
Returns the item group ID, if set.
:rtype: str
%End
virtual QIcon creationIcon() const;
%Docstring
Returns an icon representing creation of the layout item type.
@ -65,6 +73,48 @@ class QgsLayoutItemAbstractGuiMetadata
class QgsLayoutItemGuiGroup
{
%Docstring
Stores GUI metadata about a group of layout item classes.
QgsLayoutItemGuiGroup stores settings about groups of related layout item classes
which should be presented to users grouped together.
For instance, the various basic shape creation tools would use QgsLayoutItemGuiGroup
to display grouped within designer dialogs.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutitemguiregistry.h"
%End
public:
QgsLayoutItemGuiGroup( const QString &id = QString(), const QString &name = QString(), const QIcon &icon = QIcon() );
%Docstring
Constructor for QgsLayoutItemGuiGroup.
%End
QString id;
%Docstring
Unique (untranslated) group ID string.
%End
QString name;
%Docstring
Translated group name.
%End
QIcon icon;
%Docstring
Icon for group.
%End
};
class QgsLayoutItemGuiRegistry : QObject
{
%Docstring
@ -117,6 +167,25 @@ class QgsLayoutItemGuiRegistry : QObject
:rtype: bool
%End
bool addItemGroup( const QgsLayoutItemGuiGroup &group );
%Docstring
Registers a new item group with the registry. This must be done before calling
addLayoutItemGuiMetadata() for any item types associated with the group.
Returns true if group was added, or false if group could not be added (e.g. due to
duplicate id value).
.. seealso:: itemGroup()
:rtype: bool
%End
const QgsLayoutItemGuiGroup &itemGroup( const QString &id );
%Docstring
Returns a reference to the item group with matching ``id``.
.. seealso:: addItemGroup()
:rtype: QgsLayoutItemGuiGroup
%End
QWidget *createItemWidget( int type ) const /Factory/;
%Docstring
Creates a new instance of a layout item configuration widget for the specified item ``type``.

View File

@ -301,15 +301,65 @@ void QgsLayoutDesignerDialog::closeEvent( QCloseEvent * )
void QgsLayoutDesignerDialog::itemTypeAdded( int type )
{
QString name = QgsApplication::layoutItemRegistry()->itemMetadata( type )->visibleName();
QString groupId = QgsGui::layoutItemGuiRegistry()->itemMetadata( type )->groupId();
QToolButton *groupButton = nullptr;
QMenu *itemSubmenu = nullptr;
if ( !groupId.isEmpty() )
{
// find existing group toolbutton and submenu, or create new ones if this is the first time the group has been encountered
const QgsLayoutItemGuiGroup &group = QgsGui::layoutItemGuiRegistry()->itemGroup( groupId );
QIcon groupIcon = group.icon.isNull() ? QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicShape.svg" ) ) : group.icon;
QString groupText = tr( "Add %1" ).arg( group.name );
if ( mItemGroupToolButtons.contains( groupId ) )
{
groupButton = mItemGroupToolButtons.value( groupId );
}
else
{
QToolButton *groupToolButton = new QToolButton( mToolsToolbar );
groupToolButton->setIcon( groupIcon );
groupToolButton->setCheckable( true );
groupToolButton->setPopupMode( QToolButton::InstantPopup );
groupToolButton->setAutoRaise( true );
groupToolButton->setToolButtonStyle( Qt::ToolButtonIconOnly );
groupToolButton->setToolTip( groupText );
mToolsToolbar->addWidget( groupToolButton );
mItemGroupToolButtons.insert( groupId, groupToolButton );
groupButton = groupToolButton;
}
if ( mItemGroupSubmenus.contains( groupId ) )
{
itemSubmenu = mItemGroupSubmenus.value( groupId );
}
else
{
QMenu *groupSubmenu = mItemMenu->addMenu( groupText );
groupSubmenu->setIcon( groupIcon );
mItemMenu->addMenu( groupSubmenu );
mItemGroupSubmenus.insert( groupId, groupSubmenu );
itemSubmenu = groupSubmenu;
}
}
// 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( QgsGui::layoutItemGuiRegistry()->itemMetadata( type )->creationIcon() );
mToolsActionGroup->addAction( action );
mItemMenu->addAction( action );
mToolsToolbar->addAction( action );
if ( itemSubmenu )
itemSubmenu->addAction( action );
else
mItemMenu->addAction( action );
if ( groupButton )
groupButton->addAction( action );
else
mToolsToolbar->addAction( action );
connect( action, &QAction::triggered, this, [this, type]()
{
activateNewItemCreationTool( type );

View File

@ -19,6 +19,7 @@
#include "ui_qgslayoutdesignerbase.h"
#include "qgslayoutdesignerinterface.h"
#include <QToolButton>
class QgsLayoutDesignerDialog;
class QgsLayoutView;
@ -161,6 +162,9 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
QgsLayoutViewToolZoom *mZoomTool = nullptr;
QgsLayoutViewToolSelect *mSelectTool = nullptr;
QMap< QString, QToolButton * > mItemGroupToolButtons;
QMap< QString, QMenu * > mItemGroupSubmenus;
//! Save window state
void saveWindowState();

View File

@ -41,6 +41,8 @@ bool QgsLayoutItemGuiRegistry::populate()
if ( !mMetadata.isEmpty() )
return false;
addItemGroup( QgsLayoutItemGuiGroup( QStringLiteral( "shapes" ), tr( "Shape" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicShape.svg" ) ) ) );
auto createRubberBand = ( []( QgsLayoutView * view )->QgsLayoutViewRubberBand *
{
return new QgsLayoutViewRectangularRubberBand( view );
@ -55,9 +57,9 @@ bool QgsLayoutItemGuiRegistry::populate()
} );
addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( 101, QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddLabel.svg" ) ), nullptr, createRubberBand ) );
addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutRectangle, QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ), nullptr, createRubberBand ) );
addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutEllipse, QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicCircle.svg" ) ), nullptr, createEllipseBand ) );
addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutTriangle, QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicTriangle.svg" ) ), nullptr, createTriangleBand ) );
addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutRectangle, QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ), nullptr, createRubberBand, QStringLiteral( "shapes" ) ) );
addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutEllipse, QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicCircle.svg" ) ), nullptr, createEllipseBand, QStringLiteral( "shapes" ) ) );
addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutTriangle, QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicTriangle.svg" ) ), nullptr, createTriangleBand, QStringLiteral( "shapes" ) ) );
return true;
}
@ -76,6 +78,20 @@ bool QgsLayoutItemGuiRegistry::addLayoutItemGuiMetadata( QgsLayoutItemAbstractGu
return true;
}
bool QgsLayoutItemGuiRegistry::addItemGroup( const QgsLayoutItemGuiGroup &group )
{
if ( mItemGroups.contains( group.id ) )
return false;
mItemGroups.insert( group.id, group );
return true;
}
const QgsLayoutItemGuiGroup &QgsLayoutItemGuiRegistry::itemGroup( const QString &id )
{
return mItemGroups[ id ];
}
QWidget *QgsLayoutItemGuiRegistry::createItemWidget( int type ) const
{
if ( !mMetadata.contains( type ) )

View File

@ -47,9 +47,12 @@ class GUI_EXPORT QgsLayoutItemAbstractGuiMetadata
/**
* Constructor for QgsLayoutItemAbstractGuiMetadata with the specified class \a type.
*
* An optional \a groupId can be set, which allows grouping of related layout item classes. See QgsLayoutItemGuiMetadata for details.
*/
QgsLayoutItemAbstractGuiMetadata( int type )
QgsLayoutItemAbstractGuiMetadata( int type, const QString &groupId = QString() )
: mType( type )
, mGroupId( groupId )
{}
virtual ~QgsLayoutItemAbstractGuiMetadata() = default;
@ -59,6 +62,11 @@ class GUI_EXPORT QgsLayoutItemAbstractGuiMetadata
*/
int type() const { return mType; }
/**
* Returns the item group ID, if set.
*/
QString groupId() const { return mGroupId; }
/**
* Returns an icon representing creation of the layout item type.
*/
@ -78,6 +86,8 @@ class GUI_EXPORT QgsLayoutItemAbstractGuiMetadata
private:
int mType = -1;
QString mGroupId;
};
//! Layout item configuration widget creation function
@ -102,11 +112,13 @@ class GUI_EXPORT QgsLayoutItemGuiMetadata : public QgsLayoutItemAbstractGuiMetad
* Constructor for QgsLayoutItemGuiMetadata with the specified class \a type
* and \a creationIcon, and function pointers for the various
* configuration widget creation functions.
*
* An optional \a groupId can be set, which allows grouping of related layout item classes. See QgsLayoutItemGuiMetadata for details.
*/
QgsLayoutItemGuiMetadata( int type, const QIcon &creationIcon,
QgsLayoutItemWidgetFunc pfWidget = nullptr,
QgsLayoutItemRubberBandFunc pfRubberBand = nullptr )
: QgsLayoutItemAbstractGuiMetadata( type )
QgsLayoutItemRubberBandFunc pfRubberBand = nullptr, const QString &groupId = QString() )
: QgsLayoutItemAbstractGuiMetadata( type, groupId )
, mIcon( creationIcon )
, mWidgetFunc( pfWidget )
, mRubberBandFunc( pfRubberBand )
@ -149,6 +161,49 @@ class GUI_EXPORT QgsLayoutItemGuiMetadata : public QgsLayoutItemAbstractGuiMetad
#endif
/**
* \ingroup gui
* \brief Stores GUI metadata about a group of layout item classes.
*
* QgsLayoutItemGuiGroup stores settings about groups of related layout item classes
* which should be presented to users grouped together.
*
* For instance, the various basic shape creation tools would use QgsLayoutItemGuiGroup
* to display grouped within designer dialogs.
*
* \since QGIS 3.0
*/
class GUI_EXPORT QgsLayoutItemGuiGroup
{
public:
/**
* Constructor for QgsLayoutItemGuiGroup.
*/
QgsLayoutItemGuiGroup( const QString &id = QString(), const QString &name = QString(), const QIcon &icon = QIcon() )
: id( id )
, name( name )
, icon( icon )
{}
/**
* Unique (untranslated) group ID string.
*/
QString id;
/**
* Translated group name.
*/
QString name;
/**
* Icon for group.
*/
QIcon icon;
};
/**
* \ingroup core
* \class QgsLayoutItemGuiRegistry
@ -202,6 +257,23 @@ class GUI_EXPORT QgsLayoutItemGuiRegistry : public QObject
*/
bool addLayoutItemGuiMetadata( QgsLayoutItemAbstractGuiMetadata *metadata SIP_TRANSFER );
/**
* Registers a new item group with the registry. This must be done before calling
* addLayoutItemGuiMetadata() for any item types associated with the group.
*
* Returns true if group was added, or false if group could not be added (e.g. due to
* duplicate id value).
*
* \see itemGroup()
*/
bool addItemGroup( const QgsLayoutItemGuiGroup &group );
/**
* Returns a reference to the item group with matching \a id.
* \see addItemGroup()
*/
const QgsLayoutItemGuiGroup &itemGroup( const QString &id );
/**
* Creates a new instance of a layout item configuration widget for the specified item \a type.
*/
@ -233,6 +305,8 @@ class GUI_EXPORT QgsLayoutItemGuiRegistry : public QObject
QMap<int, QgsLayoutItemAbstractGuiMetadata *> mMetadata;
QMap< QString, QgsLayoutItemGuiGroup > mItemGroups;
};
#endif //QGSLAYOUTITEMGUIREGISTRY_H

View File

@ -300,6 +300,12 @@ void TestQgsLayoutView::guiRegistry()
QCOMPARE( band->view(), view );
delete band;
// groups
QVERIFY( registry.addItemGroup( QgsLayoutItemGuiGroup( QStringLiteral( "g1" ) ) ) );
QCOMPARE( registry.itemGroup( QStringLiteral( "g1" ) ).id, QStringLiteral( "g1" ) );
// can't add duplicate group
QVERIFY( !registry.addItemGroup( QgsLayoutItemGuiGroup( QStringLiteral( "g1" ) ) ) );
//test populate
QgsLayoutItemGuiRegistry reg2;
QVERIFY( reg2.itemTypes().isEmpty() );