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:
Nyall Dawson 2017-07-25 20:02:38 +10:00
parent fa5eb4e5ad
commit f5126b0abd
7 changed files with 544 additions and 13 deletions

View File

@ -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

View File

@ -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 *

View File

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

View File

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

View File

@ -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;
}

View File

@ -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

View File

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