Skip to content
Permalink
Browse files

Add support for adding/removing pages to a collection

  • Loading branch information
nyalldawson committed Jul 19, 2017
1 parent ea32391 commit 79a46941771b87a6b099c9e5ebaebb61619f9ee2
@@ -18,6 +18,24 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem

%TypeHeaderCode
#include "qgslayoutitem.h"

#include <qgslayoutitemshape.h>
#include <qgslayoutitempage.h>
%End

%ConvertToSubClassCode
// the conversions have to be static, because they're using multiple inheritance
// (seen in PyQt4 .sip files for some QGraphicsItem classes)
switch ( sipCpp->type() )
{
// really, these *should* use the constants from QgsLayoutItemRegistry, but sip doesn't like that!
case QGraphicsItem::UserType + 101:
sipType = sipType_QgsLayoutItemPage;
*sipCppRet = static_cast<QgsLayoutItemPage *>( sipCpp );
break;
default:
sipType = 0;
}
%End
public:

@@ -26,12 +26,72 @@ class QgsLayoutPageCollection : QObject
Constructor for QgsLayoutItemPage, with the specified parent ``layout``.
%End

~QgsLayoutPageCollection();

QgsLayout *layout() const;
%Docstring
Returns the layout this collection belongs to.
:rtype: QgsLayout
%End

QList< QgsLayoutItemPage * > pages();
%Docstring
Returns a list of pages in the collection.
.. seealso:: page()
.. seealso:: pageCount()
:rtype: list of QgsLayoutItemPage
%End

int pageCount() const;
%Docstring
Returns the number of pages in the collection.
.. seealso:: pages()
:rtype: int
%End

QgsLayoutItemPage *page( int pageNumber );
%Docstring
Returns a specific page (by ``pageNumber``) from the collection.
Internal page numbering starts at 0 - so a ``pageNumber`` of 0
corresponds to the first page in the collection.
A None is returned if an invalid page number is specified.
.. seealso:: pages()
:rtype: QgsLayoutItemPage
%End

void addPage( QgsLayoutItemPage *page /Transfer/ );
%Docstring
Adds a ``page`` to the collection. Ownership of the ``page`` is transferred
to the collection, and the page will automatically be added to the collection's
layout() (there is no need to manually add the page item to the layout).
The page will be added after all pages currently contained in the collection.
.. seealso:: insertPage()
%End

void insertPage( QgsLayoutItemPage *page /Transfer/, int beforePage );
%Docstring
Inserts a ``page`` into a specific position in the collection.

Ownership of the ``page`` is transferred
to the collection, and the page will automatically be added to the collection's
layout() (there is no need to manually add the page item to the layout).

The page will be added after before the page number specified by ``beforePage``.
(Page numbers in collections begin at 0 - so a ``beforePage`` of 0 will insert
the page before all existing pages).

.. seealso:: addPage()
%End

void deletePage( int pageNumber );
%Docstring
Deletes a page from the collection. The page will automatically be removed
from the collection's layout().

Page numbers in collections begin at 0 - so a ``pageNumber`` of 0 will delete
the first page in the collection.
%End

void setPageStyleSymbol( QgsFillSymbol *symbol );
%Docstring
Sets the ``symbol`` to use for drawing pages in the collection.
@@ -35,6 +35,28 @@ class QPainter;
*/
class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectItem
{
#ifdef SIP_RUN
#include <qgslayoutitemshape.h>
#include <qgslayoutitempage.h>
#endif


#ifdef SIP_RUN
SIP_CONVERT_TO_SUBCLASS_CODE
// the conversions have to be static, because they're using multiple inheritance
// (seen in PyQt4 .sip files for some QGraphicsItem classes)
switch ( sipCpp->type() )
{
// really, these *should* use the constants from QgsLayoutItemRegistry, but sip doesn't like that!
case QGraphicsItem::UserType + 101:
sipType = sipType_QgsLayoutItemPage;
*sipCppRet = static_cast<QgsLayoutItemPage *>( sipCpp );
break;
default:
sipType = 0;
}
SIP_END
#endif

Q_OBJECT

@@ -24,6 +24,15 @@ QgsLayoutPageCollection::QgsLayoutPageCollection( QgsLayout *layout )
createDefaultPageStyleSymbol();
}

