mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Start on reflow support for page collections (needs tests)
This commit is contained in:
parent
79a4694177
commit
39bf23a5d5
@ -29,6 +29,16 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator
|
|||||||
QgsLayout( QgsProject *project );
|
QgsLayout( QgsProject *project );
|
||||||
%Docstring
|
%Docstring
|
||||||
Construct a new layout linked to the specified ``project``.
|
Construct a new layout linked to the specified ``project``.
|
||||||
|
|
||||||
|
If the layout is a "new" layout (as opposed to a layout which will
|
||||||
|
restore a previous state from XML) then initializeDefaults() should be
|
||||||
|
called on the new layout.
|
||||||
|
%End
|
||||||
|
|
||||||
|
void initializeDefaults();
|
||||||
|
%Docstring
|
||||||
|
Initializes an empty layout, e.g. by adding a default page to the layout. This should be called after creating
|
||||||
|
a new layout.
|
||||||
%End
|
%End
|
||||||
|
|
||||||
QgsProject *project() const;
|
QgsProject *project() const;
|
||||||
@ -191,6 +201,29 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator
|
|||||||
:rtype: QgsLayoutPageCollection
|
:rtype: QgsLayoutPageCollection
|
||||||
%End
|
%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
|
||||||
|
and other cosmetic items.
|
||||||
|
\param ignorePages set to true to ignore page items
|
||||||
|
\param margin optional marginal (in percent, e.g., 0.05 = 5% ) to add around items
|
||||||
|
:return: layout bounds, in layout units.
|
||||||
|
:rtype: QRectF
|
||||||
|
%End
|
||||||
|
|
||||||
|
void addLayoutItem( QgsLayoutItem *item /Transfer/ );
|
||||||
|
%Docstring
|
||||||
|
Adds an ``item`` to the layout. This should be called instead of the base class addItem()
|
||||||
|
method. Ownership of the item is transferred to the layout.
|
||||||
|
%End
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void updateBounds();
|
||||||
|
%Docstring
|
||||||
|
Updates the scene bounds of the layout.
|
||||||
|
%End
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void variablesChanged();
|
void variablesChanged();
|
||||||
|
@ -65,6 +65,9 @@ class QgsLayoutPageCollection : QObject
|
|||||||
to the collection, and the page will automatically be added to the collection's
|
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).
|
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.
|
The page will be added after all pages currently contained in the collection.
|
||||||
|
|
||||||
|
Calling addPage() automatically triggers a reflow() of pages.
|
||||||
|
|
||||||
.. seealso:: insertPage()
|
.. seealso:: insertPage()
|
||||||
%End
|
%End
|
||||||
|
|
||||||
@ -80,6 +83,8 @@ class QgsLayoutPageCollection : QObject
|
|||||||
(Page numbers in collections begin at 0 - so a ``beforePage`` of 0 will insert
|
(Page numbers in collections begin at 0 - so a ``beforePage`` of 0 will insert
|
||||||
the page before all existing pages).
|
the page before all existing pages).
|
||||||
|
|
||||||
|
Calling insertPage() automatically triggers a reflow() of pages.
|
||||||
|
|
||||||
.. seealso:: addPage()
|
.. seealso:: addPage()
|
||||||
%End
|
%End
|
||||||
|
|
||||||
@ -90,6 +95,8 @@ class QgsLayoutPageCollection : QObject
|
|||||||
|
|
||||||
Page numbers in collections begin at 0 - so a ``pageNumber`` of 0 will delete
|
Page numbers in collections begin at 0 - so a ``pageNumber`` of 0 will delete
|
||||||
the first page in the collection.
|
the first page in the collection.
|
||||||
|
|
||||||
|
Calling deletePage() automatically triggers a reflow() of pages.
|
||||||
%End
|
%End
|
||||||
|
|
||||||
void setPageStyleSymbol( QgsFillSymbol *symbol );
|
void setPageStyleSymbol( QgsFillSymbol *symbol );
|
||||||
@ -107,6 +114,19 @@ class QgsLayoutPageCollection : QObject
|
|||||||
:rtype: QgsFillSymbol
|
:rtype: QgsFillSymbol
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
void reflow();
|
||||||
|
%Docstring
|
||||||
|
Forces the page collection to reflow the arrangement of pages, e.g. to account
|
||||||
|
for page size/orientation change.
|
||||||
|
%End
|
||||||
|
|
||||||
|
double maximumPageWidth() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the maximum width of pages in the collection. The returned value is
|
||||||
|
in layout units.
|
||||||
|
:rtype: float
|
||||||
|
%End
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
|
@ -25,6 +25,14 @@ QgsLayout::QgsLayout( QgsProject *project )
|
|||||||
setBackgroundBrush( QColor( 215, 215, 215 ) );
|
setBackgroundBrush( QColor( 215, 215, 215 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QgsLayout::initializeDefaults()
|
||||||
|
{
|
||||||
|
// default to a A4 landscape page
|
||||||
|
QgsLayoutItemPage *page = new QgsLayoutItemPage( this );
|
||||||
|
page->setPageSize( QgsLayoutSize( 297, 210, QgsUnitTypes::LayoutMillimeters ) );
|
||||||
|
mPageCollection->addPage( page );
|
||||||
|
}
|
||||||
|
|
||||||
QgsProject *QgsLayout::project() const
|
QgsProject *QgsLayout::project() const
|
||||||
{
|
{
|
||||||
return mProject;
|
return mProject;
|
||||||
@ -112,3 +120,48 @@ QgsLayoutPageCollection *QgsLayout::pageCollection()
|
|||||||
{
|
{
|
||||||
return mPageCollection.get();
|
return mPageCollection.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRectF QgsLayout::layoutBounds( bool ignorePages, double margin ) const
|
||||||
|
{
|
||||||
|
//start with an empty rectangle
|
||||||
|
QRectF bounds;
|
||||||
|
|
||||||
|
//add all QgsComposerItems and QgsPaperItems which are in the composition
|
||||||
|
Q_FOREACH ( const QGraphicsItem *item, items() )
|
||||||
|
{
|
||||||
|
const QgsLayoutItem *layoutItem = dynamic_cast<const QgsLayoutItem *>( item );
|
||||||
|
if ( !layoutItem )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool isPage = layoutItem->type() == QgsLayoutItemRegistry::LayoutPage;
|
||||||
|
if ( !isPage || !ignorePages )
|
||||||
|
{
|
||||||
|
//expand bounds with current item's bounds
|
||||||
|
if ( bounds.isValid() )
|
||||||
|
bounds = bounds.united( item->sceneBoundingRect() );
|
||||||
|
else
|
||||||
|
bounds = item->sceneBoundingRect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( bounds.isValid() && margin > 0.0 )
|
||||||
|
{
|
||||||
|
//finally, expand bounds out by specified margin of page size
|
||||||
|
double maxWidth = mPageCollection->maximumPageWidth();
|
||||||
|
bounds.adjust( -maxWidth * margin, -maxWidth * margin, maxWidth * margin, maxWidth * margin );
|
||||||
|
}
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLayout::addLayoutItem( QgsLayoutItem *item )
|
||||||
|
{
|
||||||
|
addItem( item );
|
||||||
|
updateBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLayout::updateBounds()
|
||||||
|
{
|
||||||
|
setSceneRect( layoutBounds( false, 0.05 ) );
|
||||||
|
}
|
||||||
|
@ -45,9 +45,19 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new layout linked to the specified \a project.
|
* Construct a new layout linked to the specified \a project.
|
||||||
|
*
|
||||||
|
* If the layout is a "new" layout (as opposed to a layout which will
|
||||||
|
* restore a previous state from XML) then initializeDefaults() should be
|
||||||
|
* called on the new layout.
|
||||||
*/
|
*/
|
||||||
QgsLayout( QgsProject *project );
|
QgsLayout( QgsProject *project );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an empty layout, e.g. by adding a default page to the layout. This should be called after creating
|
||||||
|
* a new layout.
|
||||||
|
*/
|
||||||
|
void initializeDefaults();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The project associated with the layout. Used to get access to layers, map themes,
|
* The project associated with the layout. Used to get access to layers, map themes,
|
||||||
* relations and various other bits. It is never null.
|
* relations and various other bits. It is never null.
|
||||||
@ -211,6 +221,28 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
|
|||||||
*/
|
*/
|
||||||
QgsLayoutPageCollection *pageCollection();
|
QgsLayoutPageCollection *pageCollection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the bounds of all non-gui items in the layout. Ignores snap lines, mouse handles
|
||||||
|
* and other cosmetic items.
|
||||||
|
* \param ignorePages set to true to ignore page items
|
||||||
|
* \param margin optional marginal (in percent, e.g., 0.05 = 5% ) to add around items
|
||||||
|
* \returns layout bounds, in layout units.
|
||||||
|
*/
|
||||||
|
QRectF layoutBounds( bool ignorePages = false, double margin = 0.0 ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an \a item to the layout. This should be called instead of the base class addItem()
|
||||||
|
* method. Ownership of the item is transferred to the layout.
|
||||||
|
*/
|
||||||
|
void addLayoutItem( QgsLayoutItem *item SIP_TRANSFER );
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the scene bounds of the layout.
|
||||||
|
*/
|
||||||
|
void updateBounds();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
#include "qgslayoutpagecollection.h"
|
#include "qgslayoutpagecollection.h"
|
||||||
#include "qgslayout.h"
|
#include "qgslayout.h"
|
||||||
|
|
||||||
|
#define SPACE_BETWEEN_PAGES 10
|
||||||
|
|
||||||
QgsLayoutPageCollection::QgsLayoutPageCollection( QgsLayout *layout )
|
QgsLayoutPageCollection::QgsLayoutPageCollection( QgsLayout *layout )
|
||||||
: QObject( layout )
|
: QObject( layout )
|
||||||
, mLayout( layout )
|
, mLayout( layout )
|
||||||
@ -41,6 +43,29 @@ void QgsLayoutPageCollection::setPageStyleSymbol( QgsFillSymbol *symbol )
|
|||||||
mPageStyleSymbol.reset( static_cast<QgsFillSymbol *>( symbol->clone() ) );
|
mPageStyleSymbol.reset( static_cast<QgsFillSymbol *>( symbol->clone() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QgsLayoutPageCollection::reflow()
|
||||||
|
{
|
||||||
|
double currentY = 0;
|
||||||
|
QgsLayoutPoint p( 0, 0, mLayout->units() );
|
||||||
|
Q_FOREACH ( QgsLayoutItemPage *page, mPages )
|
||||||
|
{
|
||||||
|
page->attemptMove( p );
|
||||||
|
currentY += mLayout->convertToLayoutUnits( page->pageSize() ).height() + SPACE_BETWEEN_PAGES;
|
||||||
|
p.setY( currentY );
|
||||||
|
}
|
||||||
|
mLayout->updateBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
double QgsLayoutPageCollection::maximumPageWidth() const
|
||||||
|
{
|
||||||
|
double maxWidth = 0;
|
||||||
|
Q_FOREACH ( QgsLayoutItemPage *page, mPages )
|
||||||
|
{
|
||||||
|
maxWidth = qMax( maxWidth, mLayout->convertToLayoutUnits( page->pageSize() ).width() );
|
||||||
|
}
|
||||||
|
return maxWidth;
|
||||||
|
}
|
||||||
|
|
||||||
QgsLayout *QgsLayoutPageCollection::layout() const
|
QgsLayout *QgsLayoutPageCollection::layout() const
|
||||||
{
|
{
|
||||||
return mLayout;
|
return mLayout;
|
||||||
@ -65,6 +90,7 @@ void QgsLayoutPageCollection::addPage( QgsLayoutItemPage *page )
|
|||||||
{
|
{
|
||||||
mPages.append( page );
|
mPages.append( page );
|
||||||
mLayout->addItem( page );
|
mLayout->addItem( page );
|
||||||
|
reflow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsLayoutPageCollection::insertPage( QgsLayoutItemPage *page, int beforePage )
|
void QgsLayoutPageCollection::insertPage( QgsLayoutItemPage *page, int beforePage )
|
||||||
@ -81,6 +107,7 @@ void QgsLayoutPageCollection::insertPage( QgsLayoutItemPage *page, int beforePag
|
|||||||
mPages.insert( beforePage, page );
|
mPages.insert( beforePage, page );
|
||||||
}
|
}
|
||||||
mLayout->addItem( page );
|
mLayout->addItem( page );
|
||||||
|
reflow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsLayoutPageCollection::deletePage( int pageNumber )
|
void QgsLayoutPageCollection::deletePage( int pageNumber )
|
||||||
@ -91,6 +118,7 @@ void QgsLayoutPageCollection::deletePage( int pageNumber )
|
|||||||
QgsLayoutItemPage *page = mPages.takeAt( pageNumber );
|
QgsLayoutItemPage *page = mPages.takeAt( pageNumber );
|
||||||
mLayout->removeItem( page );
|
mLayout->removeItem( page );
|
||||||
page->deleteLater();
|
page->deleteLater();
|
||||||
|
reflow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsLayoutPageCollection::createDefaultPageStyleSymbol()
|
void QgsLayoutPageCollection::createDefaultPageStyleSymbol()
|
||||||
|
@ -78,6 +78,9 @@ class CORE_EXPORT QgsLayoutPageCollection : public QObject
|
|||||||
* to the collection, and the page will automatically be added to the collection's
|
* 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).
|
* 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.
|
* The page will be added after all pages currently contained in the collection.
|
||||||
|
*
|
||||||
|
* Calling addPage() automatically triggers a reflow() of pages.
|
||||||
|
*
|
||||||
* \see insertPage()
|
* \see insertPage()
|
||||||
*/
|
*/
|
||||||
void addPage( QgsLayoutItemPage *page SIP_TRANSFER );
|
void addPage( QgsLayoutItemPage *page SIP_TRANSFER );
|
||||||
@ -93,6 +96,8 @@ class CORE_EXPORT QgsLayoutPageCollection : public QObject
|
|||||||
* (Page numbers in collections begin at 0 - so a \a beforePage of 0 will insert
|
* (Page numbers in collections begin at 0 - so a \a beforePage of 0 will insert
|
||||||
* the page before all existing pages).
|
* the page before all existing pages).
|
||||||
*
|
*
|
||||||
|
* Calling insertPage() automatically triggers a reflow() of pages.
|
||||||
|
*
|
||||||
* \see addPage()
|
* \see addPage()
|
||||||
*/
|
*/
|
||||||
void insertPage( QgsLayoutItemPage *page SIP_TRANSFER, int beforePage );
|
void insertPage( QgsLayoutItemPage *page SIP_TRANSFER, int beforePage );
|
||||||
@ -103,6 +108,8 @@ class CORE_EXPORT QgsLayoutPageCollection : public QObject
|
|||||||
*
|
*
|
||||||
* Page numbers in collections begin at 0 - so a \a pageNumber of 0 will delete
|
* Page numbers in collections begin at 0 - so a \a pageNumber of 0 will delete
|
||||||
* the first page in the collection.
|
* the first page in the collection.
|
||||||
|
*
|
||||||
|
* Calling deletePage() automatically triggers a reflow() of pages.
|
||||||
*/
|
*/
|
||||||
void deletePage( int pageNumber );
|
void deletePage( int pageNumber );
|
||||||
|
|
||||||
@ -120,6 +127,18 @@ class CORE_EXPORT QgsLayoutPageCollection : public QObject
|
|||||||
*/
|
*/
|
||||||
const QgsFillSymbol *pageStyleSymbol() const { return mPageStyleSymbol.get(); }
|
const QgsFillSymbol *pageStyleSymbol() const { return mPageStyleSymbol.get(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forces the page collection to reflow the arrangement of pages, e.g. to account
|
||||||
|
* for page size/orientation change.
|
||||||
|
*/
|
||||||
|
void reflow();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum width of pages in the collection. The returned value is
|
||||||
|
* in layout units.
|
||||||
|
*/
|
||||||
|
double maximumPageWidth() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QgsLayout *mLayout = nullptr;
|
QgsLayout *mLayout = nullptr;
|
||||||
|
@ -115,7 +115,7 @@ void QgsLayoutViewToolAddItem::layoutReleaseEvent( QgsLayoutViewMouseEvent *even
|
|||||||
settings.setValue( QStringLiteral( "LayoutDesigner/lastItemHeight" ), item->sizeWithUnits().height() );
|
settings.setValue( QStringLiteral( "LayoutDesigner/lastItemHeight" ), item->sizeWithUnits().height() );
|
||||||
settings.setValue( QStringLiteral( "LayoutDesigner/lastSizeUnit" ), static_cast< int >( item->sizeWithUnits().units() ) );
|
settings.setValue( QStringLiteral( "LayoutDesigner/lastSizeUnit" ), static_cast< int >( item->sizeWithUnits().units() ) );
|
||||||
|
|
||||||
layout()->addItem( item );
|
layout()->addLayoutItem( item );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsLayoutViewToolAddItem::deactivate()
|
void QgsLayoutViewToolAddItem::deactivate()
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#include "qgstest.h"
|
#include "qgstest.h"
|
||||||
#include "qgsproject.h"
|
#include "qgsproject.h"
|
||||||
#include "qgslayoutitemmap.h"
|
#include "qgslayoutitemmap.h"
|
||||||
|
#include "qgslayoutitemshape.h"
|
||||||
|
#include "qgstestutils.h"
|
||||||
|
|
||||||
class TestQgsLayout: public QObject
|
class TestQgsLayout: public QObject
|
||||||
{
|
{
|
||||||
@ -36,6 +38,8 @@ class TestQgsLayout: public QObject
|
|||||||
void variablesEdited();
|
void variablesEdited();
|
||||||
void scope();
|
void scope();
|
||||||
void referenceMap();
|
void referenceMap();
|
||||||
|
void bounds();
|
||||||
|
void addItem();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString mReport;
|
QString mReport;
|
||||||
@ -246,6 +250,117 @@ void TestQgsLayout::referenceMap()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestQgsLayout::bounds()
|
||||||
|
{
|
||||||
|
//add some items to a layout
|
||||||
|
QgsProject p;
|
||||||
|
QgsLayout l( &p );
|
||||||
|
l.initializeDefaults();
|
||||||
|
|
||||||
|
QgsLayoutItemRectangularShape *shape1 = new QgsLayoutItemRectangularShape( &l );
|
||||||
|
shape1->attemptResize( QgsLayoutSize( 90, 50 ) );
|
||||||
|
shape1->attemptMove( QgsLayoutPoint( 90, 50 ) );
|
||||||
|
shape1->setItemRotation( 45 );
|
||||||
|
l.addLayoutItem( shape1 );
|
||||||
|
QgsLayoutItemRectangularShape *shape2 = new QgsLayoutItemRectangularShape( &l );
|
||||||
|
shape2->attemptResize( QgsLayoutSize( 110, 50 ) );
|
||||||
|
shape2->attemptMove( QgsLayoutPoint( 100, 150 ) );
|
||||||
|
l.addLayoutItem( shape2 );
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
QgsLayoutItemRectangularShape *shape3 = new QgsLayoutItemRectangularShape( &l );
|
||||||
|
l.addLayoutItem( shape3 );
|
||||||
|
shape3->setItemPosition( 210, 30, 50, 100, QgsComposerItem::UpperLeft, false, 2 );
|
||||||
|
QgsLayoutItemRectangularShape *shape4 = new QgsLayoutItemRectangularShape( &l );
|
||||||
|
l.addLayoutItem( shape4 );
|
||||||
|
shape4->setItemPosition( 10, 120, 50, 30, QgsComposerItem::UpperLeft, false, 2 );
|
||||||
|
shape4->setVisibility( false );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//check bounds
|
||||||
|
QRectF layoutBounds = l.layoutBounds( false );
|
||||||
|
#if 0 // correct values when 2nd page items are added back in
|
||||||
|
QGSCOMPARENEAR( layoutBounds.height(), 372.15, 0.01 );
|
||||||
|
QGSCOMPARENEAR( layoutBounds.width(), 301.00, 0.01 );
|
||||||
|
QGSCOMPARENEAR( layoutBounds.left(), -2, 0.01 );
|
||||||
|
QGSCOMPARENEAR( layoutBounds.top(), -2, 0.01 );
|
||||||
|
|
||||||
|
QRectF compositionBoundsNoPage = l.layoutBounds( true );
|
||||||
|
QGSCOMPARENEAR( compositionBoundsNoPage.height(), 320.36, 0.01 );
|
||||||
|
QGSCOMPARENEAR( compositionBoundsNoPage.width(), 250.30, 0.01 );
|
||||||
|
QGSCOMPARENEAR( compositionBoundsNoPage.left(), 9.85, 0.01 );
|
||||||
|
QGSCOMPARENEAR( compositionBoundsNoPage.top(), 49.79, 0.01 );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QGSCOMPARENEAR( layoutBounds.height(), 211.000000, 0.01 );
|
||||||
|
QGSCOMPARENEAR( layoutBounds.width(), 298.000000, 0.01 );
|
||||||
|
QGSCOMPARENEAR( layoutBounds.left(), -0.500000, 0.01 );
|
||||||
|
QGSCOMPARENEAR( layoutBounds.top(), -0.500000, 0.01 );
|
||||||
|
|
||||||
|
QRectF compositionBoundsNoPage = l.layoutBounds( true );
|
||||||
|
QGSCOMPARENEAR( compositionBoundsNoPage.height(), 175.704581, 0.01 );
|
||||||
|
QGSCOMPARENEAR( compositionBoundsNoPage.width(), 125.704581, 0.01 );
|
||||||
|
QGSCOMPARENEAR( compositionBoundsNoPage.left(), 84.795419, 0.01 );
|
||||||
|
QGSCOMPARENEAR( compositionBoundsNoPage.top(), 24.795419, 0.01 );
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
QRectF page1Bounds = composition->pageItemBounds( 0, true );
|
||||||
|
QGSCOMPARENEAR( page1Bounds.height(), 150.36, 0.01 );
|
||||||
|
QGSCOMPARENEAR( page1Bounds.width(), 155.72, 0.01 );
|
||||||
|
QGSCOMPARENEAR( page1Bounds.left(), 54.43, 0.01 );
|
||||||
|
QGSCOMPARENEAR( page1Bounds.top(), 49.79, 0.01 );
|
||||||
|
|
||||||
|
QRectF page2Bounds = composition->pageItemBounds( 1, true );
|
||||||
|
QGSCOMPARENEAR( page2Bounds.height(), 100.30, 0.01 );
|
||||||
|
QGSCOMPARENEAR( page2Bounds.width(), 50.30, 0.01 );
|
||||||
|
QGSCOMPARENEAR( page2Bounds.left(), 209.85, 0.01 );
|
||||||
|
QGSCOMPARENEAR( page2Bounds.top(), 249.85, 0.01 );
|
||||||
|
|
||||||
|
QRectF page2BoundsWithHidden = composition->pageItemBounds( 1, false );
|
||||||
|
QGSCOMPARENEAR( page2BoundsWithHidden.height(), 120.30, 0.01 );
|
||||||
|
QGSCOMPARENEAR( page2BoundsWithHidden.width(), 250.30, 0.01 );
|
||||||
|
QGSCOMPARENEAR( page2BoundsWithHidden.left(), 9.85, 0.01 );
|
||||||
|
QGSCOMPARENEAR( page2BoundsWithHidden.top(), 249.85, 0.01 );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestQgsLayout::addItem()
|
||||||
|
{
|
||||||
|
QgsProject p;
|
||||||
|
QgsLayout l( &p );
|
||||||
|
l.pageCollection()->deletePage( 0 );
|
||||||
|
|
||||||
|
QgsLayoutItemRectangularShape *shape1 = new QgsLayoutItemRectangularShape( &l );
|
||||||
|
shape1->attemptResize( QgsLayoutSize( 140, 70 ) );
|
||||||
|
shape1->attemptMove( QgsLayoutPoint( 90, 50 ) );
|
||||||
|
|
||||||
|
l.addLayoutItem( shape1 );
|
||||||
|
QVERIFY( l.items().contains( shape1 ) );
|
||||||
|
// bounds should be updated to include item
|
||||||
|
QGSCOMPARENEAR( l.sceneRect().left(), 89.5, 0.001 );
|
||||||
|
QGSCOMPARENEAR( l.sceneRect().top(), 49.5, 0.001 );
|
||||||
|
QGSCOMPARENEAR( l.sceneRect().width(), 141, 0.001 );
|
||||||
|
QGSCOMPARENEAR( l.sceneRect().height(), 71, 0.001 );
|
||||||
|
|
||||||
|
QgsLayoutItemRectangularShape *shape2 = new QgsLayoutItemRectangularShape( &l );
|
||||||
|
shape2->attemptResize( QgsLayoutSize( 240, 170 ) );
|
||||||
|
shape2->attemptMove( QgsLayoutPoint( 30, 20 ) );
|
||||||
|
|
||||||
|
// don't use addLayoutItem - we want to manually trigger a bounds update
|
||||||
|
l.addItem( shape2 );
|
||||||
|
QGSCOMPARENEAR( l.sceneRect().left(), 89.5, 0.001 );
|
||||||
|
QGSCOMPARENEAR( l.sceneRect().top(), 49.5, 0.001 );
|
||||||
|
QGSCOMPARENEAR( l.sceneRect().width(), 141, 0.001 );
|
||||||
|
QGSCOMPARENEAR( l.sceneRect().height(), 71, 0.001 );
|
||||||
|
|
||||||
|
l.updateBounds();
|
||||||
|
// bounds should be updated to include item
|
||||||
|
QGSCOMPARENEAR( l.sceneRect().left(), 29.5, 0.001 );
|
||||||
|
QGSCOMPARENEAR( l.sceneRect().top(), 19.5, 0.001 );
|
||||||
|
QGSCOMPARENEAR( l.sceneRect().width(), 241, 0.001 );
|
||||||
|
QGSCOMPARENEAR( l.sceneRect().height(), 171, 0.001 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QGSTEST_MAIN( TestQgsLayout )
|
QGSTEST_MAIN( TestQgsLayout )
|
||||||
#include "testqgslayout.moc"
|
#include "testqgslayout.moc"
|
||||||
|
@ -15,7 +15,14 @@ __revision__ = '$Format:%H$'
|
|||||||
import qgis # NOQA
|
import qgis # NOQA
|
||||||
import sip
|
import sip
|
||||||
|
|
||||||
from qgis.core import QgsUnitTypes, QgsLayout, QgsLayoutItemPage, QgsProject, QgsLayoutPageCollection, QgsSimpleFillSymbolLayer, QgsFillSymbol
|
from qgis.core import (QgsUnitTypes,
|
||||||
|
QgsLayout,
|
||||||
|
QgsLayoutItemPage,
|
||||||
|
QgsLayoutSize,
|
||||||
|
QgsProject,
|
||||||
|
QgsLayoutPageCollection,
|
||||||
|
QgsSimpleFillSymbolLayer,
|
||||||
|
QgsFillSymbol)
|
||||||
from qgis.PyQt.QtCore import Qt, QCoreApplication, QEvent
|
from qgis.PyQt.QtCore import Qt, QCoreApplication, QEvent
|
||||||
from qgis.testing import start_app, unittest
|
from qgis.testing import start_app, unittest
|
||||||
|
|
||||||
@ -120,6 +127,86 @@ class TestQgsLayoutPageCollection(unittest.TestCase):
|
|||||||
self.assertTrue(sip.isdeleted(page))
|
self.assertTrue(sip.isdeleted(page))
|
||||||
self.assertTrue(sip.isdeleted(page2))
|
self.assertTrue(sip.isdeleted(page2))
|
||||||
|
|
||||||
|
def testMaxPageWidth(self):
|
||||||
|
"""
|
||||||
|
Test calculating maximum page width
|
||||||
|
"""
|
||||||
|
p = QgsProject()
|
||||||
|
l = QgsLayout(p)
|
||||||
|
collection = l.pageCollection()
|
||||||
|
|
||||||
|
# add a page
|
||||||
|
page = QgsLayoutItemPage(l)
|
||||||
|
page.setPageSize('A4')
|
||||||
|
collection.addPage(page)
|
||||||
|
self.assertEqual(collection.maximumPageWidth(), 210.0)
|
||||||
|
|
||||||
|
# add a second page
|
||||||
|
page2 = QgsLayoutItemPage(l)
|
||||||
|
page2.setPageSize('A3')
|
||||||
|
collection.addPage(page2)
|
||||||
|
self.assertEqual(collection.maximumPageWidth(), 297.0)
|
||||||
|
|
||||||
|
# add a page with other units
|
||||||
|
page3 = QgsLayoutItemPage(l)
|
||||||
|
page3.setPageSize(QgsLayoutSize(100, 100, QgsUnitTypes.LayoutMeters))
|
||||||
|
collection.addPage(page3)
|
||||||
|
self.assertEqual(collection.maximumPageWidth(), 100000.0)
|
||||||
|
|
||||||
|
def testReflow(self):
|
||||||
|
"""
|
||||||
|
Test reflowing pages
|
||||||
|
"""
|
||||||
|
p = QgsProject()
|
||||||
|
l = QgsLayout(p)
|
||||||
|
collection = l.pageCollection()
|
||||||
|
|
||||||
|
#add a page
|
||||||
|
page = QgsLayoutItemPage(l)
|
||||||
|
page.setPageSize('A4')
|
||||||
|
collection.addPage(page)
|
||||||
|
|
||||||
|
#should be positioned at origin
|
||||||
|
self.assertEqual(page.pos().x(), 0)
|
||||||
|
self.assertEqual(page.pos().y(), 0)
|
||||||
|
|
||||||
|
#second page
|
||||||
|
page2 = QgsLayoutItemPage(l)
|
||||||
|
page2.setPageSize('A5')
|
||||||
|
collection.addPage(page2)
|
||||||
|
|
||||||
|
self.assertEqual(page.pos().x(), 0)
|
||||||
|
self.assertEqual(page.pos().y(), 0)
|
||||||
|
self.assertEqual(page2.pos().x(), 0)
|
||||||
|
self.assertEqual(page2.pos().y(), 307)
|
||||||
|
|
||||||
|
#third page, slotted in middle
|
||||||
|
page3 = QgsLayoutItemPage(l)
|
||||||
|
page3.setPageSize('A3')
|
||||||
|
collection.insertPage(page3, 1)
|
||||||
|
|
||||||
|
self.assertEqual(page.pos().x(), 0)
|
||||||
|
self.assertEqual(page.pos().y(), 0)
|
||||||
|
self.assertEqual(page2.pos().x(), 0)
|
||||||
|
self.assertEqual(page2.pos().y(), 737)
|
||||||
|
self.assertEqual(page3.pos().x(), 0)
|
||||||
|
self.assertEqual(page3.pos().y(), 307)
|
||||||
|
|
||||||
|
page.setPageSize(QgsLayoutSize(100, 120))
|
||||||
|
# no update until reflow is called
|
||||||
|
self.assertEqual(page.pos().x(), 0)
|
||||||
|
self.assertEqual(page.pos().y(), 0)
|
||||||
|
self.assertEqual(page2.pos().x(), 0)
|
||||||
|
self.assertEqual(page2.pos().y(), 737)
|
||||||
|
self.assertEqual(page3.pos().x(), 0)
|
||||||
|
self.assertEqual(page3.pos().y(), 307)
|
||||||
|
collection.reflow()
|
||||||
|
self.assertEqual(page.pos().x(), 0)
|
||||||
|
self.assertEqual(page.pos().y(), 0)
|
||||||
|
self.assertEqual(page2.pos().x(), 0)
|
||||||
|
self.assertEqual(page2.pos().y(), 560)
|
||||||
|
self.assertEqual(page3.pos().x(), 0)
|
||||||
|
self.assertEqual(page3.pos().y(), 130)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user