QGIS API Documentation  3.23.0-Master (dd0cd13a00)
qgslayoutpagecollection.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutpagecollection.cpp
3  ----------------------------
4  begin : July 2017
5  copyright : (C) 2017 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 /***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
18 #include "qgslayout.h"
19 #include "qgsreadwritecontext.h"
20 #include "qgsproject.h"
22 #include "qgssymbollayerutils.h"
23 #include "qgslayoutframe.h"
24 #include "qgslayoutundostack.h"
25 #include "qgsfillsymbol.h"
26 
28  : QObject( layout )
29  , mLayout( layout )
30  , mGuideCollection( new QgsLayoutGuideCollection( layout, this ) )
31 {
32  createDefaultPageStyleSymbol();
33 }
34 
36 {
37  const auto constMPages = mPages;
38  for ( QgsLayoutItemPage *page : constMPages )
39  {
40  mLayout->removeItem( page );
41  page->deleteLater();
42  }
43 }
44 
46 {
47  if ( !symbol )
48  return;
49 
50  mPageStyleSymbol.reset( static_cast<QgsFillSymbol *>( symbol->clone() ) );
51 
52  for ( QgsLayoutItemPage *page : std::as_const( mPages ) )
53  {
54  page->setPageStyleSymbol( symbol->clone() );
55  page->update();
56  }
57 }
58 
60 {
61  return mPageStyleSymbol.get();
62 }
63 
65 {
66  mPreviousItemPositions.clear();
67  QList< QgsLayoutItem * > items;
68  mLayout->layoutItems( items );
69 
70  for ( QgsLayoutItem *item : std::as_const( items ) )
71  {
72  if ( item->type() == QgsLayoutItemRegistry::LayoutPage )
73  continue;
74 
75  mPreviousItemPositions.insert( item->uuid(), qMakePair( item->page(), item->pagePositionWithUnits() ) );
76  }
77 }
78 
80 {
81  for ( auto it = mPreviousItemPositions.constBegin(); it != mPreviousItemPositions.constEnd(); ++it )
82  {
83  if ( QgsLayoutItem *item = mLayout->itemByUuid( it.key() ) )
84  {
85  if ( !mBlockUndoCommands )
86  item->beginCommand( QString() );
87  item->attemptMove( it.value().second, true, false, it.value().first );
88  if ( !mBlockUndoCommands )
89  item->endCommand();
90  }
91  }
92  mPreviousItemPositions.clear();
93 }
94 
96 {
97  double currentY = 0;
98  QgsLayoutPoint p( 0, 0, mLayout->units() );
99  const auto constMPages = mPages;
100  for ( QgsLayoutItemPage *page : constMPages )
101  {
102  page->attemptMove( p );
103  currentY += mLayout->convertToLayoutUnits( page->pageSize() ).height() + spaceBetweenPages();
104  p.setY( currentY );
105  }
106  mLayout->guides().update();
107  mLayout->updateBounds();
108  emit changed();
109 }
110 
112 {
113  double maxWidth = 0;
114  for ( QgsLayoutItemPage *page : mPages )
115  {
116  maxWidth = std::max( maxWidth, mLayout->convertToLayoutUnits( page->pageSize() ).width() );
117  }
118  return maxWidth;
119 }
120 
122 {
123  double maxArea = 0;
124  QSizeF maxSize;
125  for ( QgsLayoutItemPage *page : mPages )
126  {
127  QSizeF pageSize = mLayout->convertToLayoutUnits( page->pageSize() );
128  double area = pageSize.width() * pageSize.height();
129  if ( area > maxArea )
130  {
131  maxArea = area;
132  maxSize = pageSize;
133  }
134  }
135  return maxSize;
136 }
137 
139 {
140  QSizeF size;
141  for ( QgsLayoutItemPage *page : mPages )
142  {
143  QSizeF pageSize = mLayout->convertToLayoutUnits( page->pageSize() );
144  if ( !size.isValid() )
145  size = pageSize;
146  else
147  {
148  if ( !qgsDoubleNear( pageSize.width(), size.width(), 0.01 )
149  || !qgsDoubleNear( pageSize.height(), size.height(), 0.01 ) )
150  return false;
151  }
152  }
153  return true;
154 }
155 
157 {
158  int pageNumber = 0;
159  double startNextPageY = 0;
160  const auto constMPages = mPages;
161  for ( QgsLayoutItemPage *page : constMPages )
162  {
163  startNextPageY += page->rect().height() + spaceBetweenPages();
164  if ( startNextPageY > point.y() )
165  break;
166  pageNumber++;
167  }
168 
169  if ( pageNumber > mPages.count() - 1 )
170  pageNumber = mPages.count() - 1;
171  return pageNumber;
172 }
173 
175 {
176  if ( mPages.empty() )
177  return 0;
178 
179  int pageNumber = 0;
180  double startNextPageY = 0;
181  const auto constMPages = mPages;
182  for ( QgsLayoutItemPage *page : constMPages )
183  {
184  startNextPageY += page->rect().height() + spaceBetweenPages();
185  if ( startNextPageY >= point.y() )
186  break;
187  pageNumber++;
188  }
189 
190  if ( startNextPageY >= point.y() )
191  {
192  // found an existing page
193  return pageNumber;
194  }
195 
196  double lastPageHeight = mPages.last()->rect().height();
197  while ( startNextPageY < point.y() )
198  {
199  startNextPageY += lastPageHeight + spaceBetweenPages();
200  if ( startNextPageY >= point.y() )
201  break;
202  pageNumber++;
203  }
204 
205  return pageNumber;
206 }
207 
209 {
210  const QList< QGraphicsItem * > items = mLayout->items( point );
211  for ( QGraphicsItem *item : items )
212  {
213  if ( item->type() == QgsLayoutItemRegistry::LayoutPage )
214  {
215  QgsLayoutItemPage *page = static_cast< QgsLayoutItemPage * >( item );
216  if ( page->mapToScene( page->rect() ).boundingRect().contains( point ) )
217  return page;
218  }
219  }
220  return nullptr;
221 }
222 
224 {
225  QPointF layoutUnitsPos = mLayout->convertToLayoutUnits( position );
226  if ( page > 0 && page < mPages.count() )
227  {
228  layoutUnitsPos.ry() += mPages.at( page )->pos().y();
229  }
230  return layoutUnitsPos;
231 }
232 
234 {
235  double vDelta = 0.0;
236  if ( page > 0 && page < mPages.count() )
237  {
238  vDelta = mLayout->convertFromLayoutUnits( mPages.at( page )->pos().y(), position.units() ).length();
239  }
240 
241  return QgsLayoutPoint( position.x(), position.y() + vDelta, position.units() );
242 }
243 
244 QPointF QgsLayoutPageCollection::positionOnPage( QPointF position ) const
245 {
246  double startCurrentPageY = 0;
247  double startNextPageY = 0;
248  int pageNumber = 0;
249  const auto constMPages = mPages;
250  for ( QgsLayoutItemPage *page : constMPages )
251  {
252  startCurrentPageY = startNextPageY;
253  startNextPageY += page->rect().height() + spaceBetweenPages();
254  if ( startNextPageY > position.y() )
255  break;
256  pageNumber++;
257  }
258 
259  double y;
260  if ( pageNumber == mPages.size() )
261  {
262  //y coordinate is greater then the end of the last page, so return distance between
263  //top of last page and y coordinate
264  y = position.y() - ( startNextPageY - spaceBetweenPages() );
265  }
266  else
267  {
268  //y coordinate is less then the end of the last page
269  y = position.y() - startCurrentPageY;
270  }
271  return QPointF( position.x(), y );
272 }
273 
275 {
276  return mLayout->convertToLayoutUnits( QgsLayoutMeasurement( 10 ) );
277 }
278 
280 {
281  return spaceBetweenPages() / 2;
282 }
283 
285 {
286  //calculate current bounds
287  QRectF bounds = mLayout->layoutBounds( true, 0.0 );
288  if ( bounds.isEmpty() )
289  return;
290 
291  if ( !mBlockUndoCommands )
292  mLayout->undoStack()->beginCommand( this, tr( "Resize to Contents" ) );
293 
294  for ( int page = mPages.count() - 1; page > 0; page-- )
295  {
296  deletePage( page );
297  }
298 
299  if ( mPages.empty() )
300  {
301  std::unique_ptr< QgsLayoutItemPage > page = std::make_unique< QgsLayoutItemPage >( mLayout );
302  addPage( page.release() );
303  }
304 
305  QgsLayoutItemPage *page = mPages.at( 0 );
306 
307  double marginLeft = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.left(), marginUnits ) );
308  double marginTop = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.top(), marginUnits ) );
309  double marginBottom = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.bottom(), marginUnits ) );
310  double marginRight = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.right(), marginUnits ) );
311 
312  bounds.setWidth( bounds.width() + marginLeft + marginRight );
313  bounds.setHeight( bounds.height() + marginTop + marginBottom );
314 
315  QgsLayoutSize newPageSize = mLayout->convertFromLayoutUnits( bounds.size(), mLayout->units() );
316  page->setPageSize( newPageSize );
317 
318  reflow();
319 
320  //also move all items so that top-left of bounds is at marginLeft, marginTop
321  double diffX = marginLeft - bounds.left();
322  double diffY = marginTop - bounds.top();
323 
324  const QList<QGraphicsItem *> itemList = mLayout->items();
325  for ( QGraphicsItem *item : itemList )
326  {
327  if ( QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item ) )
328  {
329  QgsLayoutItemPage *pageItem = dynamic_cast<QgsLayoutItemPage *>( layoutItem );
330  if ( !pageItem )
331  {
332  layoutItem->beginCommand( tr( "Move Item" ) );
333  layoutItem->attemptMoveBy( diffX, diffY );
334  layoutItem->endCommand();
335  }
336  }
337  }
338 
339  //also move guides
340  mLayout->undoStack()->beginCommand( &mLayout->guides(), tr( "Move Guides" ) );
341  const QList< QgsLayoutGuide * > verticalGuides = mLayout->guides().guides( Qt::Vertical );
342  for ( QgsLayoutGuide *guide : verticalGuides )
343  {
344  guide->setLayoutPosition( guide->layoutPosition() + diffX );
345  }
346  const QList< QgsLayoutGuide * > horizontalGuides = mLayout->guides().guides( Qt::Horizontal );
347  for ( QgsLayoutGuide *guide : horizontalGuides )
348  {
349  guide->setLayoutPosition( guide->layoutPosition() + diffY );
350  }
351  mLayout->undoStack()->endCommand();
352 
353  if ( !mBlockUndoCommands )
354  mLayout->undoStack()->endCommand();
355 }
356 
357 bool QgsLayoutPageCollection::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const
358 {
359  QDomElement element = document.createElement( QStringLiteral( "PageCollection" ) );
360 
361  QDomElement pageStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mPageStyleSymbol.get(), document, context );
362  element.appendChild( pageStyleElem );
363 
364  for ( const QgsLayoutItemPage *page : mPages )
365  {
366  page->writeXml( element, document, context );
367  }
368 
369  mGuideCollection->writeXml( element, document, context );
370 
371  parentElement.appendChild( element );
372  return true;
373 }
374 
375 bool QgsLayoutPageCollection::readXml( const QDomElement &e, const QDomDocument &document, const QgsReadWriteContext &context )
376 {
377  QDomElement element = e;
378  if ( element.nodeName() != QLatin1String( "PageCollection" ) )
379  {
380  element = element.firstChildElement( QStringLiteral( "PageCollection" ) );
381  }
382 
383  if ( element.nodeName() != QLatin1String( "PageCollection" ) )
384  {
385  return false;
386  }
387 
388  mBlockUndoCommands = true;
389 
390  int i = 0;
391  for ( QgsLayoutItemPage *page : std::as_const( mPages ) )
392  {
393  emit pageAboutToBeRemoved( i );
394  mLayout->removeItem( page );
395  page->deleteLater();
396  ++i;
397  }
398  mPages.clear();
399 
400  QDomElement pageStyleSymbolElem = element.firstChildElement( QStringLiteral( "symbol" ) );
401  if ( !pageStyleSymbolElem.isNull() )
402  {
403  mPageStyleSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( pageStyleSymbolElem, context ) );
404  }
405 
406  QDomNodeList pageList = element.elementsByTagName( QStringLiteral( "LayoutItem" ) );
407  for ( int i = 0; i < pageList.size(); ++i )
408  {
409  QDomElement pageElement = pageList.at( i ).toElement();
410  std::unique_ptr< QgsLayoutItemPage > page( new QgsLayoutItemPage( mLayout ) );
411  if ( mPageStyleSymbol )
412  page->setPageStyleSymbol( mPageStyleSymbol->clone() );
413  page->readXml( pageElement, document, context );
415  mPages.append( page.get() );
416  mLayout->addItem( page.release() );
417  }
418 
419  reflow();
420 
421  mGuideCollection->readXml( element, document, context );
422 
423  mBlockUndoCommands = false;
424  return true;
425 }
426 
428 {
429  return *mGuideCollection;
430 }
431 
433 {
434  return *mGuideCollection;
435 }
436 
438 {
439  const auto constMPages = mPages;
440  for ( QgsLayoutItemPage *page : constMPages )
441  {
442  page->redraw();
443  }
444 }
445 
447 {
448  return mLayout;
449 }
450 
451 QList<QgsLayoutItemPage *> QgsLayoutPageCollection::pages()
452 {
453  return mPages;
454 }
455 
457 {
458  return mPages.count();
459 }
460 
462 {
463  return mPages.value( pageNumber );
464 }
465 
466 const QgsLayoutItemPage *QgsLayoutPageCollection::page( int pageNumber ) const
467 {
468  return mPages.value( pageNumber );
469 }
470 
472 {
473  return mPages.indexOf( page );
474 }
475 
476 QList<QgsLayoutItemPage *> QgsLayoutPageCollection::visiblePages( const QRectF &region ) const
477 {
478  QList<QgsLayoutItemPage *> pages;
479  const auto constMPages = mPages;
480  for ( QgsLayoutItemPage *page : constMPages )
481  {
482  if ( page->mapToScene( page->rect() ).boundingRect().intersects( region ) )
483  pages << page;
484  }
485  return pages;
486 }
487 
488 QList<int> QgsLayoutPageCollection::visiblePageNumbers( const QRectF &region ) const
489 {
490  QList< int > pages;
491  int p = 0;
492  const auto constMPages = mPages;
493  for ( QgsLayoutItemPage *page : constMPages )
494  {
495  if ( page->mapToScene( page->rect() ).boundingRect().intersects( region ) )
496  pages << p;
497  p++;
498  }
499  return pages;
500 }
501 
503 {
504  //get all items on page
505  const QList<QgsLayoutItem *> items = mLayout->pageCollection()->itemsOnPage( page );
506 
507  //loop through and check for non-paper items
508  for ( QgsLayoutItem *item : items )
509  {
510  //is item a paper item?
511  if ( item->type() != QgsLayoutItemRegistry::LayoutPage )
512  {
513  //item is not a paper item, so we have other items on the page
514  return false;
515  }
516  }
517  //no non-paper items
518  return true;
519 }
520 
521 QList<QgsLayoutItem *> QgsLayoutPageCollection::itemsOnPage( int page ) const
522 {
523  QList<QgsLayoutItem *> itemList;
524  const QList<QGraphicsItem *> graphicsItemList = mLayout->items();
525  itemList.reserve( graphicsItemList.size() );
526  for ( QGraphicsItem *graphicsItem : graphicsItemList )
527  {
528  QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
529  if ( item && item->page() == page )
530  {
531  itemList.push_back( item );
532  }
533  }
534  return itemList;
535 }
536 
538 {
539  if ( page >= mPages.count() || page < 0 )
540  {
541  //page number out of range, of course we shouldn't export it - stop smoking crack!
542  return false;
543  }
544 
545  QgsLayoutItemPage *pageItem = mPages.at( page );
546  if ( !pageItem->shouldDrawItem() )
547  return false;
548 
549  //check all frame items on page
550  QList<QgsLayoutFrame *> frames;
551  itemsOnPage( frames, page );
552  for ( QgsLayoutFrame *frame : std::as_const( frames ) )
553  {
554  if ( frame->hidePageIfEmpty() && frame->isEmpty() )
555  {
556  //frame is set to hide page if empty, and frame is empty, so we don't want to export this page
557  return false;
558  }
559  }
560  return true;
561 }
562 
564 {
565  if ( !mBlockUndoCommands )
566  mLayout->undoStack()->beginCommand( this, tr( "Add Page" ) );
567  mPages.append( page );
568  mLayout->addItem( page );
569  reflow();
570  if ( !mBlockUndoCommands )
571  mLayout->undoStack()->endCommand();
572 }
573 
575 {
576  if ( mPages.empty() )
577  return nullptr;
578 
579  QgsLayoutItemPage *lastPage = mPages.at( mPages.count() - 1 );
580  std::unique_ptr< QgsLayoutItemPage > newPage = std::make_unique< QgsLayoutItemPage >( mLayout );
581  newPage->attemptResize( lastPage->sizeWithUnits() );
582  addPage( newPage.release() );
583  return mPages.at( mPages.count() - 1 );
584 }
585 
587 {
588  if ( !mBlockUndoCommands )
589  {
590  mLayout->undoStack()->beginMacro( tr( "Add Page" ) );
591  mLayout->undoStack()->beginCommand( this, tr( "Add Page" ) );
592  }
593 
594  if ( beforePage < 0 )
595  beforePage = 0;
596 
598  if ( beforePage >= mPages.count() )
599  {
600  mPages.append( page );
601  }
602  else
603  {
604  mPages.insert( beforePage, page );
605  }
606  mLayout->addItem( page );
607  reflow();
608 
609  // bump up stored page numbers to account
610  for ( auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it ) // clazy:exclude=detaching-member
611  {
612  if ( it.value().first < beforePage )
613  continue;
614 
615  it.value().first = it.value().first + 1;
616  }
617 
619  if ( ! mBlockUndoCommands )
620  {
621  mLayout->undoStack()->endCommand();
622  mLayout->undoStack()->endMacro();
623  }
624 }
625 
627 {
628  if ( pageNumber < 0 || pageNumber >= mPages.count() )
629  return;
630 
631  if ( !mBlockUndoCommands )
632  {
633  mLayout->undoStack()->beginMacro( tr( "Remove Page" ) );
634  mLayout->undoStack()->beginCommand( this, tr( "Remove Page" ) );
635  }
638  QgsLayoutItemPage *page = mPages.takeAt( pageNumber );
639  mLayout->removeItem( page );
640  page->deleteLater();
641  reflow();
642 
643  // bump stored page numbers to account
644  for ( auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it ) // clazy:exclude=detaching-member
645  {
646  if ( it.value().first <= pageNumber )
647  continue;
648 
649  it.value().first = it.value().first - 1;
650  }
651 
653  if ( ! mBlockUndoCommands )
654  {
655  mLayout->undoStack()->endCommand();
656  mLayout->undoStack()->endMacro();
657  }
658 }
659 
661 {
662  if ( !mPages.contains( page ) )
663  return;
664 
665  if ( !mBlockUndoCommands )
666  {
667  mLayout->undoStack()->beginMacro( tr( "Remove Page" ) );
668  mLayout->undoStack()->beginCommand( this, tr( "Remove Page" ) );
669  }
670  int pageIndex = mPages.indexOf( page );
671  emit pageAboutToBeRemoved( pageIndex );
673  mPages.removeAll( page );
674  page->deleteLater();
675  // remove immediately from scene -- otherwise immediately calculation of layout bounds (such as is done
676  // in reflow) will still consider the page, at least until it's actually deleted at the next event loop
677  mLayout->removeItem( page );
678  reflow();
679 
680  // bump stored page numbers to account
681  for ( auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it ) // clazy:exclude=detaching-member
682  {
683  if ( it.value().first <= pageIndex )
684  continue;
685 
686  it.value().first = it.value().first - 1;
687  }
688 
690  if ( !mBlockUndoCommands )
691  {
692  mLayout->undoStack()->endCommand();
693  mLayout->undoStack()->endMacro();
694  }
695 }
696 
698 {
699  if ( !mBlockUndoCommands )
700  {
701  mLayout->undoStack()->beginMacro( tr( "Remove Pages" ) );
702  mLayout->undoStack()->beginCommand( this, tr( "Remove Pages" ) );
703  }
704  for ( int i = mPages.count() - 1; i >= 0; --i )
705  {
706  emit pageAboutToBeRemoved( i );
707  mPages.takeAt( i )->deleteLater();
708  }
709  reflow();
710  if ( !mBlockUndoCommands )
711  {
712  mLayout->undoStack()->endCommand();
713  mLayout->undoStack()->endMacro();
714  }
715 }
716 
718 {
719  mPages.removeAll( page );
720  return page;
721 }
722 
723 void QgsLayoutPageCollection::createDefaultPageStyleSymbol()
724 {
725  QVariantMap properties;
726  properties.insert( QStringLiteral( "color" ), QStringLiteral( "white" ) );
727  properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
728  properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "no" ) );
729  properties.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
730  mPageStyleSymbol.reset( QgsFillSymbol::createSimple( properties ) );
731 }
732 
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgsfillsymbol.h:30
static 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.
QList< QgsLayoutGuide * > guides()
Returns a list of all guides contained in the collection.
void update()
Updates the position (and visibility) of all guide line items.
Contains the configuration for a single snap guide used by a layout.
Item representing the paper in a layout.
QRectF boundingRect() const override
void setPageSize(const QgsLayoutSize &size)
Sets the size of the page.
QgsLayoutSize pageSize() const
Returns the size of the page.
void setPageStyleSymbol(QgsFillSymbol *symbol)
Sets the symbol to use for drawing the page background.
void redraw() override
Base class for graphical items within a QgsLayout.
bool writeXml(QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context) const
Stores the item state in a DOM element.
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
void beginCommand(const QString &commandText, UndoCommand command=UndoNone)
Starts new undo command for this item.
int page() const
Returns the page the item is currently on, with the first page returning 0.
virtual void finalizeRestoreFromXml()
Called after all pending items have been restored from XML.
bool readXml(const QDomElement &itemElement, const QDomDocument &document, const QgsReadWriteContext &context)
Sets the item state from a DOM element.
bool shouldDrawItem() const
Returns whether the item should be drawn in the current context.
virtual void attemptMove(const QgsLayoutPoint &point, bool useReferencePoint=true, bool includesFrame=false, int page=-1)
Attempts to move the item to a specified point.
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
double length() const
Returns the length of the measurement.
QList< int > visiblePageNumbers(const QRectF &region) 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 &region) 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.
void resizeToContents(const QgsMargins &margins, QgsUnitTypes::LayoutUnit marginUnits)
Resizes the layout to a single page which fits the current contents of the layout.
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.
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).
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.
This class provides a method of storing points, consisting of an x and y coordinate,...
double x() const
Returns x coordinate of point.
QgsUnitTypes::LayoutUnit units() const
Returns the units for the point.
double y() const
Returns y coordinate of point.
void setY(const double y)
Sets y coordinate of point.
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
Definition: qgslayoutsize.h:41
void endCommand()
Saves final state of an object and pushes the active command to the undo history.
void beginMacro(const QString &commandText)
Starts a macro command, with the given descriptive commandText.
void beginCommand(QgsLayoutUndoObjectInterface *object, const QString &commandText, int id=0)
Begins a new undo command for the specified object.
void endMacro()
Ends a macro command.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:51
void updateBounds()
Updates the scene bounds of the layout.
Definition: qgslayout.cpp:1154
QgsLayoutPageCollection * pageCollection()
Returns a pointer to the layout's page collection, which stores and manages page items in the layout.
Definition: qgslayout.cpp:459
void layoutItems(QList< T * > &itemList) const
Returns a list of layout items of a specific type.
Definition: qgslayout.h:122
QgsLayoutItem * itemByUuid(const QString &uuid, bool includeTemplateUuids=false) const
Returns the layout item with matching uuid unique identifier, or nullptr if a matching item could not...
Definition: qgslayout.cpp:238
QgsLayoutGuideCollection & guides()
Returns a reference to the layout's guide collection, which manages page snap guides.
Definition: qgslayout.cpp:385
double convertToLayoutUnits(QgsLayoutMeasurement measurement) const
Converts a measurement into the layout's native units.
Definition: qgslayout.cpp:329
QgsUnitTypes::LayoutUnit units() const
Returns the native units for the layout.
Definition: qgslayout.h:329
QRectF layoutBounds(bool ignorePages=false, double margin=0.0) const
Calculates the bounds of all non-gui items in the layout.
Definition: qgslayout.cpp:469
QgsLayoutMeasurement convertFromLayoutUnits(double length, QgsUnitTypes::LayoutUnit unit) const
Converts a length measurement from the layout's native units to a specified target unit.
Definition: qgslayout.cpp:344
QgsLayoutUndoStack * undoStack()
Returns a pointer to the layout's undo stack, which manages undo/redo states for the layout and it's ...
Definition: qgslayout.cpp:686
The QgsMargins class defines the four margins of a rectangle.
Definition: qgsmargins.h:38
double top() const
Returns the top margin.
Definition: qgsmargins.h:78
double right() const
Returns the right margin.
Definition: qgsmargins.h:84
double bottom() const
Returns the bottom margin.
Definition: qgsmargins.h:90
double left() const
Returns the left margin.
Definition: qgsmargins.h:72
The class is used as a container of context for various read/write operations on other objects.
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
LayoutUnit
Layout measurement units.
Definition: qgsunittypes.h:182
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1504