QgsLayoutPageCollection::~QgsLayoutPageCollection()
{
Q_FOREACH ( QgsLayoutItemPage *page, mPages )
{
mLayout->removeItem( page );
page->deleteLater();
}
}

void QgsLayoutPageCollection::setPageStyleSymbol( QgsFillSymbol *symbol )
{
if ( !symbol )
@@ -37,6 +46,53 @@ QgsLayout *QgsLayoutPageCollection::layout() const
return mLayout;
}

QList<QgsLayoutItemPage *> QgsLayoutPageCollection::pages()
{
return mPages;
}

int QgsLayoutPageCollection::pageCount() const
{
return mPages.count();
}

QgsLayoutItemPage *QgsLayoutPageCollection::page( int pageNumber )
{
return mPages.value( pageNumber );
}

void QgsLayoutPageCollection::addPage( QgsLayoutItemPage *page )
{
mPages.append( page );
mLayout->addItem( page );
}

void QgsLayoutPageCollection::insertPage( QgsLayoutItemPage *page, int beforePage )
{
if ( beforePage < 0 )
beforePage = 0;

if ( beforePage >= mPages.count() )
{
mPages.append( page );
}
else
{
mPages.insert( beforePage, page );
}
mLayout->addItem( page );
}

void QgsLayoutPageCollection::deletePage( int pageNumber )
{
if ( pageNumber < 0 || pageNumber >= mPages.count() )
return;

QgsLayoutItemPage *page = mPages.takeAt( pageNumber );
mLayout->removeItem( page );
page->deleteLater();
}

