mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
New class QgsLayoutGuideCollection for storing sets of layout snap guides
The class is a QAbstractListModel subclass, making it easy for creation of different views showing the guides in a layout. Additionally, a QSortFilterProxyModel (QgsLayoutGuideProxyModel) has been created to filter QgsLayoutGuideCollection to guides with matching page numbers and orientations.
This commit is contained in:
parent
fa5eb4e5ad
commit
f5126b0abd
@ -159,6 +159,13 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator
|
|||||||
%End
|
%End
|
||||||
|
|
||||||
|
|
||||||
|
QgsLayoutGuideCollection &guides();
|
||||||
|
%Docstring
|
||||||
|
Returns a reference to the layout's guide collection, which manages page snap guides.
|
||||||
|
:rtype: QgsLayoutGuideCollection
|
||||||
|
%End
|
||||||
|
|
||||||
|
|
||||||
virtual QgsExpressionContext createExpressionContext() const;
|
virtual QgsExpressionContext createExpressionContext() const;
|
||||||
|
|
||||||
%Docstring
|
%Docstring
|
||||||
|
@ -26,7 +26,34 @@ class QgsLayoutGuide : QObject
|
|||||||
Vertical,
|
Vertical,
|
||||||
};
|
};
|
||||||
|
|
||||||
QgsLayoutGuide( QgsLayout *layout, Orientation orientation, const QgsLayoutMeasurement &position );
|
QgsLayoutGuide( Orientation orientation, const QgsLayoutMeasurement &position );
|
||||||
|
%Docstring
|
||||||
|
Constructor for a new guide with the specified ``orientation`` and
|
||||||
|
initial ``position``.
|
||||||
|
|
||||||
|
A layout must be set by calling setLayout() before the guide can be used.
|
||||||
|
Adding the guide to a QgsLayoutGuideCollection will automatically set
|
||||||
|
the corresponding layout for you.
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsLayout *layout() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the layout the guide belongs to.
|
||||||
|
.. seealso:: setLayout()
|
||||||
|
:rtype: QgsLayout
|
||||||
|
%End
|
||||||
|
|
||||||
|
void setLayout( QgsLayout *layout );
|
||||||
|
%Docstring
|
||||||
|
Sets the ``layout`` the guide belongs to.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Adding the guide to a QgsLayoutGuideCollection will automatically set
|
||||||
|
the corresponding layout for you.
|
||||||
|
|
||||||
|
.. seealso:: layout()
|
||||||
|
%End
|
||||||
|
|
||||||
Orientation orientation() const;
|
Orientation orientation() const;
|
||||||
%Docstring
|
%Docstring
|
||||||
@ -85,9 +112,103 @@ class QgsLayoutGuide : QObject
|
|||||||
:rtype: QGraphicsLineItem
|
:rtype: QGraphicsLineItem
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
double layoutPosition() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the guide's position in absolute layout units.
|
||||||
|
:rtype: float
|
||||||
|
%End
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void positionChanged();
|
||||||
|
%Docstring
|
||||||
|
Emitted when the guide's position is changed.
|
||||||
|
%End
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class QgsLayoutGuideCollection : QAbstractListModel
|
||||||
|
{
|
||||||
|
%Docstring
|
||||||
|
Stores and manages the snap guides used by a layout.
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
%End
|
||||||
|
|
||||||
|
%TypeHeaderCode
|
||||||
|
#include "qgslayoutguidecollection.h"
|
||||||
|
%End
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Roles
|
||||||
|
{
|
||||||
|
OrientationRole,
|
||||||
|
PositionRole,
|
||||||
|
UnitsRole,
|
||||||
|
PageRole,
|
||||||
|
};
|
||||||
|
|
||||||
|
QgsLayoutGuideCollection( QgsLayout *layout );
|
||||||
|
%Docstring
|
||||||
|
Constructor for QgsLayoutGuideCollection belonging to the specified layout.
|
||||||
|
%End
|
||||||
|
~QgsLayoutGuideCollection();
|
||||||
|
|
||||||
|
virtual int rowCount( const QModelIndex & ) const;
|
||||||
|
|
||||||
|
virtual QVariant data( const QModelIndex &index, int role ) const;
|
||||||
|
|
||||||
|
virtual bool setData( const QModelIndex &index, const QVariant &value, int role );
|
||||||
|
|
||||||
|
virtual Qt::ItemFlags flags( const QModelIndex &index ) const;
|
||||||
|
|
||||||
|
|
||||||
|
void addGuide( QgsLayoutGuide *guide /Transfer/ );
|
||||||
|
%Docstring
|
||||||
|
Adds a ``guide`` to the collection. Ownership of the guide is transferred to the
|
||||||
|
collection, and the guide will automatically have the correct layout
|
||||||
|
set.
|
||||||
|
%End
|
||||||
|
|
||||||
|
void update();
|
||||||
|
%Docstring
|
||||||
|
Updates the position (and visibility) of all guide line items.
|
||||||
|
%End
|
||||||
|
|
||||||
|
QList< QgsLayoutGuide * > guides( QgsLayoutGuide::Orientation orientation );
|
||||||
|
%Docstring
|
||||||
|
Returns the list of guides contained in the collection with the specified
|
||||||
|
``orientation``.
|
||||||
|
:rtype: list of QgsLayoutGuide
|
||||||
|
%End
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class QgsLayoutGuideProxyModel : QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
%Docstring
|
||||||
|
Filters QgsLayoutGuideCollection models to guides of a single orientation (horizontal or vertical).
|
||||||
|
.. versionadded:: 3.0
|
||||||
|
%End
|
||||||
|
|
||||||
|
%TypeHeaderCode
|
||||||
|
#include "qgslayoutguidecollection.h"
|
||||||
|
%End
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit QgsLayoutGuideProxyModel( QObject *parent /TransferThis/, QgsLayoutGuide::Orientation orientation, int page );
|
||||||
|
%Docstring
|
||||||
|
Constructor for QgsLayoutGuideProxyModel, filtered to guides of the specified ``orientation`` and ``page`` only.
|
||||||
|
|
||||||
|
Page numbers begin at 0.
|
||||||
|
%End
|
||||||
|
|
||||||
|
virtual bool filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const;
|
||||||
|
|
||||||
|
virtual bool lessThan( const QModelIndex &left, const QModelIndex &right ) const;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* This file has been generated automatically from *
|
* This file has been generated automatically from *
|
||||||
|
@ -16,11 +16,13 @@
|
|||||||
|
|
||||||
#include "qgslayout.h"
|
#include "qgslayout.h"
|
||||||
#include "qgslayoutpagecollection.h"
|
#include "qgslayoutpagecollection.h"
|
||||||
|
#include "qgslayoutguidecollection.h"
|
||||||
|
|
||||||
QgsLayout::QgsLayout( QgsProject *project )
|
QgsLayout::QgsLayout( QgsProject *project )
|
||||||
: QGraphicsScene()
|
: QGraphicsScene()
|
||||||
, mProject( project )
|
, mProject( project )
|
||||||
, mSnapper( QgsLayoutSnapper( this ) )
|
, mSnapper( QgsLayoutSnapper( this ) )
|
||||||
|
, mGuideCollection( new QgsLayoutGuideCollection( this ) )
|
||||||
, mPageCollection( new QgsLayoutPageCollection( this ) )
|
, mPageCollection( new QgsLayoutPageCollection( this ) )
|
||||||
{
|
{
|
||||||
// just to make sure - this should be the default, but maybe it'll change in some future Qt version...
|
// just to make sure - this should be the default, but maybe it'll change in some future Qt version...
|
||||||
@ -70,6 +72,16 @@ QgsLayoutPoint QgsLayout::convertFromLayoutUnits( const QPointF &point, const Qg
|
|||||||
return mContext.measurementConverter().convert( QgsLayoutPoint( point.x(), point.y(), mUnits ), unit );
|
return mContext.measurementConverter().convert( QgsLayoutPoint( point.x(), point.y(), mUnits ), unit );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsLayoutGuideCollection &QgsLayout::guides()
|
||||||
|
{
|
||||||
|
return *mGuideCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QgsLayoutGuideCollection &QgsLayout::guides() const
|
||||||
|
{
|
||||||
|
return *mGuideCollection;
|
||||||
|
}
|
||||||
|
|
||||||
QgsExpressionContext QgsLayout::createExpressionContext() const
|
QgsExpressionContext QgsLayout::createExpressionContext() const
|
||||||
{
|
{
|
||||||
QgsExpressionContext context = QgsExpressionContext();
|
QgsExpressionContext context = QgsExpressionContext();
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "qgsexpressioncontextgenerator.h"
|
#include "qgsexpressioncontextgenerator.h"
|
||||||
#include "qgslayoutpagecollection.h"
|
#include "qgslayoutpagecollection.h"
|
||||||
#include "qgslayoutgridsettings.h"
|
#include "qgslayoutgridsettings.h"
|
||||||
|
#include "qgslayoutguidecollection.h"
|
||||||
|
|
||||||
class QgsLayoutItemMap;
|
class QgsLayoutItemMap;
|
||||||
|
|
||||||
@ -182,6 +183,16 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
|
|||||||
*/
|
*/
|
||||||
SIP_SKIP const QgsLayoutGridSettings &gridSettings() const { return mGridSettings; }
|
SIP_SKIP const QgsLayoutGridSettings &gridSettings() const { return mGridSettings; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the layout's guide collection, which manages page snap guides.
|
||||||
|
*/
|
||||||
|
QgsLayoutGuideCollection &guides();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the layout's guide collection, which manages page snap guides.
|
||||||
|
*/
|
||||||
|
SIP_SKIP const QgsLayoutGuideCollection &guides() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression context relating to the layout's current state. The context includes
|
* Creates an expression context relating to the layout's current state. The context includes
|
||||||
* scopes for global, project, layout and layout context properties.
|
* scopes for global, project, layout and layout context properties.
|
||||||
@ -292,6 +303,7 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
|
|||||||
QgsLayoutContext mContext;
|
QgsLayoutContext mContext;
|
||||||
QgsLayoutSnapper mSnapper;
|
QgsLayoutSnapper mSnapper;
|
||||||
QgsLayoutGridSettings mGridSettings;
|
QgsLayoutGridSettings mGridSettings;
|
||||||
|
std::unique_ptr< QgsLayoutGuideCollection > mGuideCollection;
|
||||||
|
|
||||||
std::unique_ptr< QgsLayoutPageCollection > mPageCollection;
|
std::unique_ptr< QgsLayoutPageCollection > mPageCollection;
|
||||||
|
|
||||||
|
@ -23,17 +23,14 @@
|
|||||||
// QgsLayoutGuide
|
// QgsLayoutGuide
|
||||||
//
|
//
|
||||||
|
|
||||||
QgsLayoutGuide::QgsLayoutGuide( QgsLayout *layout, Orientation orientation, const QgsLayoutMeasurement &position )
|
QgsLayoutGuide::QgsLayoutGuide( Orientation orientation, const QgsLayoutMeasurement &position )
|
||||||
: QObject( layout )
|
: QObject( nullptr )
|
||||||
, mOrientation( orientation )
|
, mOrientation( orientation )
|
||||||
, mPosition( position )
|
, mPosition( position )
|
||||||
, mLayout( layout )
|
|
||||||
, mLineItem( new QGraphicsLineItem() )
|
, mLineItem( new QGraphicsLineItem() )
|
||||||
{
|
{
|
||||||
mLineItem->hide();
|
mLineItem->hide();
|
||||||
mLineItem->setZValue( QgsLayout::ZGuide );
|
mLineItem->setZValue( QgsLayout::ZGuide );
|
||||||
mLayout->addItem( mLineItem.get() );
|
|
||||||
|
|
||||||
QPen linePen( Qt::SolidLine );
|
QPen linePen( Qt::SolidLine );
|
||||||
linePen.setColor( Qt::red );
|
linePen.setColor( Qt::red );
|
||||||
// use a pen width of 0, since this activates a cosmetic pen
|
// use a pen width of 0, since this activates a cosmetic pen
|
||||||
@ -67,6 +64,9 @@ void QgsLayoutGuide::setPage( int page )
|
|||||||
|
|
||||||
void QgsLayoutGuide::update()
|
void QgsLayoutGuide::update()
|
||||||
{
|
{
|
||||||
|
if ( !mLayout )
|
||||||
|
return;
|
||||||
|
|
||||||
// first find matching page
|
// first find matching page
|
||||||
if ( mPage >= mLayout->pageCollection()->pageCount() )
|
if ( mPage >= mLayout->pageCollection()->pageCount() )
|
||||||
{
|
{
|
||||||
@ -125,7 +125,181 @@ double QgsLayoutGuide::layoutPosition() const
|
|||||||
return -999; // avoid warning
|
return -999; // avoid warning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsLayout *QgsLayoutGuide::layout() const
|
||||||
|
{
|
||||||
|
return mLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLayoutGuide::setLayout( QgsLayout *layout )
|
||||||
|
{
|
||||||
|
mLayout = layout;
|
||||||
|
mLayout->addItem( mLineItem.get() );
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
QgsLayoutGuide::Orientation QgsLayoutGuide::orientation() const
|
QgsLayoutGuide::Orientation QgsLayoutGuide::orientation() const
|
||||||
{
|
{
|
||||||
return mOrientation;
|
return mOrientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// QgsLayoutGuideCollection
|
||||||
|
//
|
||||||
|
|
||||||
|
QgsLayoutGuideCollection::QgsLayoutGuideCollection( QgsLayout *layout )
|
||||||
|
: QAbstractListModel( layout )
|
||||||
|
, mLayout( layout )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsLayoutGuideCollection::~QgsLayoutGuideCollection()
|
||||||
|
{
|
||||||
|
qDeleteAll( mGuides );
|
||||||
|
}
|
||||||
|
|
||||||
|
int QgsLayoutGuideCollection::rowCount( const QModelIndex & ) const
|
||||||
|
{
|
||||||
|
return mGuides.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant QgsLayoutGuideCollection::data( const QModelIndex &index, int role ) const
|
||||||
|
{
|
||||||
|
if ( !index.isValid() )
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if ( index.row() >= mGuides.count() || index.row() < 0 )
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
QgsLayoutGuide *guide = mGuides.at( index.row() );
|
||||||
|
switch ( role )
|
||||||
|
{
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
case Qt::EditRole:
|
||||||
|
{
|
||||||
|
return guide->position().length();
|
||||||
|
}
|
||||||
|
|
||||||
|
case Qt::TextAlignmentRole:
|
||||||
|
return QVariant( Qt::AlignRight | Qt::AlignVCenter );
|
||||||
|
|
||||||
|
case OrientationRole:
|
||||||
|
return guide->orientation();
|
||||||
|
|
||||||
|
case PositionRole:
|
||||||
|
return guide->position().length();
|
||||||
|
|
||||||
|
case UnitsRole:
|
||||||
|
return guide->position().units();
|
||||||
|
|
||||||
|
case PageRole:
|
||||||
|
return guide->page();
|
||||||
|
|
||||||
|
case LayoutPositionRole:
|
||||||
|
return guide->layoutPosition();
|
||||||
|
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsLayoutGuideCollection::setData( const QModelIndex &index, const QVariant &value, int role )
|
||||||
|
{
|
||||||
|
if ( !index.isValid() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( index.row() >= mGuides.count() || index.row() < 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QgsLayoutGuide *guide = mGuides.at( index.row() );
|
||||||
|
|
||||||
|
if ( role == Qt::EditRole )
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
double newPos = value.toDouble( &ok );
|
||||||
|
if ( !ok )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QgsLayoutMeasurement m = guide->position();
|
||||||
|
m.setLength( newPos );
|
||||||
|
guide->setPosition( m );
|
||||||
|
guide->update();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags QgsLayoutGuideCollection::flags( const QModelIndex &index ) const
|
||||||
|
{
|
||||||
|
if ( !index.isValid() )
|
||||||
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||||
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLayoutGuideCollection::addGuide( QgsLayoutGuide *guide )
|
||||||
|
{
|
||||||
|
guide->setLayout( mLayout );
|
||||||
|
|
||||||
|
beginInsertRows( QModelIndex(), mGuides.count(), mGuides.count() );
|
||||||
|
mGuides.append( guide );
|
||||||
|
endInsertRows();
|
||||||
|
|
||||||
|
QModelIndex index = createIndex( mGuides.length() - 1, 0 );
|
||||||
|
connect( guide, &QgsLayoutGuide::positionChanged, this, [ this, index ]
|
||||||
|
{
|
||||||
|
emit dataChanged( index, index );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLayoutGuideCollection::update()
|
||||||
|
{
|
||||||
|
Q_FOREACH ( QgsLayoutGuide *guide, mGuides )
|
||||||
|
{
|
||||||
|
guide->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QgsLayoutGuide *> QgsLayoutGuideCollection::guides( QgsLayoutGuide::Orientation orientation )
|
||||||
|
{
|
||||||
|
QList<QgsLayoutGuide *> res;
|
||||||
|
Q_FOREACH ( QgsLayoutGuide *guide, mGuides )
|
||||||
|
{
|
||||||
|
if ( guide->orientation() == orientation && guide->item()->isVisible() )
|
||||||
|
res << guide;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// QgsLayoutGuideProxyModel
|
||||||
|
//
|
||||||
|
|
||||||
|
QgsLayoutGuideProxyModel::QgsLayoutGuideProxyModel( QObject *parent, QgsLayoutGuide::Orientation orientation, int page )
|
||||||
|
: QSortFilterProxyModel( parent )
|
||||||
|
, mOrientation( orientation )
|
||||||
|
, mPage( page )
|
||||||
|
{
|
||||||
|
setDynamicSortFilter( true );
|
||||||
|
sort( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsLayoutGuideProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
|
||||||
|
{
|
||||||
|
QModelIndex index = sourceModel()->index( source_row, 0, source_parent );
|
||||||
|
QgsLayoutGuide::Orientation orientation = static_cast< QgsLayoutGuide::Orientation>( sourceModel()->data( index, QgsLayoutGuideCollection::OrientationRole ).toInt() );
|
||||||
|
if ( orientation != mOrientation )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int page = sourceModel()->data( index, QgsLayoutGuideCollection::PageRole ).toInt();
|
||||||
|
return page == mPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsLayoutGuideProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
|
||||||
|
{
|
||||||
|
double leftPos = sourceModel()->data( left, QgsLayoutGuideCollection::LayoutPositionRole ).toDouble();
|
||||||
|
double rightPos = sourceModel()->data( right, QgsLayoutGuideCollection::LayoutPositionRole ).toDouble();
|
||||||
|
return leftPos < rightPos;
|
||||||
|
}
|
||||||
|
@ -20,10 +20,12 @@
|
|||||||
#include "qgslayoutmeasurement.h"
|
#include "qgslayoutmeasurement.h"
|
||||||
#include "qgslayoutpoint.h"
|
#include "qgslayoutpoint.h"
|
||||||
#include <QPen>
|
#include <QPen>
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
#include <QGraphicsLineItem>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class QgsLayout;
|
class QgsLayout;
|
||||||
class QGraphicsLineItem;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \ingroup core
|
* \ingroup core
|
||||||
@ -45,7 +47,31 @@ class CORE_EXPORT QgsLayoutGuide : public QObject
|
|||||||
Vertical, //!< Vertical guide
|
Vertical, //!< Vertical guide
|
||||||
};
|
};
|
||||||
|
|
||||||
QgsLayoutGuide( QgsLayout *layout, Orientation orientation, const QgsLayoutMeasurement &position );
|
/**
|
||||||
|
* Constructor for a new guide with the specified \a orientation and
|
||||||
|
* initial \a position.
|
||||||
|
*
|
||||||
|
* A layout must be set by calling setLayout() before the guide can be used.
|
||||||
|
* Adding the guide to a QgsLayoutGuideCollection will automatically set
|
||||||
|
* the corresponding layout for you.
|
||||||
|
*/
|
||||||
|
QgsLayoutGuide( Orientation orientation, const QgsLayoutMeasurement &position );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the layout the guide belongs to.
|
||||||
|
* \see setLayout()
|
||||||
|
*/
|
||||||
|
QgsLayout *layout() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the \a layout the guide belongs to.
|
||||||
|
*
|
||||||
|
* \note Adding the guide to a QgsLayoutGuideCollection will automatically set
|
||||||
|
* the corresponding layout for you.
|
||||||
|
*
|
||||||
|
* \see layout()
|
||||||
|
*/
|
||||||
|
void setLayout( QgsLayout *layout );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the guide's orientation.
|
* Returns the guide's orientation.
|
||||||
@ -125,9 +151,96 @@ class CORE_EXPORT QgsLayoutGuide : public QObject
|
|||||||
QgsLayout *mLayout = nullptr;
|
QgsLayout *mLayout = nullptr;
|
||||||
|
|
||||||
//! Line item used in scene for guide
|
//! Line item used in scene for guide
|
||||||
std::shared_ptr< QGraphicsLineItem > mLineItem;
|
std::unique_ptr< QGraphicsLineItem > mLineItem;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \ingroup core
|
||||||
|
* \class QgsLayoutGuideCollection
|
||||||
|
* \brief Stores and manages the snap guides used by a layout.
|
||||||
|
* \since QGIS 3.0
|
||||||
|
*/
|
||||||
|
class CORE_EXPORT QgsLayoutGuideCollection : public QAbstractListModel
|
||||||
|
{
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! Model roles
|
||||||
|
enum Roles
|
||||||
|
{
|
||||||
|
OrientationRole = Qt::UserRole, //!< Guide orientation role
|
||||||
|
PositionRole, //!< Guide position role
|
||||||
|
UnitsRole, //!< Guide position units role
|
||||||
|
PageRole, //!< Guide page role
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for QgsLayoutGuideCollection belonging to the specified layout.
|
||||||
|
*/
|
||||||
|
QgsLayoutGuideCollection( QgsLayout *layout );
|
||||||
|
~QgsLayoutGuideCollection();
|
||||||
|
|
||||||
|
int rowCount( const QModelIndex & ) const override;
|
||||||
|
QVariant data( const QModelIndex &index, int role ) const override;
|
||||||
|
bool setData( const QModelIndex &index, const QVariant &value, int role ) override;
|
||||||
|
Qt::ItemFlags flags( const QModelIndex &index ) const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a \a guide to the collection. Ownership of the guide is transferred to the
|
||||||
|
* collection, and the guide will automatically have the correct layout
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
|
void addGuide( QgsLayoutGuide *guide SIP_TRANSFER );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the position (and visibility) of all guide line items.
|
||||||
|
*/
|
||||||
|
void update();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of guides contained in the collection with the specified
|
||||||
|
* \a orientation.
|
||||||
|
*/
|
||||||
|
QList< QgsLayoutGuide * > guides( QgsLayoutGuide::Orientation orientation );
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QgsLayout *mLayout = nullptr;
|
||||||
|
|
||||||
|
QList< QgsLayoutGuide * > mGuides;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \ingroup core
|
||||||
|
* \class QgsLayoutGuideProxyModel
|
||||||
|
* \brief Filters QgsLayoutGuideCollection models to guides of a single orientation (horizontal or vertical).
|
||||||
|
* \since QGIS 3.0
|
||||||
|
*/
|
||||||
|
class CORE_EXPORT QgsLayoutGuideProxyModel : public QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for QgsLayoutGuideProxyModel, filtered to guides of the specified \a orientation and \a page only.
|
||||||
|
*
|
||||||
|
* Page numbers begin at 0.
|
||||||
|
*/
|
||||||
|
explicit QgsLayoutGuideProxyModel( QObject *parent SIP_TRANSFERTHIS, QgsLayoutGuide::Orientation orientation, int page );
|
||||||
|
|
||||||
|
bool filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const override;
|
||||||
|
bool lessThan( const QModelIndex &left, const QModelIndex &right ) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QgsLayoutGuide::Orientation mOrientation = QgsLayoutGuide::Horizontal;
|
||||||
|
int mPage = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
#endif //QGSLAYOUTGUIDECOLLECTION_H
|
#endif //QGSLAYOUTGUIDECOLLECTION_H
|
||||||
|
@ -20,7 +20,10 @@ from qgis.core import (QgsProject,
|
|||||||
QgsLayoutMeasurement,
|
QgsLayoutMeasurement,
|
||||||
QgsUnitTypes,
|
QgsUnitTypes,
|
||||||
QgsLayoutPoint,
|
QgsLayoutPoint,
|
||||||
QgsLayoutItemPage)
|
QgsLayoutItemPage,
|
||||||
|
QgsLayoutGuideCollection,
|
||||||
|
QgsLayoutGuideProxyModel)
|
||||||
|
from qgis.PyQt.QtCore import (QModelIndex)
|
||||||
from qgis.PyQt.QtGui import (QPen,
|
from qgis.PyQt.QtGui import (QPen,
|
||||||
QColor)
|
QColor)
|
||||||
from qgis.PyQt.QtTest import QSignalSpy
|
from qgis.PyQt.QtTest import QSignalSpy
|
||||||
@ -36,11 +39,14 @@ class TestQgsLayoutGuide(unittest.TestCase):
|
|||||||
p = QgsProject()
|
p = QgsProject()
|
||||||
l = QgsLayout(p)
|
l = QgsLayout(p)
|
||||||
l.initializeDefaults() # add a page
|
l.initializeDefaults() # add a page
|
||||||
g = QgsLayoutGuide(l, QgsLayoutGuide.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutCentimeters))
|
g = QgsLayoutGuide(QgsLayoutGuide.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutCentimeters))
|
||||||
self.assertEqual(g.orientation(), QgsLayoutGuide.Horizontal)
|
self.assertEqual(g.orientation(), QgsLayoutGuide.Horizontal)
|
||||||
self.assertEqual(g.position().length(), 5.0)
|
self.assertEqual(g.position().length(), 5.0)
|
||||||
self.assertEqual(g.position().units(), QgsUnitTypes.LayoutCentimeters)
|
self.assertEqual(g.position().units(), QgsUnitTypes.LayoutCentimeters)
|
||||||
|
|
||||||
|
g.setLayout(l)
|
||||||
|
self.assertEqual(g.layout(), l)
|
||||||
|
|
||||||
position_changed_spy = QSignalSpy(g.positionChanged)
|
position_changed_spy = QSignalSpy(g.positionChanged)
|
||||||
g.setPosition(QgsLayoutMeasurement(15, QgsUnitTypes.LayoutInches))
|
g.setPosition(QgsLayoutMeasurement(15, QgsUnitTypes.LayoutInches))
|
||||||
self.assertEqual(g.position().length(), 15.0)
|
self.assertEqual(g.position().length(), 15.0)
|
||||||
@ -54,7 +60,8 @@ class TestQgsLayoutGuide(unittest.TestCase):
|
|||||||
p = QgsProject()
|
p = QgsProject()
|
||||||
l = QgsLayout(p)
|
l = QgsLayout(p)
|
||||||
l.initializeDefaults() # add a page
|
l.initializeDefaults() # add a page
|
||||||
g = QgsLayoutGuide(l, QgsLayoutGuide.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutCentimeters))
|
g = QgsLayoutGuide(QgsLayoutGuide.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutCentimeters))
|
||||||
|
g.setLayout(l)
|
||||||
g.update()
|
g.update()
|
||||||
|
|
||||||
self.assertTrue(g.item().isVisible())
|
self.assertTrue(g.item().isVisible())
|
||||||
@ -74,7 +81,8 @@ class TestQgsLayoutGuide(unittest.TestCase):
|
|||||||
self.assertEqual(g.layoutPosition(), 15)
|
self.assertEqual(g.layoutPosition(), 15)
|
||||||
|
|
||||||
# vertical guide
|
# vertical guide
|
||||||
g2 = QgsLayoutGuide(l, QgsLayoutGuide.Vertical, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutCentimeters))
|
g2 = QgsLayoutGuide(QgsLayoutGuide.Vertical, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutCentimeters))
|
||||||
|
g2.setLayout(l)
|
||||||
g2.update()
|
g2.update()
|
||||||
self.assertTrue(g2.item().isVisible())
|
self.assertTrue(g2.item().isVisible())
|
||||||
self.assertEqual(g2.item().line().x1(), 50)
|
self.assertEqual(g2.item().line().x1(), 50)
|
||||||
@ -96,6 +104,90 @@ class TestQgsLayoutGuide(unittest.TestCase):
|
|||||||
g.update()
|
g.update()
|
||||||
self.assertFalse(g.item().isVisible())
|
self.assertFalse(g.item().isVisible())
|
||||||
|
|
||||||
|
def testCollection(self):
|
||||||
|
p = QgsProject()
|
||||||
|
l = QgsLayout(p)
|
||||||
|
l.initializeDefaults() # add a page
|
||||||
|
guides = l.guides()
|
||||||
|
|
||||||
|
# no guides initially
|
||||||
|
self.assertEqual(guides.rowCount(QModelIndex()), 0)
|
||||||
|
self.assertFalse(guides.data(QModelIndex(), QgsLayoutGuideCollection.OrientationRole))
|
||||||
|
self.assertFalse(guides.guides(QgsLayoutGuide.Horizontal))
|
||||||
|
self.assertFalse(guides.guides(QgsLayoutGuide.Vertical))
|
||||||
|
|
||||||
|
# add a guide
|
||||||
|
g1 = QgsLayoutGuide(QgsLayoutGuide.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutCentimeters))
|
||||||
|
guides.addGuide(g1)
|
||||||
|
self.assertEqual(guides.rowCount(QModelIndex()), 1)
|
||||||
|
self.assertEqual(guides.data(guides.index(0, 0), QgsLayoutGuideCollection.OrientationRole), QgsLayoutGuide.Horizontal)
|
||||||
|
self.assertEqual(guides.data(guides.index(0, 0), QgsLayoutGuideCollection.PositionRole), 5)
|
||||||
|
self.assertEqual(guides.data(guides.index(0, 0), QgsLayoutGuideCollection.UnitsRole), QgsUnitTypes.LayoutCentimeters)
|
||||||
|
self.assertEqual(guides.data(guides.index(0, 0), QgsLayoutGuideCollection.PageRole), 0)
|
||||||
|
self.assertEqual(guides.guides(QgsLayoutGuide.Horizontal), [g1])
|
||||||
|
self.assertFalse(guides.guides(QgsLayoutGuide.Vertical))
|
||||||
|
|
||||||
|
g2 = QgsLayoutGuide(QgsLayoutGuide.Horizontal, QgsLayoutMeasurement(15))
|
||||||
|
guides.addGuide(g2)
|
||||||
|
self.assertEqual(guides.rowCount(QModelIndex()), 2)
|
||||||
|
self.assertEqual(guides.data(guides.index(1, 0), QgsLayoutGuideCollection.OrientationRole), QgsLayoutGuide.Horizontal)
|
||||||
|
self.assertEqual(guides.data(guides.index(1, 0), QgsLayoutGuideCollection.PositionRole), 15)
|
||||||
|
self.assertEqual(guides.data(guides.index(1, 0), QgsLayoutGuideCollection.UnitsRole), QgsUnitTypes.LayoutMillimeters)
|
||||||
|
self.assertEqual(guides.data(guides.index(1, 0), QgsLayoutGuideCollection.PageRole), 0)
|
||||||
|
self.assertEqual(guides.guides(QgsLayoutGuide.Horizontal), [g1, g2])
|
||||||
|
self.assertFalse(guides.guides(QgsLayoutGuide.Vertical))
|
||||||
|
|
||||||
|
page2 = QgsLayoutItemPage(l)
|
||||||
|
page2.setPageSize('A3')
|
||||||
|
l.pageCollection().addPage(page2)
|
||||||
|
g3 = QgsLayoutGuide(QgsLayoutGuide.Vertical, QgsLayoutMeasurement(35))
|
||||||
|
g3.setPage(1)
|
||||||
|
guides.addGuide(g3)
|
||||||
|
self.assertEqual(guides.rowCount(QModelIndex()), 3)
|
||||||
|
self.assertEqual(guides.data(guides.index(2, 0), QgsLayoutGuideCollection.OrientationRole), QgsLayoutGuide.Vertical)
|
||||||
|
self.assertEqual(guides.data(guides.index(2, 0), QgsLayoutGuideCollection.PositionRole), 35)
|
||||||
|
self.assertEqual(guides.data(guides.index(2, 0), QgsLayoutGuideCollection.UnitsRole), QgsUnitTypes.LayoutMillimeters)
|
||||||
|
self.assertEqual(guides.data(guides.index(2, 0), QgsLayoutGuideCollection.PageRole), 1)
|
||||||
|
self.assertEqual(guides.guides(QgsLayoutGuide.Horizontal), [g1, g2])
|
||||||
|
self.assertEqual(guides.guides(QgsLayoutGuide.Vertical), [g3])
|
||||||
|
|
||||||
|
def testQgsLayoutGuideProxyModel(self):
|
||||||
|
p = QgsProject()
|
||||||
|
l = QgsLayout(p)
|
||||||
|
l.initializeDefaults() # add a page
|
||||||
|
page2 = QgsLayoutItemPage(l)
|
||||||
|
page2.setPageSize('A3')
|
||||||
|
l.pageCollection().addPage(page2)
|
||||||
|
guides = l.guides()
|
||||||
|
|
||||||
|
hoz_filter = QgsLayoutGuideProxyModel(None, QgsLayoutGuide.Horizontal, 0)
|
||||||
|
hoz_filter.setSourceModel(guides)
|
||||||
|
hoz_page_1_filter = QgsLayoutGuideProxyModel(None, QgsLayoutGuide.Horizontal, 1)
|
||||||
|
hoz_page_1_filter.setSourceModel(guides)
|
||||||
|
vert_filter = QgsLayoutGuideProxyModel(None, QgsLayoutGuide.Vertical, 0)
|
||||||
|
vert_filter.setSourceModel(guides)
|
||||||
|
|
||||||
|
# no guides initially
|
||||||
|
self.assertEqual(hoz_filter.rowCount(QModelIndex()), 0)
|
||||||
|
self.assertEqual(hoz_page_1_filter.rowCount(QModelIndex()), 0)
|
||||||
|
self.assertEqual(vert_filter.rowCount(QModelIndex()), 0)
|
||||||
|
|
||||||
|
# add some guides
|
||||||
|
g1 = QgsLayoutGuide(QgsLayoutGuide.Horizontal, QgsLayoutMeasurement(5, QgsUnitTypes.LayoutCentimeters))
|
||||||
|
guides.addGuide(g1)
|
||||||
|
g2 = QgsLayoutGuide(QgsLayoutGuide.Horizontal, QgsLayoutMeasurement(15))
|
||||||
|
g2.setPage(1)
|
||||||
|
guides.addGuide(g2)
|
||||||
|
g3 = QgsLayoutGuide(QgsLayoutGuide.Vertical, QgsLayoutMeasurement(35))
|
||||||
|
guides.addGuide(g3)
|
||||||
|
|
||||||
|
self.assertEqual(hoz_filter.rowCount(QModelIndex()), 1)
|
||||||
|
self.assertEqual(hoz_filter.data(hoz_filter.index(0, 0), QgsLayoutGuideCollection.PositionRole), 5)
|
||||||
|
self.assertEqual(hoz_page_1_filter.rowCount(QModelIndex()), 1)
|
||||||
|
self.assertEqual(hoz_page_1_filter.data(hoz_page_1_filter.index(0, 0), QgsLayoutGuideCollection.PositionRole), 15)
|
||||||
|
self.assertEqual(vert_filter.rowCount(QModelIndex()), 1)
|
||||||
|
self.assertEqual(vert_filter.data(vert_filter.index(0, 0), QgsLayoutGuideCollection.PositionRole), 35)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user