Skip to content

Commit

Permalink
Fix a number of multiframe methods
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Nov 24, 2017
1 parent ee45ec9 commit 0e71505
Show file tree
Hide file tree
Showing 6 changed files with 384 additions and 32 deletions.
45 changes: 45 additions & 0 deletions python/core/layout/qgslayoutpagecollection.sip
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,19 @@ class QgsLayoutPageCollection : QObject, QgsLayoutSerializableObject
:rtype: list of int
%End

bool pageIsEmpty( int page ) const;
%Docstring
Returns whether a given ``page`` index is empty, ie, it contains no items except for the background
paper item.
:rtype: bool
%End

QList< QgsLayoutItem *> itemsOnPage( int page ) const;
%Docstring
Returns a list of layout items on the specified ``page`` index.
:rtype: list of QgsLayoutItem
%End

void addPage( QgsLayoutItemPage *page /Transfer/ );
%Docstring
Adds a ``page`` to the collection. Ownership of the ``page`` is transferred
Expand All @@ -89,9 +102,22 @@ class QgsLayoutPageCollection : QObject, QgsLayoutSerializableObject

Calling addPage() automatically triggers a reflow() of pages.

.. seealso:: extendByNewPage()
.. seealso:: insertPage()
%End

QgsLayoutItemPage *extendByNewPage();
%Docstring
Adds a new page to the end of the collection. This page will inherit the
same size as the current final page in the collection.

The newly created page will be returned.

.. seealso:: addPage()
.. seealso:: insertPage()
:rtype: QgsLayoutItemPage
%End

void insertPage( QgsLayoutItemPage *page /Transfer/, int beforePage );
%Docstring
Inserts a ``page`` into a specific position in the collection.
Expand Down Expand Up @@ -175,6 +201,25 @@ class QgsLayoutPageCollection : QObject, QgsLayoutSerializableObject
it does not consider x coordinates and vertical coordinates before the first page or
after the last page will still return the nearest page.

.. seealso:: predicatePageNumberForPoint()
.. seealso:: pageAtPoint()
.. seealso:: positionOnPage()
:rtype: int
%End

int predictPageNumberForPoint( QPointF point ) const;
%Docstring
Returns the theoretical page number corresponding to a ``point`` in the layout (in layout units),
assuming that enough pages exist in the layout to cover that point.

If there are insufficient pages currently in the layout, this method will assume that extra
"imaginary" pages have been added at the end of the layout until that point is reached. These
imaginary pages will inherit the size of the existing final page in the layout.

Page numbers in collections begin at 0 - so a page number of 0 indicates the
first page.

.. seealso:: pageNumberForPoint()
.. seealso:: pageAtPoint()
.. seealso:: positionOnPage()
:rtype: int
Expand Down
69 changes: 37 additions & 32 deletions src/core/layout/qgslayoutmultiframe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ QgsLayoutMultiFrame::QgsLayoutMultiFrame( QgsLayout *layout )
{
mLayout->addMultiFrame( this );

#if 0 //TODO
connect( mLayout, &QgsLayout::nPagesChanged, this, &QgsLayoutMultiFrame::handlePageChange );
#endif
connect( mLayout->pageCollection(), &QgsLayoutPageCollection::changed, this, &QgsLayoutMultiFrame::handlePageChange );
}

QgsLayoutMultiFrame::~QgsLayoutMultiFrame()
Expand Down Expand Up @@ -86,7 +84,6 @@ QList<QgsLayoutFrame *> QgsLayoutMultiFrame::frames() const