void QgsLayoutPageCollection::createDefaultPageStyleSymbol()
{
QgsStringMap properties;
@@ -20,6 +20,7 @@
#include "qgis_core.h"
#include "qgis_sip.h"
#include "qgssymbol.h"
#include "qgslayoutitempage.h"
#include <QObject>
#include <memory>

@@ -43,11 +44,68 @@ class CORE_EXPORT QgsLayoutPageCollection : public QObject
*/
explicit QgsLayoutPageCollection( QgsLayout *layout SIP_TRANSFERTHIS );

~QgsLayoutPageCollection();

/**
* Returns the layout this collection belongs to.
*/
QgsLayout *layout() const;

/**
* Returns a list of pages in the collection.
* \see page()
* \see pageCount()
*/
QList< QgsLayoutItemPage * > pages();

/**
* Returns the number of pages in the collection.
* \see pages()
*/
int pageCount() const;

/**
* Returns a specific page (by \a pageNumber) from the collection.
* Internal page numbering starts at 0 - so a \a pageNumber of 0
* corresponds to the first page in the collection.
* A nullptr is returned if an invalid page number is specified.
* \see pages()
*/
QgsLayoutItemPage *page( int pageNumber );

/**
* Adds a \a page to the collection. Ownership of the \a page is transferred
* to the collection, and the page will automatically be added to the collection's
* layout() (there is no need to manually add the page item to the layout).
* The page will be added after all pages currently contained in the collection.
* \see insertPage()
*/
void addPage( QgsLayoutItemPage *page SIP_TRANSFER );

/**
* Inserts a \a page into a specific position in the collection.
*
* Ownership of the \a page is transferred
* to the collection, and the page will automatically be added to the collection's
* layout() (there is no need to manually add the page item to the layout).
*
* The page will be added after before the page number specified by \a beforePage.
* (Page numbers in collections begin at 0 - so a \a beforePage of 0 will insert
* the page before all existing pages).
*
* \see addPage()
*/
void insertPage( QgsLayoutItemPage *page SIP_TRANSFER, int beforePage );

/**
* Deletes a page from the collection. The page will automatically be removed
* from the collection's layout().
*
* Page numbers in collections begin at 0 - so a \a pageNumber of 0 will delete
* the first page in the collection.
*/
void deletePage( int pageNumber );

/**
* Sets the \a symbol to use for drawing pages in the collection.
*
@@ -69,6 +127,8 @@ class CORE_EXPORT QgsLayoutPageCollection : public QObject
//! Symbol for drawing pages
std::unique_ptr< QgsFillSymbol > mPageStyleSymbol;

QList< QgsLayoutItemPage * > mPages;

void createDefaultPageStyleSymbol();
};

@@ -13,9 +13,10 @@
__revision__ = '$Format:%H$'

import qgis # NOQA
import sip

from qgis.core import QgsUnitTypes, QgsLayout, QgsProject, QgsLayoutPageCollection, QgsSimpleFillSymbolLayer, QgsFillSymbol
from qgis.PyQt.QtCore import Qt
from qgis.core import QgsUnitTypes, QgsLayout, QgsLayoutItemPage, QgsProject, QgsLayoutPageCollection, QgsSimpleFillSymbolLayer, QgsFillSymbol
from qgis.PyQt.QtCore import Qt, QCoreApplication, QEvent
from qgis.testing import start_app, unittest

start_app()
@@ -49,6 +50,76 @@ def testSymbol(self):
self.assertEqual(collection.pageStyleSymbol().symbolLayer(0).color().name(), '#00ff00')
self.assertEqual(collection.pageStyleSymbol().symbolLayer(0).strokeColor().name(), '#ff0000')

def testPages(self):
"""
Test adding/retrieving/deleting pages from the collection
"""
p = QgsProject()
l = QgsLayout(p)
collection = l.pageCollection()

self.assertEqual(collection.pageCount(), 0)
self.assertFalse(collection.pages())
self.assertFalse(collection.page(-1))
self.assertFalse(collection.page(0))
self.assertFalse(collection.page(1))

# add a page
page = QgsLayoutItemPage(l)
page.setPageSize('A4')
collection.addPage(page)

self.assertTrue(page in l.items())

self.assertEqual(collection.pageCount(), 1)
self.assertEqual(collection.pages(), [page])
self.assertFalse(collection.page(-1))
self.assertEqual(collection.page(0), page)
self.assertFalse(collection.page(1))

# add a second page
page2 = QgsLayoutItemPage(l)
page2.setPageSize('A5')
collection.addPage(page2)

self.assertEqual(collection.pageCount(), 2)
self.assertEqual(collection.pages(), [page, page2])
self.assertFalse(collection.page(-1))
self.assertEqual(collection.page(0), page)
self.assertEqual(collection.page(1), page2)

# insert a page
page3 = QgsLayoutItemPage(l)
page3.setPageSize('A3')
collection.insertPage(page3, 1)
self.assertTrue(page3 in l.items())

self.assertEqual(collection.pageCount(), 3)
self.assertEqual(collection.pages(), [page, page3, page2])
self.assertEqual(collection.page(0), page)
self.assertEqual(collection.page(1), page3)
self.assertEqual(collection.page(2), page2)

# delete page
collection.deletePage(-1)
self.assertEqual(collection.pageCount(), 3)
self.assertEqual(collection.pages(), [page, page3, page2])
collection.deletePage(100)
self.assertEqual(collection.pageCount(), 3)
self.assertEqual(collection.pages(), [page, page3, page2])
collection.deletePage(1)
self.assertEqual(collection.pageCount(), 2)
self.assertEqual(collection.pages(), [page, page2])

# make sure page was deleted
QCoreApplication.sendPostedEvents(None, QEvent.DeferredDelete)
self.assertTrue(sip.isdeleted(page3))

del l
QCoreApplication.sendPostedEvents(None, QEvent.DeferredDelete)
self.assertTrue(sip.isdeleted(page))
self.assertTrue(sip.isdeleted(page2))


if __name__ == '__main__':
unittest.main()

0 comments on commit 79a4694

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