QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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  const QString key { it.key() };
84  if ( QgsLayoutItem *item = mLayout->itemByUuid( key ) )
85  {
86  if ( !mBlockUndoCommands )
87  item->beginCommand( QString() );
88 
89  item->attemptMove( it.value().second, true, false, it.value().first );
90 
91  // Item might have been deleted
92  if ( mLayout->itemByUuid( key ) )
93  {
94  if ( !mBlockUndoCommands )
95  item->endCommand();
96  }
97  else
98  {
99  item->cancelCommand();
100  }
101  }
102  }
103  mPreviousItemPositions.clear();
104 }
105 
107 {
108  double currentY = 0;
109  QgsLayoutPoint p( 0, 0, mLayout->units() );
110  const auto constMPages = mPages;
111  for ( QgsLayoutItemPage *page : constMPages )
112  {
113  page->attemptMove( p );
114  currentY += mLayout->convertToLayoutUnits( page->pageSize() ).height() + spaceBetweenPages();
115  p.setY( currentY );
116  }
117  mLayout->guides().update();
118  mLayout->updateBounds();
119  emit changed();
120 }
121 
123 {
124  double maxWidth = 0;
125  for ( QgsLayoutItemPage *page : mPages )
126  {
127  maxWidth = std::max( maxWidth, mLayout->convertToLayoutUnits( page->pageSize() ).width() );
128  }
129  return maxWidth;
130 }
131 
133 {
134  double maxArea = 0;
135  QSizeF maxSize;
136  for ( QgsLayoutItemPage *page : mPages )
137  {
138  QSizeF pageSize = mLayout->convertToLayoutUnits( page->pageSize() );
139  double area = pageSize.width() * pageSize.height();
140  if ( area > maxArea )
141  {
142  maxArea = area;
143  maxSize = pageSize;
144  }
145  }
146  return maxSize;
147 }
148 
150 {
151  QSizeF size;
152  for ( QgsLayoutItemPage *page : mPages )
153  {
154  QSizeF pageSize = mLayout->convertToLayoutUnits( page->pageSize() );
155  if ( !size.isValid() )
156  size = pageSize;
157  else
158  {
159  if ( !qgsDoubleNear( pageSize.width(), size.width(), 0.01 )
160  || !qgsDoubleNear( pageSize.height(), size.height(), 0.01 ) )
161  return false;
162  }
163  }
164  return true;
165 }
166 
168 {
169  int pageNumber = 0;
170  double startNextPageY = 0;
171  const auto constMPages = mPages;
172  for ( QgsLayoutItemPage *page : constMPages )
173  {
174  startNextPageY += page->rect().height() + spaceBetweenPages();
175  if ( startNextPageY > point.y() )
176  break;
177  pageNumber++;
178  }
179 
180  if ( pageNumber > mPages.count() - 1 )
181  pageNumber = mPages.count() - 1;
182  return pageNumber;
183 }
184 
186 {
187  if ( mPages.empty() )
188  return 0;
189 
190  int pageNumber = 0;
191  double startNextPageY = 0;
192  const auto constMPages = mPages;
193  for ( QgsLayoutItemPage *page : constMPages )
194  {
195  startNextPageY += page->rect().height() + spaceBetweenPages();
196  if ( startNextPageY >= point.y() )
197  break;
198  pageNumber++;
199  }
200 
201  if ( startNextPageY >= point.y() )
202  {
203  // found an existing page
204  return pageNumber;
205  }
206 
207  double lastPageHeight = mPages.last()->rect().height();
208  while ( startNextPageY < point.y() )
209  {
210  startNextPageY += lastPageHeight + spaceBetweenPages();
211  if ( startNextPageY >= point.y() )
212  break;
213  pageNumber++;
214  }
215 
216  return pageNumber;
217 }
218 
220 {
221  const QList< QGraphicsItem * > items = mLayout->items( point );
222  for ( QGraphicsItem *item : items )
223  {
224  if ( item->type() == QgsLayoutItemRegistry::LayoutPage )
225  {
226  QgsLayoutItemPage *page = static_cast< QgsLayoutItemPage * >( item );
227  if ( page->mapToScene( page->rect() ).boundingRect().contains( point ) )
228  return page;
229  }
230  }
231  return nullptr;
232 }
233 
235 {
236  QPointF layoutUnitsPos = mLayout->convertToLayoutUnits( position );
237  if ( page > 0 && page < mPages.count() )
238  {
239  layoutUnitsPos.ry() += mPages.at( page )->pos().y();
240  }
241  return layoutUnitsPos;
242 }
243 
245 {
246  double vDelta = 0.0;
247  if ( page > 0 && page < mPages.count() )
248  {
249  vDelta = mLayout->convertFromLayoutUnits( mPages.at( page )->pos().y(), position.units() ).length();
250  }
251 
252  return QgsLayoutPoint( position.x(), position.y() + vDelta, position.units() );
253 }
254 
255 QPointF QgsLayoutPageCollection::positionOnPage( QPointF position ) const
256 {
257  double startCurrentPageY = 0;
258  double startNextPageY = 0;
259  int pageNumber = 0;
260  const auto constMPages = mPages;
261  for ( QgsLayoutItemPage *page : constMPages )
262  {
263  startCurrentPageY = startNextPageY;
264  startNextPageY += page->rect().height() + spaceBetweenPages();
265  if ( startNextPageY > position.y() )
266  break;
267  pageNumber++;
268  }
269 
270  double y;
271  if ( pageNumber == mPages.size() )
272  {
273  //y coordinate is greater then the end of the last page, so return distance between
274  //top of last page and y coordinate
275  y = position.y() - ( startNextPageY - spaceBetweenPages() );
276  }
277  else
278  {
279  //y coordinate is less then the end of the last page
280  y = position.y() - startCurrentPageY;
281  }
282  return QPointF( position.x(), y );
283 }
284 
286 {
287  return mLayout->convertToLayoutUnits( QgsLayoutMeasurement( 10 ) );
288 }
289 
291 {
292  return spaceBetweenPages() / 2;
293 }
294 
296 {
297  //calculate current bounds
298  QRectF bounds = mLayout->layoutBounds( true, 0.0 );
299  if ( bounds.isEmpty() )
300  return;
301 
302  if ( !mBlockUndoCommands )
303  mLayout->undoStack()->beginCommand( this, tr( "Resize to Contents" ) );
304 
305  for ( int page = mPages.count() - 1; page > 0; page-- )
306  {
307  deletePage( page );
308  }
309 
310  if ( mPages.empty() )
311  {
312  std::unique_ptr< QgsLayoutItemPage > page = std::make_unique< QgsLayoutItemPage >( mLayout );
313  addPage( page.release() );
314  }
315 
316  QgsLayoutItemPage *page = mPages.at( 0 );
317 
318  double marginLeft = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.left(), marginUnits ) );
319  double marginTop = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.top(), marginUnits ) );
320  double marginBottom = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.bottom(), marginUnits ) );
321  double marginRight = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.right(), marginUnits ) );
322 
323  bounds.setWidth( bounds.width() + marginLeft + marginRight );
324  bounds.setHeight( bounds.height() + marginTop + marginBottom );
325 
326  QgsLayoutSize newPageSize = mLayout->convertFromLayoutUnits( bounds.size(), mLayout->units() );
327  page->setPageSize( newPageSize );
328 
329  reflow();
330 
331  //also move all items so that top-left of bounds is at marginLeft, marginTop
332  double diffX = marginLeft - bounds.left();
333  double diffY = marginTop - bounds.top();
334 
335  const QList<QGraphicsItem *> itemList = mLayout->items();
336  for ( QGraphicsItem *item : itemList )
337  {
338  if ( QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item ) )
339  {
340  QgsLayoutItemPage *pageItem = dynamic_cast<QgsLayoutItemPage *>( layoutItem );
341  if ( !pageItem )
342  {
343  layoutItem->beginCommand( tr( "Move Item" ) );
344  layoutItem->attemptMoveBy( diffX, diffY );
345  layoutItem->endCommand();
346  }
347  }
348  }
349 
350  //also move guides
351  mLayout->undoStack()->beginCommand( &mLayout->guides(), tr( "Move Guides" ) );
352  const QList< QgsLayoutGuide * > verticalGuides = mLayout->guides().guides( Qt::Vertical );
353  for ( QgsLayoutGuide *guide : verticalGuides )
354  {
355  guide->setLayoutPosition( guide->layoutPosition() + diffX );
356  }
357  const QList< QgsLayoutGuide * > horizontalGuides = mLayout->guides().guides( Qt::Horizontal );
358  for ( QgsLayoutGuide *guide : horizontalGuides )
359  {
360  guide->setLayoutPosition( guide->layoutPosition() + diffY );
361  }
362  mLayout->undoStack()->endCommand();
363 
364  if ( !mBlockUndoCommands )
365  mLayout->undoStack()->endCommand();
366 }
367 
368 bool QgsLayoutPageCollection::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const
369 {
370  QDomElement element = document.createElement( QStringLiteral( "PageCollection" ) );
371 
372  QDomElement pageStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mPageStyleSymbol.get(), document, context );
373  element.appendChild( pageStyleElem );
374 
375  for ( const QgsLayoutItemPage *page : mPages )
376  {
377  page->writeXml( element, document, context );
378  }
379 
380  mGuideCollection->writeXml( element, document, context );
381 
382  parentElement.appendChild( element );
383  return true;
384 }
385 
386 bool QgsLayoutPageCollection::readXml( const QDomElement &e, const QDomDocument &document, const QgsReadWriteContext &context )
387 {
388  QDomElement element = e;
389  if ( element.nodeName() != QLatin1String( "PageCollection" ) )
390  {
391  element = element.firstChildElement( QStringLiteral( "PageCollection" ) );
392  }
393 
394  if ( element.nodeName() != QLatin1String( "PageCollection" ) )
395  {
396  return false;
397  }
398 
399  mBlockUndoCommands = true;
400 
401  int i = 0;
402  for ( QgsLayoutItemPage *page : std::as_const( mPages ) )
403  {
404  emit pageAboutToBeRemoved( i );
405  mLayout->removeItem( page );
406  page->deleteLater();
407  ++i;
408  }
409  mPages.clear();
410 
411  QDomElement pageStyleSymbolElem = element.firstChildElement( QStringLiteral( "symbol" ) );
412  if ( !pageStyleSymbolElem.isNull() )
413  {
414  mPageStyleSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( pageStyleSymbolElem, context ) );
415  }
416 
417  QDomNodeList pageList = element.elementsByTagName( QStringLiteral( "LayoutItem" ) );
418  for ( int i = 0; i < pageList.size(); ++i )
419  {
420  QDomElement pageElement = pageList.at( i ).toElement();
421  std::unique_ptr< QgsLayoutItemPage > page( new QgsLayoutItemPage( mLayout ) );
422  if ( mPageStyleSymbol )
423  page->setPageStyleSymbol( mPageStyleSymbol->clone() );
424  page->readXml( pageElement, document, context );
426  mPages.append( page.get() );
427  mLayout->addItem( page.release() );
428  }
429 
430  reflow();
431 
432  mGuideCollection->readXml( element, document, context );
433 
434  mBlockUndoCommands = false;
435  return true;
436 }
437 
439 {
440  return *mGuideCollection;
441 }
442 
444 {
445  return *mGuideCollection;
446 }
447 
449 {
450  const auto constMPages = mPages;
451  for ( QgsLayoutItemPage *page : constMPages )
452  {
453  page->redraw();
454  }
455 }
456 
458 {
459  return mLayout;
460 }
461 
462 QList<QgsLayoutItemPage *> QgsLayoutPageCollection::pages()
463 {
464  return mPages;
465 }
466 
468 {
469  return mPages.count();
470 }
471 
473 {
474  return mPages.value( pageNumber );
475 }
476 
477 const QgsLayoutItemPage *QgsLayoutPageCollection::page( int pageNumber ) const
478 {
479  return mPages.value( pageNumber );
480 }
481 
483 {
484  return mPages.indexOf( page );
485 }
486 
487 QList<QgsLayoutItemPage *> QgsLayoutPageCollection::visiblePages( const QRectF &region ) const
488 {
489  QList<QgsLayoutItemPage *> pages;
490  const auto constMPages = mPages;
491  for ( QgsLayoutItemPage *page : constMPages )
492  {
493  if ( page->mapToScene( page->rect() ).boundingRect().intersects( region ) )
494  pages << page;
495  }
496  return pages;
497 }
498 
499 QList<int> QgsLayoutPageCollection::visiblePageNumbers( const QRectF &region ) const
500 {
501  QList< int > pages;
502  int p = 0;
503  const auto constMPages = mPages;
504  for ( QgsLayoutItemPage *page : constMPages )
505  {
506  if ( page->mapToScene( page->rect() ).boundingRect().intersects( region ) )
507  pages << p;
508  p++;
509  }
510  return pages;
511 }
512 
514 {
515  //get all items on page
516  const QList<QgsLayoutItem *> items = mLayout->pageCollection()->itemsOnPage( page );
517 
518  //loop through and check for non-paper items
519  for ( QgsLayoutItem *item : items )
520  {
521  //is item a paper item?
522  if ( item->type() != QgsLayoutItemRegistry::LayoutPage )
523  {
524  //item is not a paper item, so we have other items on the page
525  return false;
526  }
527  }
528  //no non-paper items
529  return true;
530 }
531 
532 QList<QgsLayoutItem *> QgsLayoutPageCollection::itemsOnPage( int page ) const
533 {
534  QList<QgsLayoutItem *> itemList;
535  const QList<QGraphicsItem *> graphicsItemList = mLayout->items();
536  itemList.reserve( graphicsItemList.size() );
537  for ( QGraphicsItem *graphicsItem : graphicsItemList )
538  {
539  QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
540  if ( item && item->page() == page )
541  {
542  itemList.push_back( item );
543  }
544  }
545  return itemList;
546 }
547 
549 {
550  if ( page >= mPages.count() || page < 0 )
551  {
552  //page number out of range, of course we shouldn't export it - stop smoking crack!
553  return false;
554  }
555 
556  QgsLayoutItemPage *pageItem = mPages.at( page );
557  if ( !pageItem->shouldDrawItem() )
558  return false;
559 
560  //check all frame items on page
561  QList<QgsLayoutFrame *> frames;
562  itemsOnPage( frames, page );
563  for ( QgsLayoutFrame *frame : std::as_const( frames ) )
564  {
565  if ( frame->hidePageIfEmpty() && frame->isEmpty() )
566  {
567  //frame is set to hide page if empty, and frame is empty, so we don't want to export this page
568  return false;
569  }
570  }
571  return true;
572 }
573 
575 {
576  if ( !mBlockUndoCommands )
577  mLayout->undoStack()->beginCommand( this, tr( "Add Page" ) );
578  mPages.append( page );
579  mLayout->addItem( page );
580  reflow();
581  if ( !mBlockUndoCommands )
582  mLayout->undoStack()->endCommand();
583 }
584 
586 {
587  if ( mPages.empty() )
588  return nullptr;
589 
590  QgsLayoutItemPage *lastPage = mPages.at( mPages.count() - 1 );
591  std::unique_ptr< QgsLayoutItemPage > newPage = std::make_unique< QgsLayoutItemPage >( mLayout );
592  newPage->attemptResize( lastPage->sizeWithUnits() );
593  addPage( newPage.release() );
594  return mPages.at( mPages.count() - 1 );
595 }
596 
598 {
599  if ( !mBlockUndoCommands )
600  {
601  mLayout->undoStack()->beginMacro( tr( "Add Page" ) );
602  mLayout->undoStack()->beginCommand( this, tr( "Add Page" ) );
603  }
604 
605  if ( beforePage < 0 )
606  beforePage = 0;
607 
609  if ( beforePage >= mPages.count() )
610  {
611  mPages.append( page );
612  }
613  else
614  {
615  mPages.insert( beforePage, page );
616  }
617  mLayout->addItem( page );
618  reflow();
619 
620  // bump up stored page numbers to account
621  for ( auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it ) // clazy:exclude=detaching-member
622  {
623  if ( it.value().first < beforePage )
624  continue;
625 
626  it.value().first = it.value().first + 1;
627  }
628 
630  if ( ! mBlockUndoCommands )
631  {
632  mLayout->undoStack()->endCommand();
633  mLayout->undoStack()->endMacro();
634  }
635 }
636 
638 {
639  if ( pageNumber < 0 || pageNumber >= mPages.count() )
640  return;
641 
642  if ( !mBlockUndoCommands )
643  {
644  mLayout->undoStack()->beginMacro( tr( "Remove Page" ) );
645  mLayout->undoStack()->beginCommand( this, tr( "Remove Page" ) );
646  }
649  QgsLayoutItemPage *page = mPages.takeAt( pageNumber );
650  mLayout->removeItem( page );
651  page->deleteLater();
652  reflow();
653 
654  // bump stored page numbers to account
655  for ( auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it ) // clazy:exclude=detaching-member
656  {
657  if ( it.value().first <= pageNumber )
658  continue;
659 
660  it.value().first = it.value().first - 1;
661  }
662 
664  if ( ! mBlockUndoCommands )
665  {
666  mLayout->undoStack()->endCommand();
667  mLayout->undoStack()->endMacro();
668  }
669 }
670 
672 {
673  if ( !mPages.contains( page ) )
674  return;
675 
676  if ( !mBlockUndoCommands )
677  {
678  mLayout->undoStack()->beginMacro( tr( "Remove Page" ) );
679  mLayout->undoStack()->beginCommand( this, tr( "Remove Page" ) );
680  }
681  int pageIndex = mPages.indexOf( page );
682  emit pageAboutToBeRemoved( pageIndex );
684  mPages.removeAll( page );
685  page->deleteLater();
686  // remove immediately from scene -- otherwise immediately calculation of layout bounds (such as is done
687  // in reflow) will still consider the page, at least until it's actually deleted at the next event loop
688  mLayout->removeItem( page );
689  reflow();
690 
691  // bump stored page numbers to account
692  for ( auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it ) // clazy:exclude=detaching-member
693  {
694  if ( it.value().first <= pageIndex )
695  continue;
696 
697  it.value().first = it.value().first - 1;
698  }
699 
701  if ( !mBlockUndoCommands )
702  {
703  mLayout->undoStack()->endCommand();
704  mLayout->undoStack()->endMacro();
705  }
706 }
707 
709 {
710  if ( !mBlockUndoCommands )
711  {
712  mLayout->undoStack()->beginMacro( tr( "Remove Pages" ) );
713  mLayout->undoStack()->beginCommand( this, tr( "Remove Pages" ) );
714  }
715  for ( int i = mPages.count() - 1; i >= 0; --i )
716  {
717  emit pageAboutToBeRemoved( i );
718  mPages.takeAt( i )->deleteLater();
719  }
720  reflow();
721  if ( !mBlockUndoCommands )
722  {
723  mLayout->undoStack()->endCommand();
724  mLayout->undoStack()->endMacro();
725  }
726 }
727 
729 {
730  mPages.removeAll( page );
731  return page;
732 }
733 
734 void QgsLayoutPageCollection::createDefaultPageStyleSymbol()
735 {
736  QVariantMap properties;
737  properties.insert( QStringLiteral( "color" ), QStringLiteral( "white" ) );
738  properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
739  properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "no" ) );
740  properties.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
741  mPageStyleSymbol.reset( QgsFillSymbol::createSimple( properties ) );
742 }
743 
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:1578