QGIS API Documentation  3.15.0-Master (a49cb7c9f3)
qgslayout.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayout.cpp
3  -------------------
4  begin : June 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 
17 #include "qgslayout.h"
18 #include "qgslayoutitem.h"
19 #include "qgslayoutmodel.h"
22 #include "qgsreadwritecontext.h"
23 #include "qgsproject.h"
25 #include "qgslayoutitemgroup.h"
27 #include "qgslayoutmultiframe.h"
28 #include "qgslayoutitemmap.h"
29 #include "qgslayoutundostack.h"
31 #include "qgsvectorlayer.h"
33 #include "qgsstyleentityvisitor.h"
34 #include "qgsruntimeprofiler.h"
35 
37  : mProject( project )
38  , mRenderContext( new QgsLayoutRenderContext( this ) )
39  , mReportContext( new QgsLayoutReportContext( this ) )
40  , mSnapper( QgsLayoutSnapper( this ) )
41  , mGridSettings( this )
42  , mPageCollection( new QgsLayoutPageCollection( this ) )
43  , mUndoStack( new QgsLayoutUndoStack( this ) )
44 {
45  // just to make sure - this should be the default, but maybe it'll change in some future Qt version...
46  setBackgroundBrush( Qt::NoBrush );
47  mItemsModel.reset( new QgsLayoutModel( this ) );
48 }
49 
51 {
52  // no need for undo commands when we're destroying the layout
53  mUndoStack->blockCommands( true );
54 
55  deleteAndRemoveMultiFrames();
56 
57  // make sure that all layout items are removed before
58  // this class is deconstructed - to avoid segfaults
59  // when layout items access in destructor layout that isn't valid anymore
60 
61  // since deletion of some item types (e.g. groups) trigger deletion
62  // of other items, we have to do this careful, one at a time...
63  QList<QGraphicsItem *> itemList = items();
64  bool deleted = true;
65  while ( deleted )
66  {
67  deleted = false;
68  for ( QGraphicsItem *item : qgis::as_const( itemList ) )
69  {
70  if ( dynamic_cast< QgsLayoutItem * >( item ) && !dynamic_cast< QgsLayoutItemPage *>( item ) )
71  {
72  delete item;
73  deleted = true;
74  break;
75  }
76  }
77  itemList = items();
78  }
79 
80  mItemsModel.reset(); // manually delete, so we can control order of destruction
81 }
82 
84 {
85  QDomDocument currentDoc;
86 
87  QgsReadWriteContext context;
88  QDomElement elem = writeXml( currentDoc, context );
89  currentDoc.appendChild( elem );
90 
91  std::unique_ptr< QgsLayout > newLayout = qgis::make_unique< QgsLayout >( mProject );
92  bool ok = false;
93  newLayout->loadFromTemplate( currentDoc, context, true, &ok );
94  if ( !ok )
95  {
96  return nullptr;
97  }
98 
99  return newLayout.release();
100 }
101 
103 {
104  // default to a A4 landscape page
105  QgsLayoutItemPage *page = new QgsLayoutItemPage( this );
107  mPageCollection->addPage( page );
108  mUndoStack->stack()->clear();
109 }
110 
112 {
113  deleteAndRemoveMultiFrames();
114 
115  //delete all non paper items
116  const QList<QGraphicsItem *> itemList = items();
117  for ( QGraphicsItem *item : itemList )
118  {
119  QgsLayoutItem *cItem = dynamic_cast<QgsLayoutItem *>( item );
120  QgsLayoutItemPage *pItem = dynamic_cast<QgsLayoutItemPage *>( item );
121  if ( cItem && !pItem )
122  {
123  removeLayoutItemPrivate( cItem );
124  }
125  }
126  mItemsModel->clear();
127 
128  mPageCollection->clear();
129  mUndoStack->stack()->clear();
130 }
131 
133 {
134  return mProject;
135 }
136 
138 {
139  return mItemsModel.get();
140 }
141 
142 QList<QgsLayoutItem *> QgsLayout::selectedLayoutItems( const bool includeLockedItems )
143 {
144  QList<QgsLayoutItem *> layoutItemList;
145 
146  const QList<QGraphicsItem *> graphicsItemList = selectedItems();
147  for ( QGraphicsItem *item : graphicsItemList )
148  {
149  QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item );
150  if ( layoutItem && ( includeLockedItems || !layoutItem->isLocked() ) )
151  {
152  layoutItemList.push_back( layoutItem );
153  }
154  }
155 
156  return layoutItemList;
157 }
158 
160 {
161  whileBlocking( this )->deselectAll();
162  if ( item )
163  {
164  item->setSelected( true );
165  }
166  emit selectedItemChanged( item );
167 }
168 
170 {
171  //we can't use QGraphicsScene::clearSelection, as that emits no signals
172  //and we don't know which items are being deselected
173  //accordingly, we can't inform the layout model of selection changes
174  //instead, do the clear selection manually...
175  const QList<QGraphicsItem *> selectedItemList = selectedItems();
176  for ( QGraphicsItem *item : selectedItemList )
177  {
178  if ( QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item ) )
179  {
180  layoutItem->setSelected( false );
181  }
182  }
183  emit selectedItemChanged( nullptr );
184 }
185 
186 bool QgsLayout::raiseItem( QgsLayoutItem *item, bool deferUpdate )
187 {
188  //model handles reordering items
189  bool result = mItemsModel->reorderItemUp( item );
190  if ( result && !deferUpdate )
191  {
192  //update all positions
193  updateZValues();
194  update();
195  }
196  return result;
197 }
198 
199 bool QgsLayout::lowerItem( QgsLayoutItem *item, bool deferUpdate )
200 {
201  //model handles reordering items
202  bool result = mItemsModel->reorderItemDown( item );
203  if ( result && !deferUpdate )
204  {
205  //update all positions
206  updateZValues();
207  update();
208  }
209  return result;
210 }
211 
212 bool QgsLayout::moveItemToTop( QgsLayoutItem *item, bool deferUpdate )
213 {
214  //model handles reordering items
215  bool result = mItemsModel->reorderItemToTop( item );
216  if ( result && !deferUpdate )
217  {
218  //update all positions
219  updateZValues();
220  update();
221  }
222  return result;
223 }
224 
225 bool QgsLayout::moveItemToBottom( QgsLayoutItem *item, bool deferUpdate )
226 {
227  //model handles reordering items
228  bool result = mItemsModel->reorderItemToBottom( item );
229  if ( result && !deferUpdate )
230  {
231  //update all positions
232  updateZValues();
233  update();
234  }
235  return result;
236 }
237 
238 QgsLayoutItem *QgsLayout::itemByUuid( const QString &uuid, bool includeTemplateUuids ) const
239 {
240  QList<QgsLayoutItem *> itemList;
241  layoutItems( itemList );
242  for ( QgsLayoutItem *item : qgis::as_const( itemList ) )
243  {
244  if ( item->uuid() == uuid )
245  return item;
246  else if ( includeTemplateUuids && item->mTemplateUuid == uuid )
247  return item;
248  }
249 
250  return nullptr;
251 }
252 
253 QgsLayoutItem *QgsLayout::itemByTemplateUuid( const QString &uuid ) const
254 {
255  QList<QgsLayoutItem *> itemList;
256  layoutItems( itemList );
257  for ( QgsLayoutItem *item : qgis::as_const( itemList ) )
258  {
259  if ( item->mTemplateUuid == uuid )
260  return item;
261  }
262 
263  return nullptr;
264 }
265 
266 QgsLayoutItem *QgsLayout::itemById( const QString &id ) const
267 {
268  const QList<QGraphicsItem *> itemList = items();
269  for ( QGraphicsItem *item : itemList )
270  {
271  QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item );
272  if ( layoutItem && layoutItem->id() == id )
273  {
274  return layoutItem;
275  }
276  }
277  return nullptr;
278 }
279 
280 QgsLayoutMultiFrame *QgsLayout::multiFrameByUuid( const QString &uuid, bool includeTemplateUuids ) const
281 {
282  for ( QgsLayoutMultiFrame *mf : mMultiFrames )
283  {
284  if ( mf->uuid() == uuid )
285  return mf;
286  else if ( includeTemplateUuids && mf->mTemplateUuid == uuid )
287  return mf;
288  }
289 
290  return nullptr;
291 }
292 
293 QgsLayoutItem *QgsLayout::layoutItemAt( QPointF position, const bool ignoreLocked ) const
294 {
295  return layoutItemAt( position, nullptr, ignoreLocked );
296 }
297 
298 QgsLayoutItem *QgsLayout::layoutItemAt( QPointF position, const QgsLayoutItem *belowItem, const bool ignoreLocked ) const
299 {
300  //get a list of items which intersect the specified position, in descending z order
301  const QList<QGraphicsItem *> itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder );
302 
303  bool foundBelowItem = false;
304  for ( QGraphicsItem *graphicsItem : itemList )
305  {
306  QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( graphicsItem );
307  QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( layoutItem );
308  if ( layoutItem && !paperItem )
309  {
310  // If we are not checking for a an item below a specified item, or if we've
311  // already found that item, then we've found our target
312  if ( ( ! belowItem || foundBelowItem ) && ( !ignoreLocked || !layoutItem->isLocked() ) )
313  {
314  return layoutItem;
315  }
316  else
317  {
318  if ( layoutItem == belowItem )
319  {
320  //Target item is next in list
321  foundBelowItem = true;
322  }
323  }
324  }
325  }
326  return nullptr;
327 }
328 
330 {
331  return mRenderContext->measurementConverter().convert( measurement, mUnits ).length();
332 }
333 
335 {
336  return mRenderContext->measurementConverter().convert( size, mUnits ).toQSizeF();
337 }
338 
339 QPointF QgsLayout::convertToLayoutUnits( const QgsLayoutPoint &point ) const
340 {
341  return mRenderContext->measurementConverter().convert( point, mUnits ).toQPointF();
342 }
343 
345 {
346  return mRenderContext->measurementConverter().convert( QgsLayoutMeasurement( length, mUnits ), unit );
347 }
348 
350 {
351  return mRenderContext->measurementConverter().convert( QgsLayoutSize( size.width(), size.height(), mUnits ), unit );
352 }
353 
355 {
356  return mRenderContext->measurementConverter().convert( QgsLayoutPoint( point.x(), point.y(), mUnits ), unit );
357 }
358 
360 {
361  return *mRenderContext;
362 }
363 
365 {
366  return *mRenderContext;
367 }
368 
370 {
371  return *mReportContext;
372 }
373 
375 {
376  return *mReportContext;
377 }
378 
380 {
381  mGridSettings.loadFromSettings();
382  mPageCollection->redraw();
383 }
384 
386 {
387  return mPageCollection->guides();
388 }
389 
391 {
392  return mPageCollection->guides();
393 }
394 
396 {
400  if ( mReportContext->layer() )
401  context.appendScope( QgsExpressionContextUtils::layerScope( mReportContext->layer() ) );
402 
404  return context;
405 }
406 
407 void QgsLayout::setCustomProperty( const QString &key, const QVariant &value )
408 {
409  mCustomProperties.setValue( key, value );
410 
411  if ( key.startsWith( QLatin1String( "variable" ) ) )
412  emit variablesChanged();
413 }
414 
415 QVariant QgsLayout::customProperty( const QString &key, const QVariant &defaultValue ) const
416 {
417  return mCustomProperties.value( key, defaultValue );
418 }
419 
420 void QgsLayout::removeCustomProperty( const QString &key )
421 {
422  mCustomProperties.remove( key );
423 }
424 
425 QStringList QgsLayout::customProperties() const
426 {
427  return mCustomProperties.keys();
428 }
429 
431 {
432  // prefer explicitly set reference map
433  if ( QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap * >( itemByUuid( mWorldFileMapId ) ) )
434  return map;
435 
436  // else try to find largest map
437  QList< QgsLayoutItemMap * > maps;
438  layoutItems( maps );
439  QgsLayoutItemMap *largestMap = nullptr;
440  double largestMapArea = 0;
441  for ( QgsLayoutItemMap *map : qgis::as_const( maps ) )
442  {
443  double area = map->rect().width() * map->rect().height();
444  if ( area > largestMapArea )
445  {
446  largestMapArea = area;
447  largestMap = map;
448  }
449  }
450  return largestMap;
451 }
452 
454 {
455  mWorldFileMapId = map ? map->uuid() : QString();
456  mProject->setDirty( true );
457 }
458 
460 {
461  return mPageCollection.get();
462 }
463 
465 {
466  return mPageCollection.get();
467 }
468 
469 QRectF QgsLayout::layoutBounds( bool ignorePages, double margin ) const
470 {
471  //start with an empty rectangle
472  QRectF bounds;
473 
474  //add all layout items and pages which are in the layout
475  const auto constItems = items();
476  for ( const QGraphicsItem *item : constItems )
477  {
478  const QgsLayoutItem *layoutItem = dynamic_cast<const QgsLayoutItem *>( item );
479  if ( !layoutItem )
480  continue;
481 
482  bool isPage = layoutItem->type() == QgsLayoutItemRegistry::LayoutPage;
483  if ( !isPage || !ignorePages )
484  {
485  //expand bounds with current item's bounds
486  QRectF itemBounds;
487  if ( isPage )
488  {
489  // for pages we only consider the item's rect - not the bounding rect
490  // as the bounding rect contains extra padding
491  itemBounds = layoutItem->mapToScene( layoutItem->rect() ).boundingRect();
492  }
493  else
494  itemBounds = item->sceneBoundingRect();
495 
496  if ( bounds.isValid() )
497  bounds = bounds.united( itemBounds );
498  else
499  bounds = itemBounds;
500  }
501  }
502 
503  if ( bounds.isValid() && margin > 0.0 )
504  {
505  //finally, expand bounds out by specified margin of page size
506  double maxWidth = mPageCollection->maximumPageWidth();
507  bounds.adjust( -maxWidth * margin, -maxWidth * margin, maxWidth * margin, maxWidth * margin );
508  }
509 
510  return bounds;
511 
512 }
513 
514 QRectF QgsLayout::pageItemBounds( int page, bool visibleOnly ) const
515 {
516  //start with an empty rectangle
517  QRectF bounds;
518 
519  //add all QgsLayoutItems on page
520  const QList<QGraphicsItem *> itemList = items();
521  for ( QGraphicsItem *item : itemList )
522  {
523  const QgsLayoutItem *layoutItem = dynamic_cast<const QgsLayoutItem *>( item );
524  if ( layoutItem && layoutItem->type() != QgsLayoutItemRegistry::LayoutPage && layoutItem->page() == page )
525  {
526  if ( visibleOnly && !layoutItem->isVisible() )
527  continue;
528 
529  //expand bounds with current item's bounds
530  if ( bounds.isValid() )
531  bounds = bounds.united( item->sceneBoundingRect() );
532  else
533  bounds = item->sceneBoundingRect();
534  }
535  }
536 
537  return bounds;
538 }
539 
541 {
542  addLayoutItemPrivate( item );
543  QString undoText;
544  if ( QgsLayoutItemAbstractMetadata *metadata = QgsApplication::layoutItemRegistry()->itemMetadata( item->type() ) )
545  {
546  undoText = tr( "Create %1" ).arg( metadata->visibleName() );
547  }
548  else
549  {
550  undoText = tr( "Create Item" );
551  }
552  if ( !mUndoStack->isBlocked() )
553  mUndoStack->push( new QgsLayoutItemAddItemCommand( item, undoText ) );
554 }
555 
557 {
558  std::unique_ptr< QgsLayoutItemDeleteUndoCommand > deleteCommand;
559  if ( !mUndoStack->isBlocked() )
560  {
561  mUndoStack->beginMacro( tr( "Delete Items" ) );
562  deleteCommand.reset( new QgsLayoutItemDeleteUndoCommand( item, tr( "Delete Item" ) ) );
563  }
564  removeLayoutItemPrivate( item );
565  if ( deleteCommand )
566  {
567  mUndoStack->push( deleteCommand.release() );
568  mUndoStack->endMacro();
569  }
570 }
571 
573 {
574  if ( !multiFrame )
575  return;
576 
577  if ( !mMultiFrames.contains( multiFrame ) )
578  mMultiFrames << multiFrame;
579 }
580 
582 {
583  mMultiFrames.removeAll( multiFrame );
584 }
585 
586 QList<QgsLayoutMultiFrame *> QgsLayout::multiFrames() const
587 {
588  return mMultiFrames;
589 }
590 
591 bool QgsLayout::saveAsTemplate( const QString &path, const QgsReadWriteContext &context ) const
592 {
593  QFile templateFile( path );
594  if ( !templateFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
595  {
596  return false;
597  }
598 
599  QDomDocument saveDocument;
600  QDomElement elem = writeXml( saveDocument, context );
601  saveDocument.appendChild( elem );
602 
603  if ( templateFile.write( saveDocument.toByteArray() ) == -1 )
604  return false;
605 
606  return true;
607 }
608 
609 QList< QgsLayoutItem * > QgsLayout::loadFromTemplate( const QDomDocument &document, const QgsReadWriteContext &context, bool clearExisting, bool *ok )
610 {
611  if ( ok )
612  *ok = false;
613 
614  QList< QgsLayoutItem * > result;
615 
616  if ( clearExisting )
617  {
618  clear();
619  }
620 
621  QDomDocument doc;
622 
623  // If this is a 2.x composition template, convert it to a layout template
625  {
626  doc = QgsCompositionConverter::convertCompositionTemplate( document, mProject );
627  }
628  else
629  {
630  doc = document;
631  }
632 
633  // remove all uuid attributes since we don't want duplicates UUIDS
634  QDomNodeList itemsNodes = doc.elementsByTagName( QStringLiteral( "LayoutItem" ) );
635  for ( int i = 0; i < itemsNodes.count(); ++i )
636  {
637  QDomNode itemNode = itemsNodes.at( i );
638  if ( itemNode.isElement() )
639  {
640  itemNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
641  }
642  }
643  QDomNodeList multiFrameNodes = doc.elementsByTagName( QStringLiteral( "LayoutMultiFrame" ) );
644  for ( int i = 0; i < multiFrameNodes.count(); ++i )
645  {
646  QDomNode multiFrameNode = multiFrameNodes.at( i );
647  if ( multiFrameNode.isElement() )
648  {
649  multiFrameNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
650  QDomNodeList frameNodes = multiFrameNode.toElement().elementsByTagName( QStringLiteral( "childFrame" ) );
651  QDomNode itemNode = frameNodes.at( i );
652  if ( itemNode.isElement() )
653  {
654  itemNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
655  }
656  }
657  }
658 
659  //read general settings
660  if ( clearExisting )
661  {
662  QDomElement layoutElem = doc.documentElement();
663  if ( layoutElem.isNull() )
664  {
665  return result;
666  }
667 
668  bool loadOk = readXml( layoutElem, doc, context );
669  if ( !loadOk )
670  {
671  return result;
672  }
673  layoutItems( result );
674  }
675  else
676  {
677  result = addItemsFromXml( doc.documentElement(), doc, context );
678  }
679 
680  if ( ok )
681  *ok = true;
682 
683  return result;
684 }
685 
687 {
688  return mUndoStack.get();
689 }
690 
692 {
693  return mUndoStack.get();
694 }
695 
698 {
699  public:
700 
701  QgsLayoutUndoCommand( QgsLayout *layout, const QString &text, int id, QUndoCommand *parent SIP_TRANSFERTHIS = nullptr )
702  : QgsAbstractLayoutUndoCommand( text, id, parent )
703  , mLayout( layout )
704  {}
705 
706  protected:
707 
708  void saveState( QDomDocument &stateDoc ) const override
709  {
710  stateDoc.clear();
711  QDomElement documentElement = stateDoc.createElement( QStringLiteral( "UndoState" ) );
712  mLayout->writeXmlLayoutSettings( documentElement, stateDoc, QgsReadWriteContext() );
713  stateDoc.appendChild( documentElement );
714  }
715 
716  void restoreState( QDomDocument &stateDoc ) override
717  {
718  if ( !mLayout )
719  {
720  return;
721  }
722 
723  mLayout->readXmlLayoutSettings( stateDoc.documentElement(), stateDoc, QgsReadWriteContext() );
724  mLayout->project()->setDirty( true );
725  }
726 
727  private:
728 
729  QgsLayout *mLayout = nullptr;
730 };
732 
733 QgsAbstractLayoutUndoCommand *QgsLayout::createCommand( const QString &text, int id, QUndoCommand *parent )
734 {
735  return new QgsLayoutUndoCommand( this, text, id, parent );
736 }
737 
738 QgsLayoutItemGroup *QgsLayout::groupItems( const QList<QgsLayoutItem *> &items )
739 {
740  if ( items.size() < 2 )
741  {
742  //not enough items for a group
743  return nullptr;
744  }
745 
746  mUndoStack->beginMacro( tr( "Group Items" ) );
747  std::unique_ptr< QgsLayoutItemGroup > itemGroup( new QgsLayoutItemGroup( this ) );
748  for ( QgsLayoutItem *item : items )
749  {
750  itemGroup->addItem( item );
751  }
752  QgsLayoutItemGroup *returnGroup = itemGroup.get();
753  addLayoutItem( itemGroup.release() );
754 
755  std::unique_ptr< QgsLayoutItemGroupUndoCommand > c( new QgsLayoutItemGroupUndoCommand( QgsLayoutItemGroupUndoCommand::Grouped, returnGroup, this, tr( "Group Items" ) ) );
756  mUndoStack->push( c.release() );
757  mProject->setDirty( true );
758 
759  mUndoStack->endMacro();
760 
761  return returnGroup;
762 }
763 
764 QList<QgsLayoutItem *> QgsLayout::ungroupItems( QgsLayoutItemGroup *group )
765 {
766  QList<QgsLayoutItem *> ungroupedItems;
767  if ( !group )
768  {
769  return ungroupedItems;
770  }
771 
772  mUndoStack->beginMacro( tr( "Ungroup Items" ) );
773  // Call this before removing group items so it can keep note
774  // of contents
775  std::unique_ptr< QgsLayoutItemGroupUndoCommand > c( new QgsLayoutItemGroupUndoCommand( QgsLayoutItemGroupUndoCommand::Ungrouped, group, this, tr( "Ungroup Items" ) ) );
776  mUndoStack->push( c.release() );
777 
778  mProject->setDirty( true );
779 
780  ungroupedItems = group->items();
781  group->removeItems();
782 
783  removeLayoutItem( group );
784  mUndoStack->endMacro();
785 
786  return ungroupedItems;
787 }
788 
790 {
791  const QList< QGraphicsItem * > constItems = items();
792  for ( const QGraphicsItem *item : constItems )
793  {
794  const QgsLayoutItem *layoutItem = dynamic_cast<const QgsLayoutItem *>( item );
795  if ( !layoutItem )
796  continue;
797 
798  if ( !layoutItem->accept( visitor ) )
799  return false;
800  }
801  return true;
802 }
803 
805 {
806  mUndoStack->blockCommands( true );
807  mPageCollection->beginPageSizeChange();
808  emit refreshed();
809  mPageCollection->reflow();
810  mPageCollection->endPageSizeChange();
811  mUndoStack->blockCommands( false );
812  update();
813 }
814 
815 void QgsLayout::writeXmlLayoutSettings( QDomElement &element, QDomDocument &document, const QgsReadWriteContext & ) const
816 {
817  mCustomProperties.writeXml( element, document );
818  element.setAttribute( QStringLiteral( "units" ), QgsUnitTypes::encodeUnit( mUnits ) );
819  element.setAttribute( QStringLiteral( "worldFileMap" ), mWorldFileMapId );
820  element.setAttribute( QStringLiteral( "printResolution" ), mRenderContext->dpi() );
821 }
822 
823 QDomElement QgsLayout::writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const
824 {
825  QDomElement element = document.createElement( QStringLiteral( "Layout" ) );
826  auto save = [&]( const QgsLayoutSerializableObject * object )->bool
827  {
828  return object->writeXml( element, document, context );
829  };
830  save( &mSnapper );
831  save( &mGridSettings );
832  save( mPageCollection.get() );
833 
834  //save items except paper items and frame items (they are saved with the corresponding multiframe)
835  const QList<QGraphicsItem *> itemList = items();
836  for ( const QGraphicsItem *graphicsItem : itemList )
837  {
838  if ( const QgsLayoutItem *item = dynamic_cast< const QgsLayoutItem *>( graphicsItem ) )
839  {
840  if ( item->type() == QgsLayoutItemRegistry::LayoutPage )
841  continue;
842 
843  item->writeXml( element, document, context );
844  }
845  }
846 
847  //save multiframes
848  for ( QgsLayoutMultiFrame *mf : mMultiFrames )
849  {
850  if ( mf->frameCount() > 0 )
851  mf->writeXml( element, document, context );
852  }
853 
854  writeXmlLayoutSettings( element, document, context );
855  return element;
856 }
857 
858 bool QgsLayout::readXmlLayoutSettings( const QDomElement &layoutElement, const QDomDocument &, const QgsReadWriteContext & )
859 {
860  mCustomProperties.readXml( layoutElement );
861  setUnits( QgsUnitTypes::decodeLayoutUnit( layoutElement.attribute( QStringLiteral( "units" ) ) ) );
862  mWorldFileMapId = layoutElement.attribute( QStringLiteral( "worldFileMap" ) );
863  mRenderContext->setDpi( layoutElement.attribute( QStringLiteral( "printResolution" ), QStringLiteral( "300" ) ).toDouble() );
864  emit changed();
865 
866  return true;
867 }
868 
869 void QgsLayout::addLayoutItemPrivate( QgsLayoutItem *item )
870 {
871  addItem( item );
872  updateBounds();
873  mItemsModel->rebuildZList();
874  connect( item, &QgsLayoutItem::backgroundTaskCountChanged, this, &QgsLayout::itemBackgroundTaskCountChanged );
875 }
876 
877 void QgsLayout::removeLayoutItemPrivate( QgsLayoutItem *item )
878 {
879  mItemsModel->setItemRemoved( item );
880  // small chance that item is still in a scene - the model may have
881  // rejected the removal for some reason. This is probably not necessary,
882  // but can't hurt...
883  if ( item->scene() )
884  removeItem( item );
885 #if 0 //TODO
886  emit itemRemoved( item );
887 #endif
888  item->cleanup();
889  item->deleteLater();
890 }
891 
892 void QgsLayout::deleteAndRemoveMultiFrames()
893 {
894  qDeleteAll( mMultiFrames );
895  mMultiFrames.clear();
896 }
897 
898 QPointF QgsLayout::minPointFromXml( const QDomElement &elem ) const
899 {
900  double minX = std::numeric_limits<double>::max();
901  double minY = std::numeric_limits<double>::max();
902  const QDomNodeList itemList = elem.elementsByTagName( QStringLiteral( "LayoutItem" ) );
903  bool found = false;
904  for ( int i = 0; i < itemList.size(); ++i )
905  {
906  const QDomElement currentItemElem = itemList.at( i ).toElement();
907 
908  QgsLayoutPoint pos = QgsLayoutPoint::decodePoint( currentItemElem.attribute( QStringLiteral( "position" ) ) );
909  QPointF layoutPoint = convertToLayoutUnits( pos );
910 
911  minX = std::min( minX, layoutPoint.x() );
912  minY = std::min( minY, layoutPoint.y() );
913  found = true;
914  }
915  return found ? QPointF( minX, minY ) : QPointF( 0, 0 );
916 }
917 
918 void QgsLayout::updateZValues( const bool addUndoCommands )
919 {
920  int counter = mItemsModel->zOrderListSize();
921  const QList<QgsLayoutItem *> zOrderList = mItemsModel->zOrderList();
922 
923  if ( addUndoCommands )
924  {
925  mUndoStack->beginMacro( tr( "Change Item Stacking" ) );
926  }
927  for ( QgsLayoutItem *currentItem : zOrderList )
928  {
929  if ( currentItem )
930  {
931  if ( addUndoCommands )
932  {
933  mUndoStack->beginCommand( currentItem, QString() );
934  }
935  currentItem->setZValue( counter );
936  if ( addUndoCommands )
937  {
938  mUndoStack->endCommand();
939  }
940  }
941  --counter;
942  }
943  if ( addUndoCommands )
944  {
945  mUndoStack->endMacro();
946  }
947 }
948 
949 bool QgsLayout::readXml( const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context )
950 {
951  if ( layoutElement.nodeName() != QStringLiteral( "Layout" ) )
952  {
953  return false;
954  }
955 
956  auto restore = [&]( QgsLayoutSerializableObject * object )->bool
957  {
958  return object->readXml( layoutElement, document, context );
959  };
960 
961  std::unique_ptr< QgsScopedRuntimeProfile > profile;
962  if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
963  profile = qgis::make_unique< QgsScopedRuntimeProfile >( tr( "Read layout settings" ), QStringLiteral( "projectload" ) );
964 
965  blockSignals( true ); // defer changed signal to end
966  readXmlLayoutSettings( layoutElement, document, context );
967  blockSignals( false );
968 
969  if ( profile )
970  profile->switchTask( tr( "Load pages" ) );
971  restore( mPageCollection.get() );
972  if ( profile )
973  profile->switchTask( tr( "Load snapping settings" ) );
974  restore( &mSnapper );
975  if ( profile )
976  profile->switchTask( tr( "Load grid settings" ) );
977  restore( &mGridSettings );
978 
979  if ( profile )
980  profile->switchTask( tr( "Restore items" ) );
981  addItemsFromXml( layoutElement, document, context );
982 
983  emit changed();
984 
985  return true;
986 }
987 
988 QList< QgsLayoutItem * > QgsLayout::addItemsFromXml( const QDomElement &parentElement, const QDomDocument &document, const QgsReadWriteContext &context, QPointF *position, bool pasteInPlace )
989 {
990  QList< QgsLayoutItem * > newItems;
991  QList< QgsLayoutMultiFrame * > newMultiFrames;
992 
993  //if we are adding items to a layout which already contains items, we need to make sure
994  //these items are placed at the top of the layout and that zValues are not duplicated
995  //so, calculate an offset which needs to be added to the zValue of created items
996  int zOrderOffset = mItemsModel->zOrderListSize();
997 
998  QPointF pasteShiftPos;
999  int pageNumber = -1;
1000  if ( position )
1001  {
1002  //If we are placing items relative to a certain point, then calculate how much we need
1003  //to shift the items by so that they are placed at this point
1004  //First, calculate the minimum position from the xml
1005  QPointF minItemPos = minPointFromXml( parentElement );
1006  //next, calculate how much each item needs to be shifted from its original position
1007  //so that it's placed at the correct relative position
1008  pasteShiftPos = *position - minItemPos;
1009  if ( pasteInPlace )
1010  {
1011  pageNumber = mPageCollection->pageNumberForPoint( *position );
1012  }
1013  }
1014 
1015  std::unique_ptr< QgsScopedRuntimeProfile > profile;
1016  if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
1017  profile = qgis::make_unique< QgsScopedRuntimeProfile >( tr( "Read items" ), QStringLiteral( "projectload" ) );
1018 
1019  // multiframes
1020 
1021  //TODO - fix this. pasting multiframe frame items has no effect
1022  const QDomNodeList multiFrameList = parentElement.elementsByTagName( QStringLiteral( "LayoutMultiFrame" ) );
1023  for ( int i = 0; i < multiFrameList.size(); ++i )
1024  {
1025  const QDomElement multiFrameElem = multiFrameList.at( i ).toElement();
1026  const int itemType = multiFrameElem.attribute( QStringLiteral( "type" ) ).toInt();
1027 
1028  if ( profile )
1029  {
1030  if ( QgsLayoutMultiFrameAbstractMetadata *metadata = QgsApplication::layoutItemRegistry()->multiFrameMetadata( itemType ) )
1031  {
1032  profile->switchTask( tr( "Load %1" ).arg( metadata->visibleName() ) );
1033  }
1034  }
1035 
1036  std::unique_ptr< QgsLayoutMultiFrame > mf( QgsApplication::layoutItemRegistry()->createMultiFrame( itemType, this ) );
1037  if ( !mf )
1038  {
1039  // e.g. plugin based item which is no longer available
1040  continue;
1041  }
1042  mf->readXml( multiFrameElem, document, context );
1043 
1044 #if 0 //TODO?
1045  mf->setCreateUndoCommands( true );
1046 #endif
1047 
1048  QgsLayoutMultiFrame *m = mf.get();
1049  this->addMultiFrame( mf.release() );
1050 
1051  //offset z values for frames
1052  //TODO - fix this after fixing multiframe item paste
1053  /*for ( int frameIdx = 0; frameIdx < mf->frameCount(); ++frameIdx )
1054  {
1055  QgsLayoutItemFrame * frame = mf->frame( frameIdx );
1056  frame->setZValue( frame->zValue() + zOrderOffset );
1057 
1058  // also need to shift frames according to position/pasteInPlacePt
1059  }*/
1060  newMultiFrames << m;
1061  }
1062 
1063  const QDomNodeList layoutItemList = parentElement.childNodes();
1064  for ( int i = 0; i < layoutItemList.size(); ++i )
1065  {
1066  const QDomElement currentItemElem = layoutItemList.at( i ).toElement();
1067  if ( currentItemElem.nodeName() != QStringLiteral( "LayoutItem" ) )
1068  continue;
1069 
1070  const int itemType = currentItemElem.attribute( QStringLiteral( "type" ) ).toInt();
1071 
1072  if ( profile )
1073  {
1074  if ( QgsLayoutItemAbstractMetadata *metadata = QgsApplication::layoutItemRegistry()->itemMetadata( itemType ) )
1075  {
1076  profile->switchTask( tr( "Load %1" ).arg( metadata->visibleName() ) );
1077  }
1078  }
1079 
1080  std::unique_ptr< QgsLayoutItem > item( QgsApplication::layoutItemRegistry()->createItem( itemType, this ) );
1081  if ( !item )
1082  {
1083  // e.g. plugin based item which is no longer available
1084  continue;
1085  }
1086 
1087  item->readXml( currentItemElem, document, context );
1088  if ( position )
1089  {
1090  if ( pasteInPlace )
1091  {
1092  QgsLayoutPoint posOnPage = QgsLayoutPoint::decodePoint( currentItemElem.attribute( QStringLiteral( "positionOnPage" ) ) );
1093  item->attemptMove( posOnPage, true, false, pageNumber );
1094  }
1095  else
1096  {
1097  item->attemptMoveBy( pasteShiftPos.x(), pasteShiftPos.y() );
1098  }
1099  }
1100 
1101  QgsLayoutItem *layoutItem = item.get();
1102  addLayoutItem( item.release() );
1103  layoutItem->setZValue( layoutItem->zValue() + zOrderOffset );
1104  newItems << layoutItem;
1105  }
1106 
1107  // we now allow items to "post-process", e.g. if they need to setup connections
1108  // to other items in the layout, which may not have existed at the time the
1109  // item's state was restored. E.g. a scalebar may have been restored before the map
1110  // it is linked to
1111  std::unique_ptr< QgsScopedRuntimeProfile > itemProfile;
1112  if ( profile )
1113  {
1114  profile->switchTask( tr( "Finalize restore" ) );
1115  }
1116  for ( QgsLayoutItem *item : qgis::as_const( newItems ) )
1117  {
1118  if ( profile )
1119  itemProfile = qgis::make_unique< QgsScopedRuntimeProfile >( item->displayName(), QStringLiteral( "projectload" ) );
1120  item->finalizeRestoreFromXml();
1121  if ( itemProfile )
1122  itemProfile.reset();
1123  }
1124  for ( QgsLayoutMultiFrame *mf : qgis::as_const( newMultiFrames ) )
1125  {
1126  if ( profile )
1127  itemProfile = qgis::make_unique< QgsScopedRuntimeProfile >( mf->displayName(), QStringLiteral( "projectload" ) );
1128  mf->finalizeRestoreFromXml();
1129  if ( itemProfile )
1130  itemProfile.reset();
1131  }
1132 
1133  for ( QgsLayoutItem *item : qgis::as_const( newItems ) )
1134  {
1135  item->mTemplateUuid.clear();
1136  }
1137  for ( QgsLayoutMultiFrame *mf : qgis::as_const( newMultiFrames ) )
1138  {
1139  mf->mTemplateUuid.clear();
1140  }
1141 
1142  //Since this function adds items in an order which isn't the z-order, and each item is added to end of
1143  //z order list in turn, it will now be inconsistent with the actual order of items in the scene.
1144  //Make sure z order list matches the actual order of items in the scene.
1145 
1146  if ( profile )
1147  profile->switchTask( tr( "Update model" ) );
1148  mItemsModel->rebuildZList();
1149 
1150  return newItems;
1151 }
1152 
1154 {
1155  setSceneRect( layoutBounds( false, 0.05 ) );
1156 }
1157 
1158 void QgsLayout::itemBackgroundTaskCountChanged( int count )
1159 {
1160  QgsLayoutItem *item = qobject_cast<QgsLayoutItem *>( sender() );
1161  if ( !item )
1162  return;
1163 
1164  if ( count > 0 )
1165  mBackgroundTaskCount.insert( item, count );
1166  else
1167  mBackgroundTaskCount.remove( item );
1168 
1169  // sum up new count of background tasks
1170  int total = 0;
1171  for ( auto it = mBackgroundTaskCount.constBegin(); it != mBackgroundTaskCount.constEnd(); ++it )
1172  {
1173  total += it.value();
1174  }
1175 
1176  emit backgroundTaskCountChanged( total );
1177 }
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:510
The class is used as a container of context for various read/write operations on other objects...
void removeItems()
Removes all items from the group (but does not delete them).
void setSelectedItem(QgsLayoutItem *item)
Clears any selected items and sets item as the current selection.
Definition: qgslayout.cpp:159
bool raiseItem(QgsLayoutItem *item, bool deferUpdate=false)
Raises an item up the z-order.
Definition: qgslayout.cpp:186
QgsLayoutGuideCollection & guides()
Returns a reference to the layout&#39;s guide collection, which manages page snap guides.
Definition: qgslayout.cpp:385
QgsLayoutItem * itemById(const QString &id) const
Returns a layout item given its id.
Definition: qgslayout.cpp:266
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
QgsLayout * clone() const
Creates a clone of the layout.
Definition: qgslayout.cpp:83
void backgroundTaskCountChanged(int total)
Emitted whenever the total number of background tasks running in items from the layout changes...
Base class for graphical items within a QgsLayout.
#define SIP_TRANSFERTHIS
Definition: qgis_sip.h:53
int type() const override
Returns a unique graphics item type identifier.
QgsLayoutMultiFrame * multiFrameByUuid(const QString &uuid, bool includeTemplateUuids=false) const
Returns the layout multiframe with matching uuid unique identifier, or nullptr if a matching multifra...
Definition: qgslayout.cpp:280
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
Base class for commands to undo/redo layout and layout object changes.
QgsLayoutUndoStack * undoStack()
Returns a pointer to the layout&#39;s undo stack, which manages undo/redo states for the layout and it&#39;s ...
Definition: qgslayout.cpp:686
friend class QgsLayoutModel
Definition: qgslayout.h:765
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from the layout.
Definition: qgslayout.cpp:415
QgsLayoutMeasurement convert(QgsLayoutMeasurement measurement, QgsUnitTypes::LayoutUnit targetUnits) const
Converts a measurement from one unit to another.
Stores information relating to the current reporting context for a layout.
QgsLayoutItemGroup * groupItems(const QList< QgsLayoutItem *> &items)
Creates a new group from a list of layout items and adds the group to the layout. ...
Definition: qgslayout.cpp:738
virtual bool readXml(const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context)
Sets the collection&#39;s state from a DOM element.
Definition: qgslayout.cpp:949
An undo stack for QgsLayouts.
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
void loadFromSettings()
Loads grid settings from the application layout settings.
A container for grouping several QgsLayoutItems.
static QDomDocument convertCompositionTemplate(const QDomDocument &document, QgsProject *project)
Convert a composition template document to a layout template.
virtual void setSelected(bool selected)
Sets whether the item should be selected.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Returns the value for the given key.
QList< QgsLayoutItem *> addItemsFromXml(const QDomElement &parentElement, const QDomDocument &document, const QgsReadWriteContext &context, QPointF *position=nullptr, bool pasteInPlace=false)
Add items from an XML representation to the layout.
Definition: qgslayout.cpp:988
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
void setUnits(QgsUnitTypes::LayoutUnit units)
Sets the native measurement units for the layout.
Definition: qgslayout.h:321
Stores metadata about one layout item class.
QList< QgsLayoutItem * > ungroupItems(QgsLayoutItemGroup *group)
Ungroups items by removing them from an item group and removing the group from the layout...
Definition: qgslayout.cpp:764
An interface for classes which can visit style entity (e.g.
Stores metadata about one layout multiframe class.
void updateBounds()
Updates the scene bounds of the layout.
Definition: qgslayout.cpp:1153
QgsLayoutRenderContext & renderContext()
Returns a reference to the layout&#39;s render context, which stores information relating to the current ...
Definition: qgslayout.cpp:359
void remove(const QString &key)
Removes a key (entry) from the store.
QList< QgsLayoutMultiFrame *> multiFrames() const
Returns a list of multi frames contained in the layout.
Definition: qgslayout.cpp:586
Abstract base class for layout items with the ability to distribute the content to several frames (Qg...
This class provides a method of storing points, consisting of an x and y coordinate, for use in QGIS layouts.
void layoutItems(QList< T *> &itemList) const
Returns a list of layout items of a specific type.
Definition: qgslayout.h:121
void removeCustomProperty(const QString &key)
Remove a custom property from the layout.
Definition: qgslayout.cpp:420
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
void deselectAll()
Clears any selected items in the layout.
Definition: qgslayout.cpp:169
void updateZValues(bool addUndoCommands=true)
Resets the z-values of items based on their position in the internal z order list.
Definition: qgslayout.cpp:918
QgsVectorLayer * layer() const
Returns the vector layer associated with the layout&#39;s context.
static QgsLayoutItemRegistry * layoutItemRegistry()
Returns the application&#39;s layout item registry, used for layout item types.
Layout graphical items for displaying a map.
void backgroundTaskCountChanged(int count)
Emitted whenever the number of background tasks an item is executing changes.
void setValue(const QString &key, const QVariant &value)
Add an entry to the store with the specified key.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
void variablesChanged()
Emitted whenever the expression variables stored in the layout have been changed. ...
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
static bool isCompositionTemplate(const QDomDocument &document)
Check if the given document is a composition template.
static Q_INVOKABLE QgsUnitTypes::LayoutUnit decodeLayoutUnit(const QString &string, bool *ok=nullptr)
Decodes a layout unit from a string.
void refresh()
Forces the layout, and all items contained within it, to refresh.
Definition: qgslayout.cpp:804
QStringList customProperties() const
Returns list of keys stored in custom properties for the layout.
Definition: qgslayout.cpp:425
QList< QgsLayoutItem * > items() const
Returns a list of items contained by the group.
QgsLayoutPageCollection * pageCollection()
Returns a pointer to the layout&#39;s page collection, which stores and manages page items in the layout...
Definition: qgslayout.cpp:459
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QList< QgsLayoutItem * > selectedLayoutItems(bool includeLockedItems=true)
Returns list of selected layout items.
Definition: qgslayout.cpp:142
QList< QgsLayoutItem *> loadFromTemplate(const QDomDocument &document, const QgsReadWriteContext &context, bool clearExisting=true, bool *ok=nullptr)
Load a layout template document.
Definition: qgslayout.cpp:609
void selectedItemChanged(QgsLayoutItem *selected)
Emitted whenever the selected item changes.
virtual void cleanup()
Called just before a batch of items are deleted, allowing them to run cleanup tasks.
void removeMultiFrame(QgsLayoutMultiFrame *multiFrame)
Removes a multiFrame from the layout (but does not delete it).
Definition: qgslayout.cpp:581
Stores and manages the snap guides used by a layout.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc.
Definition: qgsproject.h:92
int page() const
Returns the page the item is currently on, with the first page returning 0.
QString id() const
Returns the item&#39;s ID name.
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:49
QStringList keys() const
Returns a list of all stored keys.
A manager for a collection of pages in a layout.
QRectF pageItemBounds(int page, bool visibleOnly=false) const
Returns the bounding box of the items contained on a specified page.
Definition: qgslayout.cpp:514
bool lowerItem(QgsLayoutItem *item, bool deferUpdate=false)
Lowers an item down the z-order.
Definition: qgslayout.cpp:199
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
QgsLayoutModel * itemsModel()
Returns the items model attached to the layout.
Definition: qgslayout.cpp:137
friend class QgsLayoutItemAddItemCommand
Definition: qgslayout.h:760
virtual void finalizeRestoreFromXml()
Called after all pending items have been restored from XML.
virtual QString displayName() const
Gets item display name.
QgsLayoutReportContext & reportContext()
Returns a reference to the layout&#39;s report context, which stores information relating to the current ...
Definition: qgslayout.cpp:369
friend class QgsLayoutUndoCommand
Definition: qgslayout.h:763
QgsExpressionContext createExpressionContext() const override
Creates an expression context relating to the layout&#39;s current state.
Definition: qgslayout.cpp:395
bool moveItemToBottom(QgsLayoutItem *item, bool deferUpdate=false)
Lowers an item down to the bottom of the z-order.
Definition: qgslayout.cpp:225
void clear()
Clears the layout.
Definition: qgslayout.cpp:111
QgsLayoutItemMap * referenceMap() const
Returns the map item which will be used to generate corresponding world files when the layout is expo...
Definition: qgslayout.cpp:430
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:262
double length() const
Returns the length of the measurement.
bool saveAsTemplate(const QString &path, const QgsReadWriteContext &context) const
Saves the layout as a template at the given file path.
Definition: qgslayout.cpp:591
const QgsLayoutMeasurementConverter & measurementConverter() const
Returns the layout measurement converter to be used in the layout.
void removeLayoutItem(QgsLayoutItem *item)
Removes an item from the layout.
Definition: qgslayout.cpp:556
static QgsExpressionContextScope * layoutScope(const QgsLayout *layout)
Creates a new scope which contains variables and functions relating to a QgsLayout layout...
void refreshed()
Emitted when the layout has been refreshed and items should also be refreshed and updated...
friend class QgsLayoutItemGroupUndoCommand
Definition: qgslayout.h:764
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
virtual QString uuid() const
Returns the item identification string.
void addLayoutItem(QgsLayoutItem *item)
Adds an item to the layout.
Definition: qgslayout.cpp:540
QgsLayoutMeasurement convertFromLayoutUnits(double length, QgsUnitTypes::LayoutUnit unit) const
Converts a length measurement from the layout&#39;s native units to a specified target unit...
Definition: qgslayout.cpp:344
Stores information relating to the current rendering settings for a layout.
void setReferenceMap(QgsLayoutItemMap *map)
Sets the map item which will be used to generate corresponding world files when the layout is exporte...
Definition: qgslayout.cpp:453
An interface for layout objects which can be stored and read from DOM elements.
~QgsLayout() override
Definition: qgslayout.cpp:50
void initializeDefaults()
Initializes an empty layout, e.g.
Definition: qgslayout.cpp:102
QgsProject * project() const
The project associated with the layout.
Definition: qgslayout.cpp:132
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for the layout.
Definition: qgslayout.cpp:407
LayoutUnit
Layout measurement units.
Definition: qgsunittypes.h:180
virtual QDomElement writeXml(QDomDocument &document, const QgsReadWriteContext &context) const
Returns the layout&#39;s state encapsulated in a DOM element.
Definition: qgslayout.cpp:823
bool isLocked() const
Returns true if the item is locked, and cannot be interacted with using the mouse.
QgsAbstractLayoutUndoCommand * createCommand(const QString &text, int id=0, QUndoCommand *parent=nullptr) override
Creates a new layout undo command with the specified text and parent.
Definition: qgslayout.cpp:733
void setPageSize(const QgsLayoutSize &size)
Sets the size of the page.
double convertToLayoutUnits(QgsLayoutMeasurement measurement) const
Converts a measurement into the layout&#39;s native units.
Definition: qgslayout.cpp:329
A model for items attached to a layout.
Manages snapping grids and preset snap lines in a layout, and handles snapping points to the nearest ...
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
Definition: qgslayoutsize.h:40
void changed()
Emitted when properties of the layout change.
QgsLayoutItem * layoutItemAt(QPointF position, bool ignoreLocked=false) const
Returns the topmost layout item at a specified position.
Definition: qgslayout.cpp:293
bool moveItemToTop(QgsLayoutItem *item, bool deferUpdate=false)
Raises an item up to the top of the z-order.
Definition: qgslayout.cpp:212
bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
Definition: qgslayout.cpp:789
QgsLayoutItem * itemByTemplateUuid(const QString &uuid) const
Returns the layout item with matching template uuid unique identifier, or nullptr if a matching item ...
Definition: qgslayout.cpp:253
void reloadSettings()
Refreshes the layout when global layout related options change.
Definition: qgslayout.cpp:379
void addMultiFrame(QgsLayoutMultiFrame *multiFrame)
Adds a multiFrame to the layout.
Definition: qgslayout.cpp:572
QgsLayout(QgsProject *project)
Construct a new layout linked to the specified project.
Definition: qgslayout.cpp:36
static QgsLayoutPoint decodePoint(const QString &string)
Decodes a point from a string.
Item representing the paper in a layout.
friend class QgsLayoutItemDeleteUndoCommand
Definition: qgslayout.h:761