27#include "moc_qgslayoutpagecollection.cpp"
34 createDefaultPageStyleSymbol();
39 const auto constMPages = mPages;
42 mLayout->removeItem(
page );
56 page->setPageStyleSymbol( symbol->
clone() );
63 return mPageStyleSymbol.get();
68 mPreviousItemPositions.clear();
69 QList< QgsLayoutItem * > items;
70 mLayout->layoutItems( items );
77 mPreviousItemPositions.insert( item->uuid(), qMakePair( item->page(), item->pagePositionWithUnits() ) );
83 for (
auto it = mPreviousItemPositions.constBegin(); it != mPreviousItemPositions.constEnd(); ++it )
85 const QString key { it.key() };
88 if ( !mBlockUndoCommands )
89 item->beginCommand( QString() );
91 item->attemptMove( it.value().second,
true,
false, it.value().first );
94 if ( mLayout->itemByUuid( key ) )
96 if ( !mBlockUndoCommands )
101 item->cancelCommand();
105 mPreviousItemPositions.clear();
112 const auto constMPages = mPages;
115 page->attemptMove( p );
119 mLayout->guides().update();
120 mLayout->updateBounds();
129 maxWidth = std::max( maxWidth, mLayout->convertToLayoutUnits(
page->pageSize() ).width() );
140 QSizeF pageSize = mLayout->convertToLayoutUnits(
page->pageSize() );
141 double area = pageSize.width() * pageSize.height();
142 if ( area > maxArea )
156 QSizeF pageSize = mLayout->convertToLayoutUnits(
page->pageSize() );
157 if ( !size.isValid() )
162 || !
qgsDoubleNear( pageSize.height(), size.height(), 0.01 ) )
172 double startNextPageY = 0;
173 const auto constMPages = mPages;
177 if ( startNextPageY > point.y() )
189 if ( mPages.empty() )
193 double startNextPageY = 0;
194 const auto constMPages = mPages;
198 if ( startNextPageY >= point.y() )
203 if ( startNextPageY >= point.y() )
209 double lastPageHeight = mPages.last()->rect().height();
210 while ( startNextPageY < point.y() )
213 if ( startNextPageY >= point.y() )
223 const QList< QGraphicsItem * > items = mLayout->items( point );
224 for ( QGraphicsItem *item : items )
229 if (
page->mapToScene(
page->rect() ).boundingRect().contains( point ) )
238 QPointF layoutUnitsPos = mLayout->convertToLayoutUnits( position );
239 if (
page > 0 &&
page < mPages.count() )
241 layoutUnitsPos.ry() += mPages.at(
page )->pos().y();
243 return layoutUnitsPos;
249 if (
page > 0 &&
page < mPages.count() )
251 vDelta = mLayout->convertFromLayoutUnits( mPages.at(
page )->pos().y(), position.
units() ).length();
259 double startCurrentPageY = 0;
260 double startNextPageY = 0;
262 const auto constMPages = mPages;
265 startCurrentPageY = startNextPageY;
267 if ( startNextPageY > position.y() )
282 y = position.y() - startCurrentPageY;
284 return QPointF( position.x(), y );
300 QRectF bounds = mLayout->layoutBounds(
true, 0.0 );
301 if ( bounds.isEmpty() )
304 if ( !mBlockUndoCommands )
305 mLayout->undoStack()->beginCommand(
this, tr(
"Resize to Contents" ) );
312 if ( mPages.empty() )
314 auto page = std::make_unique< QgsLayoutItemPage >( mLayout );
325 bounds.setWidth( bounds.width() + marginLeft + marginRight );
326 bounds.setHeight( bounds.height() + marginTop + marginBottom );
328 QgsLayoutSize newPageSize = mLayout->convertFromLayoutUnits( bounds.size(), mLayout->units() );
329 page->setPageSize( newPageSize );
334 double diffX = marginLeft - bounds.left();
335 double diffY = marginTop - bounds.top();
337 const QList<QGraphicsItem *> itemList = mLayout->items();
338 for ( QGraphicsItem *item : itemList )
345 layoutItem->beginCommand( tr(
"Move Item" ) );
346 layoutItem->attemptMoveBy( diffX, diffY );
347 layoutItem->endCommand();
353 mLayout->undoStack()->beginCommand( &mLayout->guides(), tr(
"Move Guides" ) );
354 const QList< QgsLayoutGuide * > verticalGuides = mLayout->guides().guides( Qt::Vertical );
357 guide->setLayoutPosition( guide->layoutPosition() + diffX );
359 const QList< QgsLayoutGuide * > horizontalGuides = mLayout->guides().guides( Qt::Horizontal );
362 guide->setLayoutPosition( guide->layoutPosition() + diffY );
364 mLayout->undoStack()->endCommand();
366 if ( !mBlockUndoCommands )
367 mLayout->undoStack()->endCommand();
372 QDomElement element = document.createElement( QStringLiteral(
"PageCollection" ) );
375 element.appendChild( pageStyleElem );
379 page->writeXml( element, document, context );
382 mGuideCollection->writeXml( element, document, context );
384 parentElement.appendChild( element );
390 QDomElement element = e;
391 if ( element.nodeName() != QLatin1String(
"PageCollection" ) )
393 element = element.firstChildElement( QStringLiteral(
"PageCollection" ) );
396 if ( element.nodeName() != QLatin1String(
"PageCollection" ) )
401 mBlockUndoCommands =
true;
407 mLayout->removeItem(
page );
413 QDomElement pageStyleSymbolElem = element.firstChildElement( QStringLiteral(
"symbol" ) );
414 if ( !pageStyleSymbolElem.isNull() )
419 QDomNodeList pageList = element.elementsByTagName( QStringLiteral(
"LayoutItem" ) );
420 for (
int i = 0; i < pageList.size(); ++i )
422 QDomElement pageElement = pageList.at( i ).toElement();
423 auto page = std::make_unique<QgsLayoutItemPage>( mLayout );
424 if ( mPageStyleSymbol )
425 page->setPageStyleSymbol( mPageStyleSymbol->clone() );
426 page->readXml( pageElement, document, context );
427 page->finalizeRestoreFromXml();
428 mPages.append(
page.get() );
429 mLayout->addItem(
page.release() );
434 mGuideCollection->readXml( element, document, context );
436 mBlockUndoCommands =
false;
442 return *mGuideCollection;
447 return *mGuideCollection;
453 if ( !referencePage )
458 mLayout->undoStack()->beginCommand(
this, tr(
"Apply page properties" ) );
459 mBlockUndoCommands =
true;
463 if (
page == referencePage )
471 mLayout->undoStack()->endCommand();
472 mBlockUndoCommands =
false;
478 const auto constMPages = mPages;
497 return mPages.count();
512 return mPages.indexOf(
page );
517 QList<QgsLayoutItemPage *>
pages;
518 const auto constMPages = mPages;
521 if (
page->mapToScene(
page->rect() ).boundingRect().intersects( region ) )
531 const auto constMPages = mPages;
534 if (
page->mapToScene(
page->rect() ).boundingRect().intersects( region ) )
544 const QList<QgsLayoutItem *> items = mLayout->pageCollection()->itemsOnPage(
page );
562 QList<QgsLayoutItem *> itemList;
563 const QList<QGraphicsItem *> graphicsItemList = mLayout->items();
564 itemList.reserve( graphicsItemList.size() );
565 for ( QGraphicsItem *graphicsItem : graphicsItemList )
570 itemList.push_back( item );
578 if (
page >= mPages.count() ||
page < 0 )
589 QList<QgsLayoutFrame *> frames;
593 if ( frame->hidePageIfEmpty() && frame->isEmpty() )
604 if ( !mBlockUndoCommands )
605 mLayout->undoStack()->beginCommand(
this, tr(
"Add Page" ) );
606 mPages.append(
page );
607 mLayout->addItem(
page );
609 if ( !mBlockUndoCommands )
610 mLayout->undoStack()->endCommand();
615 if ( mPages.empty() )
619 auto newPage = std::make_unique< QgsLayoutItemPage >( mLayout );
622 return mPages.at( mPages.count() - 1 );
627 if ( !mBlockUndoCommands )
629 mLayout->undoStack()->beginMacro( tr(
"Add Page" ) );
630 mLayout->undoStack()->beginCommand(
this, tr(
"Add Page" ) );
633 if ( beforePage < 0 )
637 if ( beforePage >= mPages.count() )
639 mPages.append(
page );
643 mPages.insert( beforePage,
page );
645 mLayout->addItem(
page );
649 for (
auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it )
651 if ( it.value().first < beforePage )
654 it.value().first = it.value().first + 1;
658 if ( ! mBlockUndoCommands )
660 mLayout->undoStack()->endCommand();
661 mLayout->undoStack()->endMacro();
670 if ( !mBlockUndoCommands )
672 mLayout->undoStack()->beginMacro( tr(
"Remove Page" ) );
673 mLayout->undoStack()->beginCommand(
this, tr(
"Remove Page" ) );
678 mLayout->removeItem(
page );
683 for (
auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it )
688 it.value().first = it.value().first - 1;
692 if ( ! mBlockUndoCommands )
694 mLayout->undoStack()->endCommand();
695 mLayout->undoStack()->endMacro();
701 if ( !mPages.contains(
page ) )
704 if ( !mBlockUndoCommands )
706 mLayout->undoStack()->beginMacro( tr(
"Remove Page" ) );
707 mLayout->undoStack()->beginCommand(
this, tr(
"Remove Page" ) );
709 int pageIndex = mPages.indexOf(
page );
712 mPages.removeAll(
page );
716 mLayout->removeItem(
page );
720 for (
auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it )
722 if ( it.value().first <= pageIndex )
725 it.value().first = it.value().first - 1;
729 if ( !mBlockUndoCommands )
731 mLayout->undoStack()->endCommand();
732 mLayout->undoStack()->endMacro();
738 if ( !mBlockUndoCommands )
740 mLayout->undoStack()->beginMacro( tr(
"Remove Pages" ) );
741 mLayout->undoStack()->beginCommand(
this, tr(
"Remove Pages" ) );
743 for (
int i = mPages.count() - 1; i >= 0; --i )
746 mPages.takeAt( i )->deleteLater();
749 if ( !mBlockUndoCommands )
751 mLayout->undoStack()->endCommand();
752 mLayout->undoStack()->endMacro();
758 mPages.removeAll(
page );
762void QgsLayoutPageCollection::createDefaultPageStyleSymbol()
764 QVariantMap properties;
765 properties.insert( QStringLiteral(
"color" ), QStringLiteral(
"white" ) );
766 properties.insert( QStringLiteral(
"style" ), QStringLiteral(
"solid" ) );
767 properties.insert( QStringLiteral(
"style_border" ), QStringLiteral(
"no" ) );
768 properties.insert( QStringLiteral(
"joinstyle" ), QStringLiteral(
"miter" ) );
LayoutUnit
Layout measurement units.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
static std::unique_ptr< QgsFillSymbol > createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
QgsFillSymbol * clone() const override
Returns a deep copy of this symbol.
Base class for frame items, which form a layout multiframe item.
Stores and manages the snap guides used by a layout.
Contains the configuration for a single snap guide used by a layout.
Item representing the paper in a layout.
QgsLayoutSize pageSize() const
Returns the size of the page.
const QgsFillSymbol * pageStyleSymbol() const
Returns the symbol to use for drawing the page background.
Base class for graphical items within a QgsLayout.
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
int page() const
Returns the page the item is currently on, with the first page returning 0.
bool shouldDrawItem() const
Returns whether the item should be drawn in the current context.
Provides a method of storing measurements for use in QGIS layouts using a variety of different measur...
QList< int > visiblePageNumbers(const QRectF ®ion) const
Returns a list of the page numbers which are visible within the specified region (in layout coordinat...
void deletePage(int pageNumber)
Deletes a page from the collection.
bool pageIsEmpty(int page) const
Returns whether a given page index is empty, ie, it contains no items except for the background paper...
bool readXml(const QDomElement &collectionElement, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets the collection's state from a DOM element.
QPointF pagePositionToLayoutPosition(int page, const QgsLayoutPoint &position) const
Converts a position on a page to an absolute position in layout coordinates.
void addPage(QgsLayoutItemPage *page)
Adds a page to the collection.
void changed()
Emitted when pages are added or removed from the collection.
int pageNumberForPoint(QPointF point) const
Returns the page number corresponding to a point in the layout (in layout units).
QgsLayoutItemPage * takePage(QgsLayoutItemPage *page)
Takes a page from the collection, returning ownership of the page to the caller.
QList< QgsLayoutItemPage * > visiblePages(const QRectF ®ion) const
Returns a list of the pages which are visible within the specified region (in layout coordinates).
Q_DECL_DEPRECATED const QgsFillSymbol * pageStyleSymbol() const
Returns the symbol to use for drawing pages in the collection.
QgsLayoutPageCollection(QgsLayout *layout)
Constructor for QgsLayoutItemPage, with the specified parent layout.
void insertPage(QgsLayoutItemPage *page, int beforePage)
Inserts a page into a specific position in the collection.
void setPageStyleSymbol(QgsFillSymbol *symbol)
Sets the symbol to use for drawing pages in the collection.
void reflow()
Forces the page collection to reflow the arrangement of pages, e.g.
QgsLayoutItemPage * extendByNewPage()
Adds a new page to the end of the collection.
bool writeXml(QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores the collection's state in a DOM element.
QgsLayout * layout() override
Returns the layout the object belongs to.
double spaceBetweenPages() const
Returns the space between pages, in layout units.
QgsLayoutGuideCollection & guides()
Returns a reference to the collection's guide collection, which manages page snap guides.
int predictPageNumberForPoint(QPointF point) const
Returns the theoretical page number corresponding to a point in the layout (in layout units),...
void endPageSizeChange()
Should be called after changing any page item sizes, and preceded by a call to beginPageSizeChange().
QList< QgsLayoutItem * > itemsOnPage(int page) const
Returns a list of layout items on the specified page index.
QList< QgsLayoutItemPage * > pages()
Returns a list of pages in the collection.
void pageAboutToBeRemoved(int pageNumber)
Emitted just before a page is removed from the collection.
int pageCount() const
Returns the number of pages in the collection.
~QgsLayoutPageCollection() override
void applyPropertiesToAllOtherPages(int sourcePage)
Apply the source page properties (size & background color) to all other pages.
double maximumPageWidth() const
Returns the maximum width of pages in the collection.
QPointF positionOnPage(QPointF point) const
Returns the position within a page of a point in the layout (in layout units).
void resizeToContents(const QgsMargins &margins, Qgis::LayoutUnit marginUnits)
Resizes the layout to a single page which fits the current contents of the layout.
bool shouldExportPage(int page) const
Returns whether the specified page number should be included in exports of the layouts.
QgsLayoutItemPage * page(int pageNumber)
Returns a specific page (by pageNumber) from the collection.
void redraw()
Triggers a redraw for all pages.
QgsLayoutPoint pagePositionToAbsolute(int page, const QgsLayoutPoint &position) const
Converts a position on a page to an absolute position in (maintaining the units from the input positi...
double pageShadowWidth() const
Returns the size of the page shadow, in layout units.
void clear()
Removes all pages from the collection.
int pageNumber(QgsLayoutItemPage *page) const
Returns the page number for the specified page, or -1 if the page is not contained in the collection.
bool hasUniformPageSizes() const
Returns true if the layout has uniform page sizes, e.g.
void beginPageSizeChange()
Should be called before changing any page item sizes, and followed by a call to endPageSizeChange().
QgsLayoutItemPage * pageAtPoint(QPointF point) const
Returns the page at a specified point (in layout coordinates).
QSizeF maximumPageSize() const
Returns the maximum size of any page in the collection, by area.
Provides a method of storing points, consisting of an x and y coordinate, for use in QGIS layouts.
double x() const
Returns x coordinate of point.
double y() const
Returns y coordinate of point.
Qgis::LayoutUnit units() const
Returns the units for the point.
void setY(const double y)
Sets y coordinate of point.
Provides a method of storing sizes, consisting of a width and height, for use in QGIS layouts.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Defines the four margins of a rectangle.
double top() const
Returns the top margin.
double right() const
Returns the right margin.
double bottom() const
Returns the bottom margin.
double left() const
Returns the left margin.
A container for the context for various read/write operations on objects.
static std::unique_ptr< QgsSymbol > loadSymbol(const QDomElement &element, const QgsReadWriteContext &context)
Attempts to load a symbol from a DOM element.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).