void QgsLayoutMultiFrame::recalculateFrameSizes()
{
#if 0 //TODO
if ( mFrameItems.empty() )
{
return;
Expand Down Expand Up @@ -143,38 +140,49 @@ void QgsLayoutMultiFrame::recalculateFrameSizes()
while ( ( mResizeMode == RepeatOnEveryPage ) || currentY < totalHeight )
{
//find out on which page the lower left point of the last frame is
int page = std::floor( ( currentItem->pos().y() + currentItem->rect().height() ) / ( mLayout->paperHeight() + mComposition->spaceBetweenPages() ) ) + 1;
int page = mLayout->pageCollection()->predictPageNumberForPoint( QPointF( 0, currentItem->pos().y() + currentItem->rect().height() ) );

if ( mResizeMode == RepeatOnEveryPage )
{
if ( page >= mComposition->numPages() )
if ( page >= mLayout->pageCollection()->pageCount() )
{
break;
}
}
else
{
//add an extra page if required
if ( mComposition->numPages() < ( page + 1 ) )
//add new pages if required
for ( int p = mLayout->pageCollection()->pageCount() - 1 ; p < page; ++p )
{
mComposition->setNumPages( page + 1 );
mLayout->pageCollection()->extendByNewPage();
}
}

double currentPageHeight = mLayout->pageCollection()->page( page )->rect().height();

double frameHeight = 0;
if ( mResizeMode == RepeatUntilFinished || mResizeMode == RepeatOnEveryPage )
switch ( mResizeMode )
{
frameHeight = currentItem->rect().height();
}
else //mResizeMode == ExtendToNextPage
{
frameHeight = ( currentY + mComposition->paperHeight() ) > totalHeight ? totalHeight - currentY : mComposition->paperHeight();
case RepeatUntilFinished:
case RepeatOnEveryPage:
{
frameHeight = currentItem->rect().height();
break;
}
case ExtendToNextPage:
{
frameHeight = ( currentY + currentPageHeight ) > totalHeight ? totalHeight - currentY : currentPageHeight;
break;
}

case UseExistingFrames:
break;
}

double newFrameY = page * ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
double newFrameY = mLayout->pageCollection()->page( page )->pos().y();
if ( mResizeMode == RepeatUntilFinished || mResizeMode == RepeatOnEveryPage )
{
newFrameY += currentItem->pos().y() - ( page - 1 ) * ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
newFrameY += currentItem->pagePos().y();
}

//create new frame
Expand All @@ -197,7 +205,6 @@ void QgsLayoutMultiFrame::recalculateFrameSizes()
currentItem = newFrame;
}
}
#endif
}

void QgsLayoutMultiFrame::recalculateFrameRects()
Expand Down Expand Up @@ -281,7 +288,6 @@ void QgsLayoutMultiFrame::handleFrameRemoval()

void QgsLayoutMultiFrame::handlePageChange()
{
#if 0 //TODO
if ( mLayout->pageCollection()->pageCount() < 1 )
{
return;
Expand All @@ -296,30 +302,31 @@ void QgsLayoutMultiFrame::handlePageChange()
for ( int i = mFrameItems.size() - 1; i >= 0; --i )
{
QgsLayoutFrame *frame = mFrameItems.at( i );
int page = frame->pos().y() / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
if ( page > ( mComposition->numPages() - 1 ) )
int page = mLayout->pageCollection()->predictPageNumberForPoint( frame->pos() );
if ( page >= mLayout->pageCollection()->pageCount() )
{
removeFrame( i );
}
}

//page number of the last item
QgsLayoutFrame *lastFrame = mFrameItems.last();
int lastItemPage = lastFrame->pos().y() / ( mLayout->paperHeight() + mLayout->spaceBetweenPages() );
int lastItemPage = mLayout->pageCollection()->predictPageNumberForPoint( lastFrame->pos() );

for ( int i = lastItemPage + 1; i < mLayout->pageCollection()->pageCount(); ++i )
{
//copy last frame to current page
QgsLayoutFrame *newFrame = new QgsLayoutFrame( mLayout, this, lastFrame->pos().x(),
lastFrame->pos().y() + mLayout->paperHeight() + mLayout->spaceBetweenPages(),
lastFrame->rect().width(), lastFrame->rect().height() );
addFrame( newFrame, false );
lastFrame = newFrame;
std::unique_ptr< QgsLayoutFrame > newFrame = qgis::make_unique< QgsLayoutFrame >( mLayout, this );

newFrame->attemptSetSceneRect( QRectF( lastFrame->pos().x(),
mLayout->pageCollection()->page( i )->pos().y() + lastFrame->pagePos().y(),
lastFrame->rect().width(), lastFrame->rect().height() ) );
lastFrame = newFrame.get();
addFrame( newFrame.release(), false );
}

recalculateFrameSizes();
update();
#endif
}

void QgsLayoutMultiFrame::removeFrame( int i, const bool removeEmptyPages )
Expand All @@ -333,18 +340,16 @@ void QgsLayoutMultiFrame::removeFrame( int i, const bool removeEmptyPages )
if ( mLayout )
{
mIsRecalculatingSize = true;
#if 0 //TODO
int pageNumber = frameItem->page();
//remove item, but don't create undo command
#if 0 //TODO - block undo commands
#endif
mLayout->removeLayoutItem( frameItem );
//if frame was the only item on the page, remove the page
if ( removeEmptyPages && mComposition->pageIsEmpty( pageNumber ) )
if ( removeEmptyPages && mLayout->pageCollection()->pageIsEmpty( pageNumber ) )
{
mComposition->setNumPages( mComposition->numPages() - 1 );
mLayout->pageCollection()->deletePage( pageNumber );
}
#endif
mIsRecalculatingSize = false;
}
mFrameItems.removeAt( i );
Expand Down
78 changes: 78 additions & 0 deletions src/core/layout/qgslayoutpagecollection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,36 @@ int QgsLayoutPageCollection::pageNumberForPoint( QPointF point ) const
return pageNumber;
}

