mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-15 00:02:52 -04:00
[feature][layouts] Add menu entry to add dynamic text labels
easily to a layout The new "Add Item" -> "Dynamic Text" menu contains a bunch of preset handy dynamic text expressions which users can use to insert a label automatically containing the corresponding expression. E.g. Add Item -> Dynamic Text -> Layout Name will insert a label containing the expression [% @layout_name %]. This raises discoverability and user-friendliness of inserting dynamic labels
This commit is contained in:
parent
f81737c960
commit
ad944156c8
@ -188,6 +188,18 @@ QgsLayoutItemGuiRegistry is not usually directly created, but rather accessed th
|
||||
%Docstring
|
||||
Returns the metadata for the specified item ``metadataId``. Returns ``None`` if
|
||||
a corresponding ``metadataId`` was not found in the registry.
|
||||
%End
|
||||
|
||||
int metadataIdForItemType( int type ) const;
|
||||
%Docstring
|
||||
Returns the GUI item metadata ID which corresponds to the specified layout item ``type``.
|
||||
|
||||
In the case that multiple GUI metadata classes exist for a single layout item ``type`` then
|
||||
only the first encountered GUI metadata ID will be returned.
|
||||
|
||||
Returns -1 if no matching metadata is found in the GUI registry.
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
bool addLayoutItemGuiMetadata( QgsLayoutItemAbstractGuiMetadata *metadata /Transfer/ );
|
||||
@ -219,12 +231,15 @@ Returns a reference to the item group with matching ``id``.
|
||||
Creates a new instance of a layout item given the item metadata ``metadataId``, target ``layout``.
|
||||
%End
|
||||
|
||||
void newItemAddedToLayout( int metadataId, QgsLayoutItem *item );
|
||||
void newItemAddedToLayout( int metadataId, QgsLayoutItem *item, const QVariantMap &properties = QVariantMap() );
|
||||
%Docstring
|
||||
Called when a newly created item of the associated metadata ``metadataId`` has been added to a layout.
|
||||
|
||||
This is only called for additions which result from GUI operations - i.e. it is not
|
||||
called for items added from templates.
|
||||
|
||||
Since QGIS 3.18 the optional ``properties`` argument can be used to pass custom properties to the
|
||||
:py:func:`QgsLayoutItemGuiMetadata.newItemAddedToLayout()` function.
|
||||
%End
|
||||
|
||||
|
||||
|
@ -49,9 +49,32 @@ from :py:class:`QgsLayoutItemGuiRegistry`.
|
||||
|
||||
virtual void layoutReleaseEvent( QgsLayoutViewMouseEvent *event );
|
||||
|
||||
virtual void activate();
|
||||
|
||||
virtual void deactivate();
|
||||
|
||||
|
||||
QVariantMap customProperties() const;
|
||||
%Docstring
|
||||
Returns any custom properties set for the tool.
|
||||
|
||||
.. seealso:: :py:func:`setCustomProperties`
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
void setCustomProperties( const QVariantMap &properties );
|
||||
%Docstring
|
||||
Sets custom ``properties`` for the tool.
|
||||
|
||||
These properties are transient, and are cleared whenever the tool is activated. Callers must ensure
|
||||
that the properties are set only after the tool is activated.
|
||||
|
||||
.. seealso:: :py:func:`customProperties`
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
signals:
|
||||
|
||||
void createdItem();
|
||||
|
@ -73,6 +73,7 @@
|
||||
#include "qgsabstractvaliditycheck.h"
|
||||
#include "qgsvaliditycheckcontext.h"
|
||||
#include "qgsprojectviewsettings.h"
|
||||
#include "qgslayoutlabelwidget.h"
|
||||
#include "ui_defaults.h"
|
||||
|
||||
#include <QShortcut>
|
||||
@ -407,6 +408,23 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
|
||||
|
||||
connect( mActionClose, &QAction::triggered, this, &QWidget::close );
|
||||
|
||||
mDynamicTextMenu = new QMenu( tr( "Dynamic Text" ), this );
|
||||
|
||||
connect( mDynamicTextMenu, &QMenu::aboutToShow, this, [ = ]
|
||||
{
|
||||
mDynamicTextMenu->clear();
|
||||
// we need to rebuild this on each show, as the content varies depending on other available items...
|
||||
QgsLayoutLabelWidget::buildInsertDynamicTextMenu( mLayout, mDynamicTextMenu, [ = ]( const QString & expression )
|
||||
{
|
||||
activateNewItemCreationTool( QgsGui::layoutItemGuiRegistry()->metadataIdForItemType( QgsLayoutItemRegistry::LayoutLabel ), false );
|
||||
QVariantMap properties;
|
||||
properties.insert( QStringLiteral( "expression" ), expression );
|
||||
mAddItemTool->setCustomProperties( properties );
|
||||
} );
|
||||
} );
|
||||
|
||||
mItemMenu->addMenu( mDynamicTextMenu );
|
||||
|
||||
// populate with initial items...
|
||||
const QList< int > itemMetadataIds = QgsGui::layoutItemGuiRegistry()->itemMetadataIds();
|
||||
for ( int id : itemMetadataIds )
|
||||
|
@ -465,6 +465,8 @@ class QgsLayoutDesignerDialog: public QMainWindow, public Ui::QgsLayoutDesignerB
|
||||
QAction *mActionPaste = nullptr;
|
||||
QProgressBar *mStatusProgressBar = nullptr;
|
||||
|
||||
QMenu *mDynamicTextMenu = nullptr;
|
||||
|
||||
struct PanelStatus
|
||||
{
|
||||
PanelStatus( bool visible = true, bool active = false )
|
||||
|
@ -117,7 +117,7 @@ void QgsLayoutGuiUtils::registerGuiForKnownItemTypes( QgsMapCanvas *mapCanvas )
|
||||
{
|
||||
return new QgsLayoutMapWidget( qobject_cast< QgsLayoutItemMap * >( item ), mapCanvas );
|
||||
}, createRubberBand );
|
||||
mapItemMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item )
|
||||
mapItemMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item, const QVariantMap & )
|
||||
{
|
||||
QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap * >( item );
|
||||
Q_ASSERT( map );
|
||||
@ -176,12 +176,12 @@ void QgsLayoutGuiUtils::registerGuiForKnownItemTypes( QgsMapCanvas *mapCanvas )
|
||||
{
|
||||
return new QgsLayoutLabelWidget( qobject_cast< QgsLayoutItemLabel * >( item ) );
|
||||
}, createRubberBand );
|
||||
labelItemMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item )
|
||||
labelItemMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item, const QVariantMap & properties )
|
||||
{
|
||||
QgsLayoutItemLabel *label = qobject_cast< QgsLayoutItemLabel * >( item );
|
||||
Q_ASSERT( label );
|
||||
|
||||
label->setText( QObject::tr( "Lorem ipsum" ) );
|
||||
label->setText( properties.value( QStringLiteral( "expression" ) ).toString().isEmpty() ? QObject::tr( "Lorem ipsum" ) : QStringLiteral( "[% %1 %]" ).arg( properties.value( QStringLiteral( "expression" ) ).toString() ) );
|
||||
if ( QApplication::isRightToLeft() )
|
||||
{
|
||||
label->setHAlign( Qt::AlignRight );
|
||||
@ -205,7 +205,7 @@ void QgsLayoutGuiUtils::registerGuiForKnownItemTypes( QgsMapCanvas *mapCanvas )
|
||||
{
|
||||
return new QgsLayoutLegendWidget( qobject_cast< QgsLayoutItemLegend * >( item ), mapCanvas );
|
||||
}, createRubberBand );
|
||||
legendItemMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item )
|
||||
legendItemMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item, const QVariantMap & )
|
||||
{
|
||||
QgsLayoutItemLegend *legend = qobject_cast< QgsLayoutItemLegend * >( item );
|
||||
Q_ASSERT( legend );
|
||||
@ -246,7 +246,7 @@ void QgsLayoutGuiUtils::registerGuiForKnownItemTypes( QgsMapCanvas *mapCanvas )
|
||||
{
|
||||
return new QgsLayoutScaleBarWidget( qobject_cast< QgsLayoutItemScaleBar * >( item ) );
|
||||
}, createRubberBand );
|
||||
scalebarItemMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item )
|
||||
scalebarItemMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item, const QVariantMap & )
|
||||
{
|
||||
QgsLayoutItemScaleBar *scalebar = qobject_cast< QgsLayoutItemScaleBar * >( item );
|
||||
Q_ASSERT( scalebar );
|
||||
@ -294,7 +294,7 @@ void QgsLayoutGuiUtils::registerGuiForKnownItemTypes( QgsMapCanvas *mapCanvas )
|
||||
picture->setId( northArrowCount > 0 ? QObject::tr( "North Arrow %1" ).arg( northArrowCount + 1 ) : QObject::tr( "North Arrow" ) );
|
||||
return picture.release();
|
||||
} );
|
||||
northArrowMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item )
|
||||
northArrowMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item, const QVariantMap & )
|
||||
{
|
||||
QgsLayoutItemPicture *picture = qobject_cast< QgsLayoutItemPicture * >( item );
|
||||
Q_ASSERT( picture );
|
||||
|
@ -57,6 +57,16 @@ QgsLayoutItemAbstractGuiMetadata *QgsLayoutItemGuiRegistry::itemMetadata( int me
|
||||
return mMetadata.value( metadataId );
|
||||
}
|
||||
|
||||
int QgsLayoutItemGuiRegistry::metadataIdForItemType( int type ) const
|
||||
{
|
||||
for ( auto it = mMetadata.constBegin(); it != mMetadata.constEnd(); ++it )
|
||||
{
|
||||
if ( it.value()->type() == type )
|
||||
return it.key();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool QgsLayoutItemGuiRegistry::addLayoutItemGuiMetadata( QgsLayoutItemAbstractGuiMetadata *metadata )
|
||||
{
|
||||
if ( !metadata )
|
||||
@ -95,12 +105,19 @@ QgsLayoutItem *QgsLayoutItemGuiRegistry::createItem( int metadataId, QgsLayout *
|
||||
return QgsApplication::layoutItemRegistry()->createItem( type, layout );
|
||||
}
|
||||
|
||||
void QgsLayoutItemGuiRegistry::newItemAddedToLayout( int metadataId, QgsLayoutItem *item )
|
||||
void QgsLayoutItemGuiRegistry::newItemAddedToLayout( int metadataId, QgsLayoutItem *item, const QVariantMap &properties )
|
||||
{
|
||||
if ( !mMetadata.contains( metadataId ) )
|
||||
return;
|
||||
|
||||
mMetadata.value( metadataId )->newItemAddedToLayout( item );
|
||||
if ( QgsLayoutItemGuiMetadata *metadata = dynamic_cast<QgsLayoutItemGuiMetadata *>( mMetadata.value( metadataId ) ) )
|
||||
{
|
||||
metadata->newItemAddedToLayout( item, properties );
|
||||
}
|
||||
else
|
||||
{
|
||||
mMetadata.value( metadataId )->newItemAddedToLayout( item );
|
||||
}
|
||||
}
|
||||
|
||||
QgsLayoutItemBaseWidget *QgsLayoutItemGuiRegistry::createItemWidget( QgsLayoutItem *item ) const
|
||||
@ -153,5 +170,11 @@ QgsLayoutItem *QgsLayoutItemGuiMetadata::createItem( QgsLayout *layout )
|
||||
void QgsLayoutItemGuiMetadata::newItemAddedToLayout( QgsLayoutItem *item )
|
||||
{
|
||||
if ( mAddedToLayoutFunc )
|
||||
mAddedToLayoutFunc( item );
|
||||
mAddedToLayoutFunc( item, QVariantMap() );
|
||||
}
|
||||
|
||||
void QgsLayoutItemGuiMetadata::newItemAddedToLayout( QgsLayoutItem *item, const QVariantMap &properties )
|
||||
{
|
||||
if ( mAddedToLayoutFunc )
|
||||
mAddedToLayoutFunc( item, properties );
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ typedef std::function<QgsLayoutViewRubberBand *( QgsLayoutView * )> QgsLayoutIte
|
||||
typedef std::function<QAbstractGraphicsShapeItem *( QgsLayoutView * )> QgsLayoutNodeItemRubberBandFunc SIP_SKIP;
|
||||
|
||||
//! Layout item added to layout callback
|
||||
typedef std::function<void ( QgsLayoutItem * )> QgsLayoutItemAddedToLayoutFunc SIP_SKIP;
|
||||
typedef std::function<void ( QgsLayoutItem *, const QVariantMap & )> QgsLayoutItemAddedToLayoutFunc SIP_SKIP;
|
||||
|
||||
#ifndef SIP_RUN
|
||||
|
||||
@ -272,8 +272,10 @@ class GUI_EXPORT QgsLayoutItemGuiMetadata : public QgsLayoutItemAbstractGuiMetad
|
||||
QgsLayoutItemBaseWidget *createItemWidget( QgsLayoutItem *item ) override { return mWidgetFunc ? mWidgetFunc( item ) : nullptr; }
|
||||
QgsLayoutViewRubberBand *createRubberBand( QgsLayoutView *view ) override { return mRubberBandFunc ? mRubberBandFunc( view ) : nullptr; }
|
||||
QAbstractGraphicsShapeItem *createNodeRubberBand( QgsLayoutView *view ) override { return mNodeRubberBandFunc ? mNodeRubberBandFunc( view ) : nullptr; }
|
||||
|
||||
QgsLayoutItem *createItem( QgsLayout *layout ) override;
|
||||
void newItemAddedToLayout( QgsLayoutItem *item ) override;
|
||||
void newItemAddedToLayout( QgsLayoutItem *item, const QVariantMap &properties );
|
||||
|
||||
protected:
|
||||
QIcon mIcon;
|
||||
@ -370,6 +372,18 @@ class GUI_EXPORT QgsLayoutItemGuiRegistry : public QObject
|
||||
*/
|
||||
QgsLayoutItemAbstractGuiMetadata *itemMetadata( int metadataId ) const;
|
||||
|
||||
/**
|
||||
* Returns the GUI item metadata ID which corresponds to the specified layout item \a type.
|
||||
*
|
||||
* In the case that multiple GUI metadata classes exist for a single layout item \a type then
|
||||
* only the first encountered GUI metadata ID will be returned.
|
||||
*
|
||||
* Returns -1 if no matching metadata is found in the GUI registry.
|
||||
*
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
int metadataIdForItemType( int type ) const;
|
||||
|
||||
/**
|
||||
* Registers the gui metadata for a new layout item type. Takes ownership of the metadata instance.
|
||||
*/
|
||||
@ -417,8 +431,11 @@ class GUI_EXPORT QgsLayoutItemGuiRegistry : public QObject
|
||||
*
|
||||
* This is only called for additions which result from GUI operations - i.e. it is not
|
||||
* called for items added from templates.
|
||||
*
|
||||
* Since QGIS 3.18 the optional \a properties argument can be used to pass custom properties to the
|
||||
* QgsLayoutItemGuiMetadata::newItemAddedToLayout() function.
|
||||
*/
|
||||
void newItemAddedToLayout( int metadataId, QgsLayoutItem *item );
|
||||
void newItemAddedToLayout( int metadataId, QgsLayoutItem *item, const QVariantMap &properties = QVariantMap() );
|
||||
|
||||
/*
|
||||
* IMPORTANT: While it seems like /Factory/ would be the correct annotations here, that's not
|
||||
|
@ -20,10 +20,14 @@
|
||||
#include "qgslayout.h"
|
||||
#include "qgsexpressionbuilderdialog.h"
|
||||
#include "qgsguiutils.h"
|
||||
#include "qgslayoutitemmap.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
|
||||
#include <QColorDialog>
|
||||
#include <QFontDialog>
|
||||
#include <QWidget>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
|
||||
QgsLayoutLabelWidget::QgsLayoutLabelWidget( QgsLayoutItemLabel *label )
|
||||
: QgsLayoutItemBaseWidget( nullptr, label )
|
||||
@ -64,6 +68,22 @@ QgsLayoutLabelWidget::QgsLayoutLabelWidget( QgsLayoutItemLabel *label )
|
||||
|
||||
connect( mFontButton, &QgsFontButton::changed, this, &QgsLayoutLabelWidget::fontChanged );
|
||||
connect( mJustifyRadioButton, &QRadioButton::clicked, this, &QgsLayoutLabelWidget::justifyClicked );
|
||||
|
||||
mDynamicTextMenu = new QMenu( this );
|
||||
mDynamicTextButton->setMenu( mDynamicTextMenu );
|
||||
|
||||
connect( mDynamicTextMenu, &QMenu::aboutToShow, this, [ = ]
|
||||
{
|
||||
mDynamicTextMenu->clear();
|
||||
// we need to rebuild this on each show, as the content varies depending on other available items...
|
||||
buildInsertDynamicTextMenu( mLabel->layout(), mDynamicTextMenu, [ = ]( const QString & expression )
|
||||
{
|
||||
mLabel->beginCommand( tr( "Insert dynamic text" ) );
|
||||
mTextEdit->insertPlainText( "[%" + expression + "%]" );
|
||||
mLabel->endCommand();
|
||||
} );
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
void QgsLayoutLabelWidget::setMasterLayout( QgsMasterLayoutInterface *masterLayout )
|
||||
@ -72,6 +92,132 @@ void QgsLayoutLabelWidget::setMasterLayout( QgsMasterLayoutInterface *masterLayo
|
||||
mItemPropertiesWidget->setMasterLayout( masterLayout );
|
||||
}
|
||||
|
||||
void QgsLayoutLabelWidget::buildInsertDynamicTextMenu( QgsLayout *layout, QMenu *menu, const std::function<void ( const QString & )> &callback )
|
||||
{
|
||||
auto addExpression = [&callback]( QMenu * menu, const QString & name, const QString & expression )
|
||||
{
|
||||
QAction *action = new QAction( name, menu );
|
||||
connect( action, &QAction::triggered, action, [callback, expression]
|
||||
{
|
||||
callback( expression );
|
||||
} );
|
||||
menu->addAction( action );
|
||||
};
|
||||
|
||||
QMenu *dateMenu = new QMenu( tr( "Current Date" ), menu );
|
||||
for ( const std::pair< QString, QString > &expression :
|
||||
{
|
||||
std::make_pair( tr( "ISO Format (%1)" ).arg( QDateTime::currentDateTime().toString( QStringLiteral( "yyyy-MM-dd" ) ) ), QStringLiteral( "format_date(now(), 'yyyy-MM-dd')" ) ),
|
||||
std::make_pair( tr( "Day/Month/Year (%1)" ).arg( QDateTime::currentDateTime().toString( QStringLiteral( "dd/MM/yyyy" ) ) ), QStringLiteral( "format_date(now(), 'dd/MM/yyyy')" ) ),
|
||||
std::make_pair( tr( "Month/Day/Year (%1)" ).arg( QDateTime::currentDateTime().toString( QStringLiteral( "MM/dd/yyyy" ) ) ), QStringLiteral( "format_date(now(), 'MM/dd/yyyy')" ) ),
|
||||
} )
|
||||
{
|
||||
addExpression( dateMenu, expression.first, expression.second );
|
||||
}
|
||||
menu->addMenu( dateMenu );
|
||||
|
||||
QMenu *mapsMenu = new QMenu( tr( "Map Properties" ), menu );
|
||||
QList< QgsLayoutItemMap * > maps;
|
||||
layout->layoutItems( maps );
|
||||
for ( QgsLayoutItemMap *map : qgis::as_const( maps ) )
|
||||
{
|
||||
// these expressions require the map to have a non-empty ID set
|
||||
if ( map->id().isEmpty() )
|
||||
continue;
|
||||
|
||||
QMenu *mapMenu = new QMenu( map->displayName(), mapsMenu );
|
||||
for ( const std::pair< QString, QString > &expression :
|
||||
{
|
||||
std::make_pair( tr( "Scale (%1)" ).arg( map->scale() ), QStringLiteral( "item_variables('%1')['map_scale']" ).arg( map->id() ) ),
|
||||
std::make_pair( tr( "Rotation (%1)" ).arg( map->rotation() ), QStringLiteral( "item_variables('%1')['map_rotation']" ).arg( map->id() ) ),
|
||||
} )
|
||||
{
|
||||
addExpression( mapMenu, expression.first, expression.second );
|
||||
}
|
||||
mapMenu->addSeparator();
|
||||
for ( const std::pair< QString, QString > &expression :
|
||||
{
|
||||
std::make_pair( tr( "CRS Identifier (%1)" ).arg( map->crs().authid() ), QStringLiteral( "item_variables('%1')['map_crs']" ).arg( map->id() ) ),
|
||||
std::make_pair( tr( "CRS Name (%1)" ).arg( map->crs().description() ), QStringLiteral( "item_variables('%1')['map_crs_description']" ).arg( map->id() ) ),
|
||||
std::make_pair( tr( "Ellipsoid Name (%1)" ).arg( map->crs().ellipsoidAcronym() ), QStringLiteral( "item_variables('%1')['map_crs_ellipsoid']" ).arg( map->id() ) ),
|
||||
std::make_pair( tr( "Units (%1)" ).arg( QgsUnitTypes::toString( map->crs().mapUnits() ) ), QStringLiteral( "item_variables('%1')['map_units']" ).arg( map->id() ) ),
|
||||
} )
|
||||
{
|
||||
addExpression( mapMenu, expression.first, expression.second );
|
||||
}
|
||||
mapMenu->addSeparator();
|
||||
|
||||
const QgsRectangle mapExtent = map->extent();
|
||||
const QgsPointXY center = mapExtent.center();
|
||||
for ( const std::pair< QString, QString > &expression :
|
||||
{
|
||||
std::make_pair( tr( "Center (X) (%1)" ).arg( center.x() ), QStringLiteral( "x(item_variables('%1')['map_extent_center'])" ).arg( map->id() ) ),
|
||||
std::make_pair( tr( "Center (Y) (%1)" ).arg( center.y() ), QStringLiteral( "y(item_variables('%1')['map_extent_center'])" ).arg( map->id() ) ),
|
||||
std::make_pair( tr( "X Minimum (%1)" ).arg( mapExtent.xMinimum() ), QStringLiteral( "x_min(item_variables('%1')['map_extent'])" ).arg( map->id() ) ),
|
||||
std::make_pair( tr( "Y Minimum (%1)" ).arg( mapExtent.yMinimum() ), QStringLiteral( "y_min(item_variables('%1')['map_extent'])" ).arg( map->id() ) ),
|
||||
std::make_pair( tr( "X Maximum (%1)" ).arg( mapExtent.xMaximum() ), QStringLiteral( "x_max(item_variables('%1')['map_extent'])" ).arg( map->id() ) ),
|
||||
std::make_pair( tr( "Y Maximum (%1)" ).arg( mapExtent.yMaximum() ), QStringLiteral( "y_max(item_variables('%1')['map_extent'])" ).arg( map->id() ) ),
|
||||
} )
|
||||
{
|
||||
addExpression( mapMenu, expression.first, expression.second );
|
||||
}
|
||||
mapMenu->addSeparator();
|
||||
for ( const std::pair< QString, QString > &expression :
|
||||
{
|
||||
std::make_pair( tr( "Layer Credits" ), QStringLiteral( "array_to_string(map_credits('%1'))" ).arg( map->id() ) ),
|
||||
} )
|
||||
{
|
||||
addExpression( mapMenu, expression.first, expression.second );
|
||||
}
|
||||
mapsMenu->addMenu( mapMenu );
|
||||
}
|
||||
menu->addMenu( mapsMenu );
|
||||
menu->addSeparator();
|
||||
|
||||
if ( layout->reportContext().layer() )
|
||||
{
|
||||
const QgsFields fields = layout->reportContext().layer()->fields();
|
||||
|
||||
QMenu *fieldsMenu = new QMenu( tr( "Field" ), menu );
|
||||
for ( const QgsField &field : fields )
|
||||
{
|
||||
addExpression( fieldsMenu, field.displayName(), QStringLiteral( "\"%1\"" ).arg( field.name() ) );
|
||||
}
|
||||
|
||||
menu->addMenu( fieldsMenu );
|
||||
menu->addSeparator();
|
||||
}
|
||||
|
||||
for ( const std::pair< QString, QString > &expression :
|
||||
{
|
||||
std::make_pair( tr( "Layout Name" ), QStringLiteral( "@layout_name" ) ),
|
||||
std::make_pair( tr( "Layout Page Number" ), QStringLiteral( "@layout_page" ) ),
|
||||
std::make_pair( tr( "Layout Page Count" ), QStringLiteral( "@layout_numpages" ) )
|
||||
} )
|
||||
{
|
||||
addExpression( menu, expression.first, expression.second );
|
||||
}
|
||||
menu->addSeparator();
|
||||
for ( const std::pair< QString, QString > &expression :
|
||||
{
|
||||
std::make_pair( tr( "Project Author" ), QStringLiteral( "@project_author" ) ),
|
||||
std::make_pair( tr( "Project Title" ), QStringLiteral( "@project_title" ) ),
|
||||
std::make_pair( tr( "Project Path" ), QStringLiteral( "@project_path" ) )
|
||||
} )
|
||||
{
|
||||
addExpression( menu, expression.first, expression.second );
|
||||
}
|
||||
menu->addSeparator();
|
||||
for ( const std::pair< QString, QString > &expression :
|
||||
{
|
||||
std::make_pair( tr( "Current User Name" ), QStringLiteral( "@user_full_name" ) ),
|
||||
std::make_pair( tr( "Current User Account" ), QStringLiteral( "@user_account_name" ) )
|
||||
} )
|
||||
{
|
||||
addExpression( menu, expression.first, expression.second );
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsLayoutLabelWidget::setNewItem( QgsLayoutItem *item )
|
||||
{
|
||||
if ( item->type() != QgsLayoutItemRegistry::LayoutLabel )
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "ui_qgslayoutlabelwidgetbase.h"
|
||||
#include "qgslayoutitemwidget.h"
|
||||
#include "qgslayoutitemlabel.h"
|
||||
#include <functional>
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
@ -41,6 +42,22 @@ class GUI_EXPORT QgsLayoutLabelWidget: public QgsLayoutItemBaseWidget, private U
|
||||
explicit QgsLayoutLabelWidget( QgsLayoutItemLabel *label );
|
||||
void setMasterLayout( QgsMasterLayoutInterface *masterLayout ) override;
|
||||
|
||||
/**
|
||||
* Populates the specified \a menu with actions reflecting dynamic text expressions applicable for a \a layout.
|
||||
*
|
||||
* This includes dynamic text for expressions like:
|
||||
*
|
||||
* - current date
|
||||
* - total page count
|
||||
* - current page number
|
||||
* - etc
|
||||
*
|
||||
* The \a callback function will be called whenever one of the created actions is triggered.
|
||||
*
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
static void buildInsertDynamicTextMenu( QgsLayout *layout, QMenu *menu, const std::function< void( const QString &expression ) > &callback );
|
||||
|
||||
protected:
|
||||
|
||||
bool setNewItem( QgsLayoutItem *item ) override;
|
||||
@ -67,6 +84,8 @@ class GUI_EXPORT QgsLayoutLabelWidget: public QgsLayoutItemBaseWidget, private U
|
||||
|
||||
QgsLayoutItemPropertiesWidget *mItemPropertiesWidget = nullptr;
|
||||
|
||||
QMenu *mDynamicTextMenu = nullptr;
|
||||
|
||||
void blockAllSignals( bool block );
|
||||
};
|
||||
|
||||
|
@ -146,7 +146,7 @@ void QgsLayoutViewToolAddItem::layoutReleaseEvent( QgsLayoutViewMouseEvent *even
|
||||
settings.setEnumValue( QStringLiteral( "LayoutDesigner/lastSizeUnit" ), item->sizeWithUnits().units() );
|
||||
}
|
||||
|
||||
QgsGui::layoutItemGuiRegistry()->newItemAddedToLayout( mItemMetadataId, item );
|
||||
QgsGui::layoutItemGuiRegistry()->newItemAddedToLayout( mItemMetadataId, item, mCustomProperties );
|
||||
|
||||
// it's possible (in certain circumstances, e.g. when adding frame items) that this item
|
||||
// has already been added to the layout
|
||||
@ -158,6 +158,12 @@ void QgsLayoutViewToolAddItem::layoutReleaseEvent( QgsLayoutViewMouseEvent *even
|
||||
emit createdItem();
|
||||
}
|
||||
|
||||
void QgsLayoutViewToolAddItem::activate()
|
||||
{
|
||||
QgsLayoutViewTool::activate();
|
||||
mCustomProperties.clear();
|
||||
}
|
||||
|
||||
void QgsLayoutViewToolAddItem::deactivate()
|
||||
{
|
||||
if ( mDrawing )
|
||||
@ -170,6 +176,16 @@ void QgsLayoutViewToolAddItem::deactivate()
|
||||
QgsLayoutViewTool::deactivate();
|
||||
}
|
||||
|
||||
QVariantMap QgsLayoutViewToolAddItem::customProperties() const
|
||||
{
|
||||
return mCustomProperties;
|
||||
}
|
||||
|
||||
void QgsLayoutViewToolAddItem::setCustomProperties( const QVariantMap &customProperties )
|
||||
{
|
||||
mCustomProperties = customProperties;
|
||||
}
|
||||
|
||||
int QgsLayoutViewToolAddItem::itemMetadataId() const
|
||||
{
|
||||
return mItemMetadataId;
|
||||
|
@ -56,8 +56,28 @@ class GUI_EXPORT QgsLayoutViewToolAddItem : public QgsLayoutViewTool
|
||||
void layoutPressEvent( QgsLayoutViewMouseEvent *event ) override;
|
||||
void layoutMoveEvent( QgsLayoutViewMouseEvent *event ) override;
|
||||
void layoutReleaseEvent( QgsLayoutViewMouseEvent *event ) override;
|
||||
void activate() override;
|
||||
void deactivate() override;
|
||||
|
||||
/**
|
||||
* Returns any custom properties set for the tool.
|
||||
*
|
||||
*\see setCustomProperties()
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
QVariantMap customProperties() const;
|
||||
|
||||
/**
|
||||
* Sets custom \a properties for the tool.
|
||||
*
|
||||
* These properties are transient, and are cleared whenever the tool is activated. Callers must ensure
|
||||
* that the properties are set only after the tool is activated.
|
||||
*
|
||||
*\see customProperties()
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
void setCustomProperties( const QVariantMap &properties );
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
@ -83,6 +103,8 @@ class GUI_EXPORT QgsLayoutViewToolAddItem : public QgsLayoutViewTool
|
||||
//! Start of rubber band creation
|
||||
QPointF mRubberBandStartPos;
|
||||
|
||||
QVariantMap mCustomProperties;
|
||||
|
||||
};
|
||||
|
||||
#endif // QGSLAYOUTVIEWTOOLADDITEM_H
|
||||
|
@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>304</width>
|
||||
<width>360</width>
|
||||
<height>705</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -61,8 +61,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>446</width>
|
||||
<height>665</height>
|
||||
<width>358</width>
|
||||
<height>680</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="mainLayout">
|
||||
@ -84,27 +84,49 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QPlainTextEdit" name="mTextEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
<item row="2" column="1">
|
||||
<widget class="QToolButton" name="mDynamicTextButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Dynamic Text</string>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::InstantPopup</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QToolButton" name="mInsertExpressionButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Insert/Edit Expression…</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="mHtmlCheckBox">
|
||||
<property name="text">
|
||||
<string>Render as HTML</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QPushButton" name="mInsertExpressionButton">
|
||||
<property name="text">
|
||||
<string>Insert or Edit an Expression…</string>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QPlainTextEdit" name="mTextEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -401,7 +423,7 @@
|
||||
<resources/>
|
||||
<connections/>
|
||||
<buttongroups>
|
||||
<buttongroup name="buttonGroup"/>
|
||||
<buttongroup name="buttonGroup_2"/>
|
||||
<buttongroup name="buttonGroup"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
@ -264,6 +264,7 @@ void TestQgsLayoutView::guiRegistry()
|
||||
// empty registry
|
||||
QVERIFY( !registry.itemMetadata( -1 ) );
|
||||
QVERIFY( registry.itemMetadataIds().isEmpty() );
|
||||
QCOMPARE( registry.metadataIdForItemType( 0 ), -1 );
|
||||
QVERIFY( !registry.createItemWidget( nullptr ) );
|
||||
QVERIFY( !registry.createItemWidget( nullptr ) );
|
||||
std::unique_ptr< TestItem > testItem = qgis::make_unique< TestItem >( nullptr );
|
||||
@ -287,6 +288,7 @@ void TestQgsLayoutView::guiRegistry()
|
||||
QCOMPARE( spyTypeAdded.count(), 1 );
|
||||
int uuid = registry.itemMetadataIds().value( 0 );
|
||||
QCOMPARE( spyTypeAdded.value( 0 ).at( 0 ).toInt(), uuid );
|
||||
QCOMPARE( registry.metadataIdForItemType( QgsLayoutItemRegistry::LayoutItem + 101 ), uuid );
|
||||
|
||||
// duplicate type id is allowed
|
||||
metadata = new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutItem + 101, QStringLiteral( "mytype" ), QIcon(), createWidget, createRubberBand );
|
||||
@ -295,6 +297,7 @@ void TestQgsLayoutView::guiRegistry()
|
||||
//retrieve metadata
|
||||
QVERIFY( !registry.itemMetadata( -1 ) );
|
||||
QCOMPARE( registry.itemMetadataIds().count(), 2 );
|
||||
QCOMPARE( registry.metadataIdForItemType( QgsLayoutItemRegistry::LayoutItem + 101 ), uuid );
|
||||
|
||||
QVERIFY( registry.itemMetadata( uuid ) );
|
||||
QCOMPARE( registry.itemMetadata( uuid )->visibleName(), QStringLiteral( "mytype" ) );
|
||||
|
Loading…
x
Reference in New Issue
Block a user