Skip to content
Permalink
Browse files

Add method to specify item groups for item classes in QgsLayoutItemGu…

…iRegistry

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.
  • Loading branch information
nyalldawson committed Jul 18, 2017
1 parent de2626d commit 7f066672b3ea9982fc57e9f58d90f5231b75d383
@@ -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``.
@@ -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 );
@@ -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();

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

0 comments on commit 7f06667

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