int QgsLayoutPageCollection::predictPageNumberForPoint( QPointF point ) const
{
int pageNumber = 0;
double startNextPageY = 0;
Q_FOREACH ( QgsLayoutItemPage *page, mPages )
{
startNextPageY += page->rect().height() + spaceBetweenPages();
if ( startNextPageY >= point.y() )
break;
pageNumber++;
}

if ( startNextPageY >= point.y() )
{
// found an existing page
return pageNumber;
}

double lastPageHeight = mPages.last()->rect().height();
while ( startNextPageY < point.y() )
{
startNextPageY += lastPageHeight + spaceBetweenPages();
if ( startNextPageY >= point.y() )
break;
pageNumber++;
}

return pageNumber;
}

QgsLayoutItemPage *QgsLayoutPageCollection::pageAtPoint( QPointF point ) const
{
Q_FOREACH ( QGraphicsItem *item, mLayout->items( point ) )
Expand Down Expand Up @@ -301,6 +331,40 @@ QList<int> QgsLayoutPageCollection::visiblePageNumbers( QRectF region ) const
return pages;
}

bool QgsLayoutPageCollection::pageIsEmpty( int page ) const
{
//get all items on page
const QList<QgsLayoutItem *> items = mLayout->pageCollection()->itemsOnPage( page );

//loop through and check for non-paper items
for ( QgsLayoutItem *item : items )
{
//is item a paper item?
if ( item->type() != QgsLayoutItemRegistry::LayoutPage )
{
//item is not a paper item, so we have other items on the page
return false;
}
}
//no non-paper items
return true;
}

QList<QgsLayoutItem *> QgsLayoutPageCollection::itemsOnPage( int page ) const
{
QList<QgsLayoutItem *> itemList;
const QList<QGraphicsItem *> graphicsItemList = mLayout->items();
for ( QGraphicsItem *graphicsItem : graphicsItemList )
{
QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
if ( item && item->page() == page )
{
itemList.push_back( item );
}
}
return itemList;
}

void QgsLayoutPageCollection::addPage( QgsLayoutItemPage *page )
{
if ( !mBlockUndoCommands )
Expand All @@ -312,6 +376,18 @@ void QgsLayoutPageCollection::addPage( QgsLayoutItemPage *page )
mLayout->undoStack()->endCommand();
}

QgsLayoutItemPage *QgsLayoutPageCollection::extendByNewPage()
{
if ( mPages.empty() )
return nullptr;

QgsLayoutItemPage *lastPage = mPages.at( mPages.count() - 1 );
std::unique_ptr< QgsLayoutItemPage > newPage = qgis::make_unique< QgsLayoutItemPage >( mLayout );
newPage->attemptResize( lastPage->sizeWithUnits() );
addPage( newPage.release() );
return mPages.at( mPages.count() - 1 );
}

void QgsLayoutPageCollection::insertPage( QgsLayoutItemPage *page, int beforePage )
{
if ( !mBlockUndoCommands )
Expand Down Expand Up @@ -392,3 +468,5 @@ void QgsLayoutPageCollection::createDefaultPageStyleSymbol()
properties.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
mPageStyleSymbol.reset( QgsFillSymbol::createSimple( properties ) );
}


Loading

0 comments on commit 0e71505

Please sign in to comment.