diff --git a/python/core/layout/qgslayout.sip b/python/core/layout/qgslayout.sip index ba0d432cf818..9e4accbe18f3 100644 --- a/python/core/layout/qgslayout.sip +++ b/python/core/layout/qgslayout.sip @@ -228,6 +228,7 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator :rtype: QgsLayoutPageCollection %End + QRectF layoutBounds( bool ignorePages = false, double margin = 0.0 ) const; %Docstring Calculates the bounds of all non-gui items in the layout. Ignores snap lines, mouse handles diff --git a/python/core/layout/qgslayoutpagecollection.sip b/python/core/layout/qgslayoutpagecollection.sip index 0fe4e3185852..34562d2b3f40 100644 --- a/python/core/layout/qgslayoutpagecollection.sip +++ b/python/core/layout/qgslayoutpagecollection.sip @@ -66,6 +66,22 @@ class QgsLayoutPageCollection : QObject :rtype: int %End + QList< QgsLayoutItemPage * > visiblePages( QRectF region ) const; +%Docstring + Returns a list of the pages which are visible within the specified + ``region`` (in layout coordinates). +.. seealso:: visiblePageNumbers() + :rtype: list of QgsLayoutItemPage +%End + + QList< int > visiblePageNumbers( QRectF region ) const; +%Docstring + Returns a list of the page numbers which are visible within the specified + ``region`` (in layout coordinates). +.. seealso:: visiblePages() + :rtype: list of int +%End + void addPage( QgsLayoutItemPage *page /Transfer/ ); %Docstring Adds a ``page`` to the collection. Ownership of the ``page`` is transferred diff --git a/python/gui/layout/qgslayoutview.sip b/python/gui/layout/qgslayoutview.sip index 09f53931c42c..5b2a32da7e33 100644 --- a/python/gui/layout/qgslayoutview.sip +++ b/python/gui/layout/qgslayoutview.sip @@ -37,6 +37,7 @@ class QgsLayoutView: QGraphicsView :rtype: QgsLayout %End + void setCurrentLayout( QgsLayout *layout /KeepReference/ ); %Docstring Sets the current ``layout`` to edit in the view. @@ -112,6 +113,20 @@ class QgsLayoutView: QGraphicsView :rtype: int %End + QList< QgsLayoutItemPage * > visiblePages() const; +%Docstring + Returns a list of page items which are currently visible in the view. +.. seealso:: visiblePageNumbers() + :rtype: list of QgsLayoutItemPage +%End + + QList< int > visiblePageNumbers() const; +%Docstring + Returns a list of page numbers for pages which are currently visible in the view. +.. seealso:: visiblePages() + :rtype: list of int +%End + public slots: void zoomFull(); diff --git a/src/core/layout/qgslayout.cpp b/src/core/layout/qgslayout.cpp index b61c0631644a..61ef558abc56 100644 --- a/src/core/layout/qgslayout.cpp +++ b/src/core/layout/qgslayout.cpp @@ -135,6 +135,11 @@ QgsLayoutPageCollection *QgsLayout::pageCollection() return mPageCollection.get(); } +const QgsLayoutPageCollection *QgsLayout::pageCollection() const +{ + return mPageCollection.get(); +} + QRectF QgsLayout::layoutBounds( bool ignorePages, double margin ) const { //start with an empty rectangle diff --git a/src/core/layout/qgslayout.h b/src/core/layout/qgslayout.h index 2f25b6247af8..5c42e2125999 100644 --- a/src/core/layout/qgslayout.h +++ b/src/core/layout/qgslayout.h @@ -262,6 +262,12 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext */ QgsLayoutPageCollection *pageCollection(); + /** + * Returns a pointer to the layout's page collection, which stores and manages + * page items in the layout. + */ + SIP_SKIP const QgsLayoutPageCollection *pageCollection() const; + /** * Calculates the bounds of all non-gui items in the layout. Ignores snap lines, mouse handles * and other cosmetic items. diff --git a/src/core/layout/qgslayoutpagecollection.cpp b/src/core/layout/qgslayoutpagecollection.cpp index 82beba9ce896..3481d8d43bd1 100644 --- a/src/core/layout/qgslayoutpagecollection.cpp +++ b/src/core/layout/qgslayoutpagecollection.cpp @@ -168,6 +168,30 @@ int QgsLayoutPageCollection::pageNumber( QgsLayoutItemPage *page ) const return mPages.indexOf( page ); } +QList QgsLayoutPageCollection::visiblePages( QRectF region ) const +{ + QList pages; + Q_FOREACH ( QgsLayoutItemPage *page, mPages ) + { + if ( page->mapToScene( page->rect() ).boundingRect().intersects( region ) ) + pages << page; + } + return pages; +} + +QList QgsLayoutPageCollection::visiblePageNumbers( QRectF region ) const +{ + QList< int > pages; + int p = 0; + Q_FOREACH ( QgsLayoutItemPage *page, mPages ) + { + if ( page->mapToScene( page->rect() ).boundingRect().intersects( region ) ) + pages << p; + p++; + } + return pages; +} + void QgsLayoutPageCollection::addPage( QgsLayoutItemPage *page ) { mPages.append( page ); diff --git a/src/core/layout/qgslayoutpagecollection.h b/src/core/layout/qgslayoutpagecollection.h index 06e1da72a6d0..f7d2c301aee7 100644 --- a/src/core/layout/qgslayoutpagecollection.h +++ b/src/core/layout/qgslayoutpagecollection.h @@ -79,6 +79,20 @@ class CORE_EXPORT QgsLayoutPageCollection : public QObject */ int pageNumber( QgsLayoutItemPage *page ) const; + /** + * Returns a list of the pages which are visible within the specified + * \a region (in layout coordinates). + * \see visiblePageNumbers() + */ + QList< QgsLayoutItemPage * > visiblePages( QRectF region ) const; + + /** + * Returns a list of the page numbers which are visible within the specified + * \a region (in layout coordinates). + * \see visiblePages() + */ + QList< int > visiblePageNumbers( QRectF region ) const; + /** * 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 diff --git a/src/gui/layout/qgslayoutview.cpp b/src/gui/layout/qgslayoutview.cpp index dd5f974edcaf..2d42a7322504 100644 --- a/src/gui/layout/qgslayoutview.cpp +++ b/src/gui/layout/qgslayoutview.cpp @@ -57,6 +57,11 @@ QgsLayout *QgsLayoutView::currentLayout() return qobject_cast( scene() ); } +const QgsLayout *QgsLayoutView::currentLayout() const +{ + return qobject_cast( scene() ); +} + void QgsLayoutView::setCurrentLayout( QgsLayout *layout ) { setScene( layout ); @@ -163,6 +168,22 @@ QgsLayoutViewMenuProvider *QgsLayoutView::menuProvider() const return mMenuProvider.get(); } +QList QgsLayoutView::visiblePages() const +{ + //get current visible part of scene + QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() ); + QRectF visibleRect = mapToScene( viewportRect ).boundingRect(); + return currentLayout()->pageCollection()->visiblePages( visibleRect ); +} + +QList QgsLayoutView::visiblePageNumbers() const +{ + //get current visible part of scene + QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() ); + QRectF visibleRect = mapToScene( viewportRect ).boundingRect(); + return currentLayout()->pageCollection()->visiblePageNumbers( visibleRect ); +} + void QgsLayoutView::zoomFull() { fitInView( scene()->sceneRect(), Qt::KeepAspectRatio ); diff --git a/src/gui/layout/qgslayoutview.h b/src/gui/layout/qgslayoutview.h index 55403a92e8bb..8366bbdb235f 100644 --- a/src/gui/layout/qgslayoutview.h +++ b/src/gui/layout/qgslayoutview.h @@ -20,6 +20,7 @@ #include "qgis.h" #include "qgsprevieweffect.h" // for QgsPreviewEffect::PreviewMode #include "qgis_gui.h" +#include "qgslayoutitempage.h" #include #include #include @@ -65,6 +66,13 @@ class GUI_EXPORT QgsLayoutView: public QGraphicsView */ QgsLayout *currentLayout(); + /** + * Returns the current layout associated with the view. + * \see setCurrentLayout() + * \see layoutSet() + */ + SIP_SKIP const QgsLayout *currentLayout() const; + /** * Sets the current \a layout to edit in the view. * \see currentLayout() @@ -137,6 +145,18 @@ class GUI_EXPORT QgsLayoutView: public QGraphicsView */ int currentPage() const { return mCurrentPage; } + /** + * Returns a list of page items which are currently visible in the view. + * \see visiblePageNumbers() + */ + QList< QgsLayoutItemPage * > visiblePages() const; + + /** + * Returns a list of page numbers for pages which are currently visible in the view. + * \see visiblePages() + */ + QList< int > visiblePageNumbers() const; + public slots: /** diff --git a/tests/src/python/test_qgslayoutpagecollection.py b/tests/src/python/test_qgslayoutpagecollection.py index 009d724753cd..bb47d69873cb 100644 --- a/tests/src/python/test_qgslayoutpagecollection.py +++ b/tests/src/python/test_qgslayoutpagecollection.py @@ -25,7 +25,8 @@ QgsLayoutPageCollection, QgsSimpleFillSymbolLayer, QgsFillSymbol) -from qgis.PyQt.QtCore import Qt, QCoreApplication, QEvent, QPointF +from qgis.PyQt.QtCore import Qt, QCoreApplication, QEvent, QPointF, QRectF + from qgis.testing import start_app, unittest start_app() @@ -378,6 +379,44 @@ def testPageAtPoint(self): self.assertEqual(collection.pageAtPoint(QPointF(10, 500)), page2) self.assertFalse(collection.pageAtPoint(QPointF(10, 600))) + def testVisiblePages(self): + p = QgsProject() + l = QgsLayout(p) + collection = l.pageCollection() + + self.assertFalse(collection.visiblePages(QRectF(0, 0, 10, 10))) + self.assertFalse(collection.visiblePageNumbers(QRectF(0, 0, 10, 10))) + + # add a page + page = QgsLayoutItemPage(l) + page.setPageSize('A4') + collection.addPage(page) + + self.assertFalse(collection.visiblePages(QRectF(-10, -10, 5, 5))) + self.assertFalse(collection.visiblePageNumbers(QRectF(-10, -10, 5, 5))) + self.assertEqual(collection.visiblePages(QRectF(-10, -10, 15, 15)), [page]) + self.assertEqual(collection.visiblePageNumbers(QRectF(-10, -10, 15, 15)), [0]) + self.assertEqual(collection.visiblePages(QRectF(200, 200, 115, 115)), [page]) + self.assertEqual(collection.visiblePageNumbers(QRectF(200, 200, 115, 115)), [0]) + + page2 = QgsLayoutItemPage(l) + page2.setPageSize('A5') + collection.addPage(page2) + + self.assertFalse(collection.visiblePages(QRectF(-10, -10, 5, 5))) + self.assertFalse(collection.visiblePageNumbers(QRectF(-10, -10, 5, 5))) + self.assertEqual(collection.visiblePages(QRectF(-10, -10, 15, 15)), [page]) + self.assertEqual(collection.visiblePageNumbers(QRectF(-10, -10, 15, 15)), [0]) + self.assertEqual(collection.visiblePages(QRectF(200, 200, 115, 115)), [page]) + self.assertEqual(collection.visiblePageNumbers(QRectF(200, 200, 115, 115)), [0]) + + self.assertEqual(collection.visiblePages(QRectF(200, 200, 115, 615)), [page]) + self.assertEqual(collection.visiblePageNumbers(QRectF(200, 200, 115, 115)), [0]) + self.assertEqual(collection.visiblePages(QRectF(100, 200, 115, 615)), [page, page2]) + self.assertEqual(collection.visiblePageNumbers(QRectF(100, 200, 115, 115)), [0, 1]) + self.assertEqual(collection.visiblePages(QRectF(100, 310, 115, 615)), [page2]) + self.assertEqual(collection.visiblePageNumbers(QRectF(100, 310, 115, 115)), [1]) + if __name__ == '__main__': unittest.main()