Skip to content

Commit

Permalink
Add method to specify item groups for item classes in QgsLayoutItemGu…
Browse files Browse the repository at this point in the history
…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 7f06667
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 9 deletions.
71 changes: 70 additions & 1 deletion python/gui/layout/qgslayoutitemguiregistry.sip
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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``.
Expand Down
54 changes: 52 additions & 2 deletions src/app/layout/qgslayoutdesignerdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down
4 changes: 4 additions & 0 deletions src/app/layout/qgslayoutdesignerdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "ui_qgslayoutdesignerbase.h"
#include "qgslayoutdesignerinterface.h"
#include <QToolButton>

class QgsLayoutDesignerDialog;
class QgsLayoutView;
Expand Down Expand Up @@ -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();

Expand Down
22 changes: 19 additions & 3 deletions src/gui/layout/qgslayoutitemguiregistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand All @@ -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;
}

Expand All @@ -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 ) )
Expand Down
80 changes: 77 additions & 3 deletions src/gui/layout/qgslayoutitemguiregistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
*/
Expand All @@ -78,6 +86,8 @@ class GUI_EXPORT QgsLayoutItemAbstractGuiMetadata
private:

int mType = -1;
QString mGroupId;

};

//! Layout item configuration widget creation function
Expand All @@ -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 )
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -233,6 +305,8 @@ class GUI_EXPORT QgsLayoutItemGuiRegistry : public QObject

QMap<int, QgsLayoutItemAbstractGuiMetadata *> mMetadata;

QMap< QString, QgsLayoutItemGuiGroup > mItemGroups;

};

#endif //QGSLAYOUTITEMGUIREGISTRY_H
Expand Down
6 changes: 6 additions & 0 deletions tests/src/gui/testqgslayoutview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() );
Expand Down

0 comments on commit 7f06667

Please sign in to comment.