29#include "moc_qgslayoutpagecollection.cpp"
31using namespace Qt::StringLiterals;
38 createDefaultPageStyleSymbol();
43 const auto constMPages = mPages;
46 mLayout->removeItem(
page );
60 page->setPageStyleSymbol( symbol->
clone() );
67 return mPageStyleSymbol.get();
72 mPreviousItemPositions.clear();
73 QList< QgsLayoutItem * > items;
74 mLayout->layoutItems( items );
81 mPreviousItemPositions.insert( item->uuid(), qMakePair( item->page(), item->pagePositionWithUnits() ) );
87 for (
auto it = mPreviousItemPositions.constBegin(); it != mPreviousItemPositions.constEnd(); ++it )
89 const QString key { it.key() };
92 if ( !mBlockUndoCommands )
93 item->beginCommand( QString() );
95 item->attemptMove( it.value().second,
true,
false, it.value().first );
98 if ( mLayout->itemByUuid( key ) )
100 if ( !mBlockUndoCommands )
105 item->cancelCommand();
109 mPreviousItemPositions.clear();
116 const auto constMPages = mPages;
119 page->attemptMove( p );
123 mLayout->guides().update();
124 mLayout->updateBounds();
133 maxWidth = std::max( maxWidth, mLayout->convertToLayoutUnits(
page->pageSize() ).width() );
144 QSizeF pageSize = mLayout->convertToLayoutUnits(
page->pageSize() );
145 double area = pageSize.width() * pageSize.height();
146 if ( area > maxArea )
160 QSizeF pageSize = mLayout->convertToLayoutUnits(
page->pageSize() );
161 if ( !size.isValid() )
166 || !
qgsDoubleNear( pageSize.height(), size.height(), 0.01 ) )
176 double startNextPageY = 0;
177 const auto constMPages = mPages;
181 if ( startNextPageY > point.y() )
193 if ( mPages.empty() )
197 double startNextPageY = 0;
198 const auto constMPages = mPages;
202 if ( startNextPageY >= point.y() )
207 if ( startNextPageY >= point.y() )
213 double lastPageHeight = mPages.last()->rect().height();
214 while ( startNextPageY < point.y() )
217 if ( startNextPageY >= point.y() )
227 const QList< QGraphicsItem * > items = mLayout->items( point );
228 for ( QGraphicsItem *item : items )
233 if (
page->mapToScene(
page->rect() ).boundingRect().contains( point ) )
242 QPointF layoutUnitsPos = mLayout->convertToLayoutUnits( position );
243 if (
page > 0 &&
page < mPages.count() )
245 layoutUnitsPos.ry() += mPages.at(
page )->pos().y();
247 return layoutUnitsPos;
253 if (
page > 0 &&
page < mPages.count() )
255 vDelta = mLayout->convertFromLayoutUnits( mPages.at(
page )->pos().y(), position.
units() ).length();
263 double startCurrentPageY = 0;
264 double startNextPageY = 0;
266 const auto constMPages = mPages;
269 startCurrentPageY = startNextPageY;
271 if ( startNextPageY > position.y() )
286 y = position.y() - startCurrentPageY;
288 return QPointF( position.x(), y );
304 QRectF bounds = mLayout->layoutBounds(
true, 0.0 );
305 if ( bounds.isEmpty() )
308 if ( !mBlockUndoCommands )
309 mLayout->undoStack()->beginCommand(
this, tr(
"Resize to Contents" ) );
316 if ( mPages.empty() )
318 auto page = std::make_unique< QgsLayoutItemPage >( mLayout );
329 bounds.setWidth( bounds.width() + marginLeft + marginRight );
330 bounds.setHeight( bounds.height() + marginTop + marginBottom );
332 QgsLayoutSize newPageSize = mLayout->convertFromLayoutUnits( bounds.size(), mLayout->units() );
333 page->setPageSize( newPageSize );
338 double diffX = marginLeft - bounds.left();
339 double diffY = marginTop - bounds.top();
341 const QList<QGraphicsItem *> itemList = mLayout->items();
342 for ( QGraphicsItem *item : itemList )
349 layoutItem->beginCommand( tr(
"Move Item" ) );
350 layoutItem->attemptMoveBy( diffX, diffY );
351 layoutItem->endCommand();
357 mLayout->undoStack()->beginCommand( &mLayout->guides(), tr(
"Move Guides" ) );
358 const QList< QgsLayoutGuide * > verticalGuides = mLayout->guides().guides( Qt::Vertical );
361 guide->setLayoutPosition( guide->layoutPosition() + diffX );
363 const QList< QgsLayoutGuide * > horizontalGuides = mLayout->guides().guides( Qt::Horizontal );
366 guide->setLayoutPosition( guide->layoutPosition() + diffY );
368 mLayout->undoStack()->endCommand();
370 if ( !mBlockUndoCommands )
371 mLayout->undoStack()->endCommand();
376 QDomElement element = document.createElement( u
"PageCollection"_s );
379 element.appendChild( pageStyleElem );
383 page->writeXml( element, document, context );
386 mGuideCollection->writeXml( element, document, context );
388 parentElement.appendChild( element );
394 QDomElement element = e;
395 if ( element.nodeName() !=
"PageCollection"_L1 )
397 element = element.firstChildElement( u
"PageCollection"_s );
400 if ( element.nodeName() !=
"PageCollection"_L1 )
405 mBlockUndoCommands =
true;
411 mLayout->removeItem(
page );
417 QDomElement pageStyleSymbolElem = element.firstChildElement( u
"symbol"_s );
418 if ( !pageStyleSymbolElem.isNull() )
423 QDomNodeList pageList = element.elementsByTagName( u
"LayoutItem"_s );
424 for (
int i = 0; i < pageList.size(); ++i )
426 QDomElement pageElement = pageList.at( i ).toElement();
427 auto page = std::make_unique<QgsLayoutItemPage>( mLayout );
428 if ( mPageStyleSymbol )
429 page->setPageStyleSymbol( mPageStyleSymbol->clone() );
430 page->readXml( pageElement, document, context );
431 page->finalizeRestoreFromXml();
432 mPages.append(
page.get() );
433 mLayout->addItem(
page.release() );
438 mGuideCollection->readXml( element, document, context );
440 mBlockUndoCommands =
false;
446 return *mGuideCollection;
451 return *mGuideCollection;
457 if ( !referencePage )
462 mLayout->undoStack()->beginCommand(
this, tr(
"Apply page properties" ) );
463 mBlockUndoCommands =
true;
467 if (
page == referencePage )
475 mLayout->undoStack()->endCommand();
476 mBlockUndoCommands =
false;
482 const auto constMPages = mPages;
501 return mPages.count();
516 return mPages.indexOf(
page );
521 QList<QgsLayoutItemPage *>
pages;
522 const auto constMPages = mPages;
525 if (
page->mapToScene(
page->rect() ).boundingRect().intersects( region ) )
535 const auto constMPages = mPages;
538 if (
page->mapToScene(
page->rect() ).boundingRect().intersects( region ) )
548 const QList<QgsLayoutItem *> items = mLayout->pageCollection()->itemsOnPage(
page );
566 QList<QgsLayoutItem *> itemList;
567 const QList<QGraphicsItem *> graphicsItemList = mLayout->items();
568 itemList.reserve( graphicsItemList.size() );
569 for ( QGraphicsItem *graphicsItem : graphicsItemList )
574 itemList.push_back( item );
582 if (
page >= mPages.count() ||
page < 0 )
593 QList<QgsLayoutFrame *> frames;
597 if ( frame->hidePageIfEmpty() && frame->isEmpty() )
608 if ( !mBlockUndoCommands )
609 mLayout->undoStack()->beginCommand(
this, tr(
"Add Page" ) );
610 mPages.append(
page );
611 mLayout->addItem(
page );
613 if ( !mBlockUndoCommands )
614 mLayout->undoStack()->endCommand();
619 if ( mPages.empty() )
623 auto newPage = std::make_unique< QgsLayoutItemPage >( mLayout );
626 return mPages.at( mPages.count() - 1 );
631 if ( !mBlockUndoCommands )
633 mLayout->undoStack()->beginMacro( tr(
"Add Page" ) );
634 mLayout->undoStack()->beginCommand(
this, tr(
"Add Page" ) );
637 if ( beforePage < 0 )
641 if ( beforePage >= mPages.count() )
643 mPages.append(
page );
647 mPages.insert( beforePage,
page );
649 mLayout->addItem(
page );
653 for (
auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it )
655 if ( it.value().first < beforePage )
658 it.value().first = it.value().first + 1;
662 if ( ! mBlockUndoCommands )
664 mLayout->undoStack()->endCommand();
665 mLayout->undoStack()->endMacro();
674 if ( !mBlockUndoCommands )
676 mLayout->undoStack()->beginMacro( tr(
"Remove Page" ) );
677 mLayout->undoStack()->beginCommand(
this, tr(
"Remove Page" ) );
682 mLayout->removeItem(
page );
687 for (
auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it )
692 it.value().first = it.value().first - 1;
696 if ( ! mBlockUndoCommands )
698 mLayout->undoStack()->endCommand();
699 mLayout->undoStack()->endMacro();
705 if ( !mPages.contains(
page ) )
708 if ( !mBlockUndoCommands )
710 mLayout->undoStack()->beginMacro( tr(
"Remove Page" ) );
711 mLayout->undoStack()->beginCommand(
this, tr(
"Remove Page" ) );
713 int pageIndex = mPages.indexOf(
page );
716 mPages.removeAll(
page );
720 mLayout->removeItem(
page );
724 for (
auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it )
726 if ( it.value().first <= pageIndex )
729 it.value().first = it.value().first - 1;
733 if ( !mBlockUndoCommands )
735 mLayout->undoStack()->endCommand();
736 mLayout->undoStack()->endMacro();
742 if ( !mBlockUndoCommands )
744 mLayout->undoStack()->beginMacro( tr(
"Remove Pages" ) );
745 mLayout->undoStack()->beginCommand(
this, tr(
"Remove Pages" ) );
747 for (
int i = mPages.count() - 1; i >= 0; --i )
750 mPages.takeAt( i )->deleteLater();
753 if ( !mBlockUndoCommands )
755 mLayout->undoStack()->endCommand();
756 mLayout->undoStack()->endMacro();
762 mPages.removeAll(
page );
766void QgsLayoutPageCollection::createDefaultPageStyleSymbol()
768 QVariantMap properties;
769 properties.insert( u
"color"_s, u
"white"_s );
770 properties.insert( u
"style"_s, u
"solid"_s );
771 properties.insert( u
"style_border"_s, u
"no"_s );
772 properties.insert( u
"joinstyle"_s, u
"miter"_s );
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).