QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
qgscompositionconverter.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscompositionconverter.cpp - QgsCompositionConverter
3 
4  ---------------------
5  begin : 13.12.2017
6  copyright : (C) 2017 by Alessandro Pasotti
7  email : elpaso at itopen dot it
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 <QObject>
18 
20 #include "qgsreadwritecontext.h"
21 #include "qgslayertree.h"
22 #include "qgslayoutmodel.h"
23 #include "qgslayoutitemgroup.h"
24 #include "qgslayoutobject.h"
25 #include "qgsfontutils.h"
26 #include "qgspainting.h"
27 #include "qgsproperty.h"
28 #include "qgssymbollayerutils.h"
29 #include "qgssymbollayer.h"
30 #include "qgsproject.h"
32 #include "qgsvectorlayer.h"
33 
34 #include "qgsprintlayout.h"
35 #include "qgslayoutatlas.h"
36 
37 #include "qgslayoutundostack.h"
39 #include "qgslayoutitemregistry.h"
40 #include "qgslayoutitemlabel.h"
41 #include "qgslayoutitemshape.h"
42 #include "qgslayoutitempicture.h"
43 #include "qgslayoutitempolygon.h"
44 #include "qgslayoutitempolyline.h"
45 #include "qgslayoutitemmap.h"
46 #include "qgslayoutitemmapgrid.h"
47 #include "qgslayoutitemscalebar.h"
48 #include "qgslayoutitemlegend.h"
49 #include "qgslayoutitemhtml.h"
50 #include "qgslayouttable.h"
52 #include "qgslayouttablecolumn.h"
53 #include "qgslayoutmultiframe.h"
54 #include "qgslayoutframe.h"
56 
57 QgsPropertiesDefinition QgsCompositionConverter::sPropertyDefinitions;
58 
59 void QgsCompositionConverter::initPropertyDefinitions()
60 {
61  if ( !sPropertyDefinitions.isEmpty() )
62  return;
63 
64  sPropertyDefinitions = QgsPropertiesDefinition
65  {
66  { QgsCompositionConverter::TestProperty, QgsPropertyDefinition( "dataDefinedProperty", QgsPropertyDefinition::DataTypeString, "invalid property", QString() ) },
67  {
68  QgsCompositionConverter::PresetPaperSize, QgsPropertyDefinition( "dataDefinedPaperSize", QgsPropertyDefinition::DataTypeString, QObject::tr( "Paper size" ), QObject::tr( "string " ) + QStringLiteral( "[<b>A5</b>|<b>A4</b>|<b>A3</b>|<b>A2</b>|<b>A1</b>|<b>A0</b>"
69  "|<b>B5</b>|<b>B4</b>|<b>B3</b>|<b>B2</b>|<b>B1</b>|<b>B0</b>"
70  "|<b>Legal</b>|<b>Ansi A</b>|<b>Ansi B</b>|<b>Ansi C</b>|<b>Ansi D</b>|<b>Ansi E</b>"
71  "|<b>Arch A</b>|<b>Arch B</b>|<b>Arch C</b>|<b>Arch D</b>|<b>Arch E</b>|<b>Arch E1</b>]"
72  ) )
73  },
74  { QgsCompositionConverter::PaperWidth, QgsPropertyDefinition( "dataDefinedPaperWidth", QObject::tr( "Page width" ), QgsPropertyDefinition::DoublePositive ) },
75  { QgsCompositionConverter::PaperHeight, QgsPropertyDefinition( "dataDefinedPaperHeight", QObject::tr( "Page height" ), QgsPropertyDefinition::DoublePositive ) },
76  { QgsCompositionConverter::NumPages, QgsPropertyDefinition( "dataDefinedNumPages", QObject::tr( "Number of pages" ), QgsPropertyDefinition::IntegerPositive ) },
77  { QgsCompositionConverter::PaperOrientation, QgsPropertyDefinition( "dataDefinedPaperOrientation", QgsPropertyDefinition::DataTypeString, QObject::tr( "Symbol size" ), QObject::tr( "string " ) + QStringLiteral( "[<b>portrait</b>|<b>landscape</b>]" ) ) },
78  { QgsCompositionConverter::PageNumber, QgsPropertyDefinition( "dataDefinedPageNumber", QObject::tr( "Page number" ), QgsPropertyDefinition::IntegerPositive ) },
79  { QgsCompositionConverter::PositionX, QgsPropertyDefinition( "dataDefinedPositionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double ) },
80  { QgsCompositionConverter::PositionY, QgsPropertyDefinition( "dataDefinedPositionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double ) },
82  { QgsCompositionConverter::ItemHeight, QgsPropertyDefinition( "dataDefinedHeight", QObject::tr( "Height" ), QgsPropertyDefinition::DoublePositive ) },
83  { QgsCompositionConverter::ItemRotation, QgsPropertyDefinition( "dataDefinedRotation", QObject::tr( "Rotation angle" ), QgsPropertyDefinition::Rotation ) },
84  { QgsCompositionConverter::Transparency, QgsPropertyDefinition( "dataDefinedTransparency", QObject::tr( "Transparency" ), QgsPropertyDefinition::Opacity ) },
85  { QgsCompositionConverter::Opacity, QgsPropertyDefinition( "dataDefinedOpacity", QObject::tr( "Opacity" ), QgsPropertyDefinition::Opacity ) },
86  { QgsCompositionConverter::BlendMode, QgsPropertyDefinition( "dataDefinedBlendMode", QObject::tr( "Blend mode" ), QgsPropertyDefinition::BlendMode ) },
87  { QgsCompositionConverter::ExcludeFromExports, QgsPropertyDefinition( "dataDefinedExcludeExports", QObject::tr( "Exclude item from exports" ), QgsPropertyDefinition::Boolean ) },
88  { QgsCompositionConverter::FrameColor, QgsPropertyDefinition( "dataDefinedFrameColor", QObject::tr( "Frame color" ), QgsPropertyDefinition::ColorWithAlpha ) },
89  { QgsCompositionConverter::BackgroundColor, QgsPropertyDefinition( "dataDefinedBackgroundColor", QObject::tr( "Background color" ), QgsPropertyDefinition::ColorWithAlpha ) },
90  { QgsCompositionConverter::MapRotation, QgsPropertyDefinition( "dataDefinedMapRotation", QObject::tr( "Map rotation" ), QgsPropertyDefinition::Rotation ) },
91  { QgsCompositionConverter::MapScale, QgsPropertyDefinition( "dataDefinedMapScale", QObject::tr( "Map scale" ), QgsPropertyDefinition::DoublePositive ) },
92  { QgsCompositionConverter::MapXMin, QgsPropertyDefinition( "dataDefinedMapXMin", QObject::tr( "Extent minimum X" ), QgsPropertyDefinition::Double ) },
93  { QgsCompositionConverter::MapYMin, QgsPropertyDefinition( "dataDefinedMapYMin", QObject::tr( "Extent minimum Y" ), QgsPropertyDefinition::Double ) },
94  { QgsCompositionConverter::MapXMax, QgsPropertyDefinition( "dataDefinedMapXMax", QObject::tr( "Extent maximum X" ), QgsPropertyDefinition::Double ) },
95  { QgsCompositionConverter::MapYMax, QgsPropertyDefinition( "dataDefinedMapYMax", QObject::tr( "Extent maximum Y" ), QgsPropertyDefinition::Double ) },
96  { QgsCompositionConverter::MapAtlasMargin, QgsPropertyDefinition( "dataDefinedMapAtlasMargin", QObject::tr( "Atlas margin" ), QgsPropertyDefinition::DoublePositive ) },
97  { QgsCompositionConverter::MapLayers, QgsPropertyDefinition( "dataDefinedMapLayers", QgsPropertyDefinition::DataTypeString, QObject::tr( "Symbol size" ), QObject::tr( "list of map layer names separated by | characters" ) ) },
98  { QgsCompositionConverter::MapStylePreset, QgsPropertyDefinition( "dataDefinedMapStylePreset", QgsPropertyDefinition::DataTypeString, QObject::tr( "Symbol size" ), QObject::tr( "list of map layer names separated by | characters" ) ) },
99  { QgsCompositionConverter::PictureSource, QgsPropertyDefinition( "dataDefinedSource", QObject::tr( "Picture source (URL)" ), QgsPropertyDefinition::String ) },
100  { QgsCompositionConverter::SourceUrl, QgsPropertyDefinition( "dataDefinedSourceUrl", QObject::tr( "Source URL" ), QgsPropertyDefinition::String ) },
101  { QgsCompositionConverter::PictureSvgBackgroundColor, QgsPropertyDefinition( "dataDefinedSvgBackgroundColor", QObject::tr( "SVG background color" ), QgsPropertyDefinition::ColorWithAlpha ) },
102  { QgsCompositionConverter::PictureSvgStrokeColor, QgsPropertyDefinition( "dataDefinedSvgStrokeColor", QObject::tr( "SVG stroke color" ), QgsPropertyDefinition::ColorWithAlpha ) },
103  { QgsCompositionConverter::PictureSvgStrokeWidth, QgsPropertyDefinition( "dataDefinedSvgStrokeWidth", QObject::tr( "SVG stroke width" ), QgsPropertyDefinition::StrokeWidth ) },
104  { QgsCompositionConverter::LegendTitle, QgsPropertyDefinition( "dataDefinedLegendTitle", QObject::tr( "Legend title" ), QgsPropertyDefinition::String ) },
105  { QgsCompositionConverter::LegendColumnCount, QgsPropertyDefinition( "dataDefinedLegendColumns", QObject::tr( "Number of columns" ), QgsPropertyDefinition::IntegerPositiveGreaterZero ) },
106  { QgsCompositionConverter::ScalebarFillColor, QgsPropertyDefinition( "dataDefinedScalebarFill", QObject::tr( "Fill color" ), QgsPropertyDefinition::ColorWithAlpha ) },
107  { QgsCompositionConverter::ScalebarFillColor2, QgsPropertyDefinition( "dataDefinedScalebarFill2", QObject::tr( "Secondary fill color" ), QgsPropertyDefinition::ColorWithAlpha ) },
108  { QgsCompositionConverter::ScalebarLineColor, QgsPropertyDefinition( "dataDefinedScalebarLineColor", QObject::tr( "Line color" ), QgsPropertyDefinition::ColorWithAlpha ) },
109  { QgsCompositionConverter::ScalebarLineWidth, QgsPropertyDefinition( "dataDefinedScalebarLineWidth", QObject::tr( "Line width" ), QgsPropertyDefinition::StrokeWidth ) },
110  };
111 }
112 
113 QgsPropertiesDefinition QgsCompositionConverter::propertyDefinitions()
114 {
115  QgsCompositionConverter::initPropertyDefinitions();
116  return sPropertyDefinitions;
117 }
118 
119 
120 std::unique_ptr< QgsPrintLayout > QgsCompositionConverter::createLayoutFromCompositionXml( const QDomElement &composerElement, QgsProject *project )
121 {
122  initPropertyDefinitions();
123 
124  QDomElement parentElement = composerElement.parentNode().toElement();
125 
126  std::unique_ptr< QgsPrintLayout > layout = qgis::make_unique< QgsPrintLayout >( project );
127  layout->undoStack()->blockCommands( true );
128 
129  layout->mCustomProperties.readXml( composerElement );
130 
131  // Guides
132  layout->guides().setVisible( composerElement.attribute( QStringLiteral( "guidesVisible" ), QStringLiteral( "1" ) ).toInt() != 0 );
133 
134  int printResolution = composerElement.attribute( QStringLiteral( "printResolution" ), QStringLiteral( "300" ) ).toInt();
135  layout->renderContext().setDpi( printResolution );
136 
137  // Create pages
138  int pages = composerElement.attribute( QStringLiteral( "numPages" ) ).toInt( );
139  float paperHeight = composerElement.attribute( QStringLiteral( "paperHeight" ) ).toDouble( );
140  float paperWidth = composerElement.attribute( QStringLiteral( "paperWidth" ) ).toDouble( );
141 
142  QString name = composerElement.attribute( QStringLiteral( "name" ) );
143  // Try title
144  if ( name.isEmpty() )
145  name = composerElement.attribute( QStringLiteral( "title" ) );
146  // Try title on parent element
147  if ( name.isEmpty() )
148  name = parentElement.attribute( QStringLiteral( "title" ) );
149  layout->setName( name );
150  QgsLayoutSize pageSize( paperWidth, paperHeight );
151  for ( int j = 0; j < pages; j++ )
152  {
153  QgsLayoutItemPage *page = QgsLayoutItemPage::create( layout.get() );
154  page->setPageSize( pageSize );
155  layout->pageCollection()->addPage( page );
156  //custom snap lines
157  QDomNodeList snapLineNodes = composerElement.elementsByTagName( QStringLiteral( "SnapLine" ) );
158  for ( int i = 0; i < snapLineNodes.size(); ++i )
159  {
160  QDomElement snapLineElem = snapLineNodes.at( i ).toElement();
161  double x1 = snapLineElem.attribute( QStringLiteral( "x1" ) ).toDouble();
162  double y1 = snapLineElem.attribute( QStringLiteral( "y1" ) ).toDouble();
163  double x2 = snapLineElem.attribute( QStringLiteral( "x2" ) ).toDouble();
164  // Not necessary: double y2 = snapLineElem.attribute( QStringLiteral( "y2" ) ).toDouble();
165  Qt::Orientation orientation( x1 == x2 ? Qt::Orientation::Vertical : Qt::Orientation::Horizontal );
166  QgsLayoutMeasurement position( x1 == x2 ? x1 : y1 );
167  std::unique_ptr< QgsLayoutGuide > guide = qgis::make_unique< QgsLayoutGuide >( orientation, position, page );
168  layout->guides().addGuide( guide.release() );
169  }
170  }
171 
172 
173  if ( composerElement.elementsByTagName( QStringLiteral( "symbol" ) ).size() )
174  {
175  QDomElement symbolElement = composerElement.elementsByTagName( QStringLiteral( "symbol" ) ).at( 0 ).toElement();
176  QgsReadWriteContext context;
177  if ( project )
178  context.setPathResolver( project->pathResolver() );
179  std::unique_ptr< QgsFillSymbol > symbol( QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElement, context ) );
180  if ( symbol )
181  layout->pageCollection()->setPageStyleSymbol( symbol.get() );
182  }
183 
184  addItemsFromCompositionXml( layout.get(), composerElement );
185 
186  // Read atlas from the parent element (Composer)
187  if ( parentElement.elementsByTagName( QStringLiteral( "Atlas" ) ).size() )
188  {
189  QDomElement atlasElement = parentElement.elementsByTagName( QStringLiteral( "Atlas" ) ).at( 0 ).toElement();
190  readAtlasXml( layout->atlas(), atlasElement, layout->project() );
191  }
192 
193  layout->undoStack()->blockCommands( false );
194  return layout;
195 }
196 
197 
198 void QgsCompositionConverter::adjustPos( QgsPrintLayout *layout, QgsLayoutItem *layoutItem, QPointF *position, bool &pasteInPlace, int zOrderOffset, QPointF &pasteShiftPos, int &pageNumber )
199 {
200  if ( position )
201  {
202  if ( pasteInPlace )
203  {
204  layoutItem->attemptMove( QgsLayoutPoint( *position ), true, false, pageNumber );
205  }
206  else
207  {
208  layoutItem->attemptMoveBy( pasteShiftPos.x(), pasteShiftPos.y() );
209  }
210  }
211 
212  if ( !layoutItem->scene() )
213  layout->addLayoutItem( layoutItem );
214  layoutItem->setZValue( layoutItem->zValue() + zOrderOffset );
215 }
216 
217 void QgsCompositionConverter::restoreGeneralComposeItemProperties( QgsLayoutItem *layoutItem, const QDomElement &itemElem )
218 {
219  //restore general composer item properties
220  QDomNodeList composerItemList = itemElem.elementsByTagName( QStringLiteral( "ComposerItem" ) );
221  if ( !composerItemList.isEmpty() )
222  {
223  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
224 
225  //rotation
226  if ( !qgsDoubleNear( composerItemElem.attribute( QStringLiteral( "rotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) )
227  {
228  //check for old (pre 2.1) rotation attribute
229  layoutItem->setItemRotation( composerItemElem.attribute( QStringLiteral( "rotation" ), QStringLiteral( "0" ) ).toDouble(), false );
230  }
231  QgsCompositionConverter::readXml( layoutItem, composerItemElem );
232  }
233 }
234 
235 QRectF QgsCompositionConverter::itemPosition( QgsLayoutItem *layoutItem, const QDomElement &itemElem )
236 {
237  int page;
238  double x, y, pagex, pagey, width, height;
239  bool xOk, yOk, pageOk, pagexOk, pageyOk, widthOk, heightOk, positionModeOk;
240 
241  x = itemElem.attribute( QStringLiteral( "x" ) ).toDouble( &xOk );
242  y = itemElem.attribute( QStringLiteral( "y" ) ).toDouble( &yOk );
243  page = itemElem.attribute( QStringLiteral( "page" ) ).toInt( &pageOk );
244  pagex = itemElem.attribute( QStringLiteral( "pagex" ) ).toDouble( &pagexOk );
245  pagey = itemElem.attribute( QStringLiteral( "pagey" ) ).toDouble( &pageyOk );
246  width = itemElem.attribute( QStringLiteral( "width" ) ).toDouble( &widthOk );
247  height = itemElem.attribute( QStringLiteral( "height" ) ).toDouble( &heightOk );
248 
249 
250  layoutItem->mReferencePoint = static_cast< QgsLayoutItem::ReferencePoint >( itemElem.attribute( QStringLiteral( "positionMode" ) ).toInt( &positionModeOk ) );
251  if ( !positionModeOk )
252  {
253  layoutItem->setReferencePoint( QgsLayoutItem::ReferencePoint::UpperLeft );
254  }
255 
256  if ( pageOk && pagexOk && pageyOk )
257  {
258  xOk = true;
259  yOk = true;
260  x = pagex;
261  // position in the page (1-based)
262  if ( page <= layoutItem->layout()->pageCollection()->pageCount() )
263  {
264  QgsLayoutItemPage *pageObject = layoutItem->layout()->pageCollection()->pages().at( page - 1 );
265  y = ( page - 1 )
266  * ( pageObject->sizeWithUnits().height()
267  + layoutItem->layout()->pageCollection()->spaceBetweenPages() )
268  + pagey;
269  }
270  else
271  {
272  y = pagey;
273  }
274  }
275  return QRectF( x, y, width, height );
276 }
277 
278 QPointF QgsCompositionConverter::minPointFromXml( const QDomElement &elem )
279 {
280  double minX = std::numeric_limits<double>::max();
281  double minY = std::numeric_limits<double>::max();
282  QDomNodeList composerItemList = elem.elementsByTagName( QStringLiteral( "ComposerItem" ) );
283  for ( int i = 0; i < composerItemList.size(); ++i )
284  {
285  QDomElement currentComposerItemElem = composerItemList.at( i ).toElement();
286  double x, y;
287  bool xOk, yOk;
288  x = currentComposerItemElem.attribute( QStringLiteral( "x" ) ).toDouble( &xOk );
289  y = currentComposerItemElem.attribute( QStringLiteral( "y" ) ).toDouble( &yOk );
290  if ( !xOk || !yOk )
291  {
292  continue;
293  }
294  minX = std::min( minX, x );
295  minY = std::min( minY, y );
296  }
297  if ( minX < std::numeric_limits<double>::max() )
298  {
299  return QPointF( minX, minY );
300  }
301  else
302  {
303  return QPointF( 0, 0 );
304  }
305 }
306 
307 QList<QgsLayoutObject *> QgsCompositionConverter::addItemsFromCompositionXml( QgsPrintLayout *layout, const QDomElement &parentElement, QPointF *position, bool pasteInPlace )
308 {
309 
310  initPropertyDefinitions();
311 
312  QList< QgsLayoutObject * > newItems;
313 
314  //if we are adding items to a layout which already contains items, we need to make sure
315  //these items are placed at the top of the layout and that zValues are not duplicated
316  //so, calculate an offset which needs to be added to the zValue of created items
317  int zOrderOffset = layout->mItemsModel->zOrderListSize();
318 
319  QPointF pasteShiftPos;
320  int pageNumber = -1;
321  if ( position )
322  {
323  //If we are placing items relative to a certain point, then calculate how much we need
324  //to shift the items by so that they are placed at this point
325  //First, calculate the minimum position from the xml
326  QPointF minItemPos = minPointFromXml( parentElement );
327  //next, calculate how much each item needs to be shifted from its original position
328  //so that it's placed at the correct relative position
329  pasteShiftPos = *position - minItemPos;
330  if ( pasteInPlace )
331  {
332  pageNumber = layout->mPageCollection->pageNumberForPoint( *position );
333  }
334  }
335 
336  QgsStringMap mapIdUiidMap;
337 
338  // Map (this needs to come first to build the uuid <-> ID map for map composer items
339  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerMap" ) ).size(); i++ )
340  {
341  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerMap" ) ).at( i ) );
342  QgsLayoutItemMap *layoutItem = new QgsLayoutItemMap( layout );
343  readMapXml( layoutItem, itemNode.toElement(), layout->project(), mapIdUiidMap );
344  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
345  newItems << layoutItem ;
346  }
347 
348  // Label
349  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerLabel" ) ).size(); i++ )
350  {
351  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerLabel" ) ).at( i ) );
352  QgsLayoutItemLabel *layoutItem = new QgsLayoutItemLabel( layout );
353  readLabelXml( layoutItem, itemNode.toElement(), layout->project() );
354  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
355  newItems << layoutItem ;
356  }
357 
358  // Shape
359  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerShape" ) ).size(); i++ )
360  {
361  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerShape" ) ).at( i ) );
362  QgsLayoutItemShape *layoutItem = new QgsLayoutItemShape( layout );
363  readShapeXml( layoutItem, itemNode.toElement(), layout->project() );
364  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
365  newItems << layoutItem ;
366  }
367 
368  // Picture
369  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerPicture" ) ).size(); i++ )
370  {
371  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerPicture" ) ).at( i ) );
372  QgsLayoutItemPicture *layoutItem = new QgsLayoutItemPicture( layout );
373  readPictureXml( layoutItem, itemNode.toElement(), layout->project(), mapIdUiidMap );
374  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
375  newItems << layoutItem ;
376  }
377 
378  // Polygon
379  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerPolygon" ) ).size(); i++ )
380  {
381  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerPolygon" ) ).at( i ) );
382  QgsLayoutItemPolygon *layoutItem = new QgsLayoutItemPolygon( layout );
383  readPolyXml<QgsLayoutItemPolygon, QgsFillSymbol>( layoutItem, itemNode.toElement(), layout->project() );
384  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
385  newItems << layoutItem ;
386  }
387 
388  // Polyline
389  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerPolyline" ) ).size(); i++ )
390  {
391  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerPolyline" ) ).at( i ) );
392  QgsLayoutItemPolyline *layoutItem = new QgsLayoutItemPolyline( layout );
393  readPolyXml<QgsLayoutItemPolyline, QgsLineSymbol>( layoutItem, itemNode.toElement(), layout->project() );
394  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
395  newItems << layoutItem ;
396  }
397 
398  // Arrow
399  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerArrow" ) ).size(); i++ )
400  {
401  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerArrow" ) ).at( i ) );
402  QgsLayoutItemPolyline *layoutItem = new QgsLayoutItemPolyline( layout );
403  readArrowXml( layoutItem, itemNode.toElement(), layout->project() );
404  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
405  newItems << layoutItem ;
406  }
407 
408  // Scalebar
409  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerScaleBar" ) ).size(); i++ )
410  {
411  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerScaleBar" ) ).at( i ) );
412  QgsLayoutItemScaleBar *layoutItem = new QgsLayoutItemScaleBar( layout );
413  readScaleBarXml( layoutItem, itemNode.toElement(), layout->project(), mapIdUiidMap );
414  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
415  newItems << layoutItem ;
416  }
417 
418  // Legend
419  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerLegend" ) ).size(); i++ )
420  {
421  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerLegend" ) ).at( i ) );
422  QgsLayoutItemLegend *layoutItem = new QgsLayoutItemLegend( layout );
423  readLegendXml( layoutItem, itemNode.toElement(), layout->project(), mapIdUiidMap );
424  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
425  newItems << layoutItem ;
426  }
427 
428  // Html
429  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerHtml" ) ).size(); i++ )
430  {
431  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerHtml" ) ).at( i ) );
432  QgsLayoutItemHtml *layoutItem = new QgsLayoutItemHtml( layout );
433  readHtmlXml( layoutItem, itemNode.toElement(), layout->project() );
434  // Adjust position for frames
435  const QList<QgsLayoutFrame *> framesList( layoutItem->frames() );
436  for ( const auto &frame : framesList )
437  {
438  adjustPos( layout, frame, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
439  }
440  newItems << layoutItem ;
441  }
442 
443  // Attribute Table
444  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerAttributeTableV2" ) ).size(); i++ )
445  {
446  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerAttributeTableV2" ) ).at( i ) );
447  QgsLayoutItemAttributeTable *layoutItem = new QgsLayoutItemAttributeTable( layout );
448  readTableXml( layoutItem, itemNode.toElement(), layout->project() );
449  // Adjust position for frames
450  const QList<QgsLayoutFrame *> framesList( layoutItem->frames() );
451  for ( const auto &frame : framesList )
452  {
453  adjustPos( layout, frame, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
454  }
455  newItems << layoutItem ;
456  }
457 
458  return newItems;
459 }
460 
461 bool QgsCompositionConverter::isCompositionTemplate( const QDomDocument &document )
462 {
463  return document.elementsByTagName( QStringLiteral( "Composition" ) ).count() > 0;
464 }
465 
466 QDomDocument QgsCompositionConverter::convertCompositionTemplate( const QDomDocument &document, QgsProject *project )
467 {
468  QDomDocument doc;
469  QgsReadWriteContext context;
470  if ( project )
471  context.setPathResolver( project->pathResolver() );
472  if ( document.elementsByTagName( QStringLiteral( "Composition" ) ).count( ) > 0 )
473  {
474  QDomElement composerElem = document.elementsByTagName( QStringLiteral( "Composition" ) ).at( 0 ).toElement( );
475 
476  std::unique_ptr<QgsLayout> layout = createLayoutFromCompositionXml( composerElem,
477  project );
478  QDomElement elem = layout->writeXml( doc, context );
479  doc.appendChild( elem );
480  }
481  return doc;
482 }
483 
484 bool QgsCompositionConverter::readLabelXml( QgsLayoutItemLabel *layoutItem, const QDomElement &itemElem, const QgsProject *project )
485 {
486  Q_UNUSED( project )
487  if ( itemElem.isNull() )
488  {
489  return false;
490  }
491 
492  restoreGeneralComposeItemProperties( layoutItem, itemElem );
493 
494  //text
495  layoutItem->setText( itemElem.attribute( QStringLiteral( "labelText" ) ) );
496 
497  //html state
498  layoutItem->setMode( itemElem.attribute( QStringLiteral( "htmlState" ) ).toInt() == Qt::Checked ? QgsLayoutItemLabel::Mode::ModeHtml : QgsLayoutItemLabel::Mode::ModeFont );
499 
500  //margin
501  bool marginXOk = false;
502  bool marginYOk = false;
503  double marginX = itemElem.attribute( QStringLiteral( "marginX" ) ).toDouble( &marginXOk );
504  double marginY = itemElem.attribute( QStringLiteral( "marginY" ) ).toDouble( &marginYOk );
505  if ( !marginXOk || !marginYOk )
506  {
507  //upgrade old projects where margins where stored in a single attribute
508  double margin = itemElem.attribute( QStringLiteral( "margin" ), QStringLiteral( "1.0" ) ).toDouble();
509  marginX = margin;
510  marginY = margin;
511  }
512  layoutItem->setMarginX( marginX );
513  layoutItem->setMarginY( marginY );
514 
515  //Horizontal alignment
516  layoutItem->setHAlign( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "halign" ) ).toInt() ) );
517 
518  //Vertical alignment
519  layoutItem->setVAlign( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "valign" ) ).toInt() ) );
520 
521 
522  QFont font;
523  //font
524  QgsFontUtils::setFromXmlChildNode( font, itemElem, QStringLiteral( "LabelFont" ) );
525  layoutItem->setFont( font );
526 
527  //font color
528  QDomNodeList fontColorList = itemElem.elementsByTagName( QStringLiteral( "FontColor" ) );
529  if ( !fontColorList.isEmpty() )
530  {
531  QDomElement fontColorElem = fontColorList.at( 0 ).toElement();
532  int red = fontColorElem.attribute( QStringLiteral( "red" ), QStringLiteral( "0" ) ).toInt();
533  int green = fontColorElem.attribute( QStringLiteral( "green" ), QStringLiteral( "0" ) ).toInt();
534  int blue = fontColorElem.attribute( QStringLiteral( "blue" ), QStringLiteral( "0" ) ).toInt();
535  layoutItem->setFontColor( QColor( red, green, blue ) );
536  }
537  else
538  {
539  layoutItem->setFontColor( QColor( 0, 0, 0 ) );
540  }
541 
542  return true;
543 }
544 
545 bool QgsCompositionConverter::readShapeXml( QgsLayoutItemShape *layoutItem, const QDomElement &itemElem, const QgsProject *project )
546 {
547  Q_UNUSED( project )
548  layoutItem->setShapeType( static_cast<QgsLayoutItemShape::Shape>( itemElem.attribute( QStringLiteral( "shapeType" ), QStringLiteral( "0" ) ).toInt() ) );
549  layoutItem->setCornerRadius( QgsLayoutMeasurement( itemElem.attribute( QStringLiteral( "cornerRadius" ), QStringLiteral( "0" ) ).toDouble() ) );
550 
551  restoreGeneralComposeItemProperties( layoutItem, itemElem );
552 
553  QgsReadWriteContext context;
554  if ( project )
555  context.setPathResolver( project->pathResolver() );
556 
557  if ( itemElem.elementsByTagName( QStringLiteral( "symbol" ) ).size() )
558  {
559  QDomElement symbolElement = itemElem.elementsByTagName( QStringLiteral( "symbol" ) ).at( 0 ).toElement();
560  std::unique_ptr< QgsFillSymbol > shapeStyleSymbol( QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElement, context ) );
561  if ( shapeStyleSymbol )
562  layoutItem->setSymbol( shapeStyleSymbol.get() );
563  }
564  else
565  {
566  //upgrade project file from 2.0 to use symbol styling
567  QgsStringMap properties;
568  properties.insert( QStringLiteral( "color" ), QgsSymbolLayerUtils::encodeColor( layoutItem->brush().color() ) );
569  if ( layoutItem->hasBackground() )
570  {
571  properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
572  }
573  else
574  {
575  properties.insert( QStringLiteral( "style" ), QStringLiteral( "no" ) );
576  }
577  if ( layoutItem->frameEnabled() )
578  {
579  properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "solid" ) );
580  }
581  else
582  {
583  properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "no" ) );
584  }
585  properties.insert( QStringLiteral( "color_border" ), QgsSymbolLayerUtils::encodeColor( layoutItem->pen().color() ) );
586  properties.insert( QStringLiteral( "width_border" ), QString::number( layoutItem->pen().widthF() ) );
587 
588  //for pre 2.0 projects, shape color and outline were specified in a different element...
589  QDomNodeList outlineColorList = itemElem.elementsByTagName( QStringLiteral( "OutlineColor" ) );
590  if ( !outlineColorList.isEmpty() )
591  {
592  QDomElement frameColorElem = outlineColorList.at( 0 ).toElement();
593  bool redOk, greenOk, blueOk, alphaOk, widthOk;
594  int penRed, penGreen, penBlue, penAlpha;
595  double penWidth;
596 
597  penWidth = itemElem.attribute( QStringLiteral( "outlineWidth" ) ).toDouble( &widthOk );
598  penRed = frameColorElem.attribute( QStringLiteral( "red" ) ).toInt( &redOk );
599  penGreen = frameColorElem.attribute( QStringLiteral( "green" ) ).toInt( &greenOk );
600  penBlue = frameColorElem.attribute( QStringLiteral( "blue" ) ).toInt( &blueOk );
601  penAlpha = frameColorElem.attribute( QStringLiteral( "alpha" ) ).toInt( &alphaOk );
602 
603  if ( redOk && greenOk && blueOk && alphaOk && widthOk )
604  {
605  properties.insert( QStringLiteral( "color_border" ), QgsSymbolLayerUtils::encodeColor( QColor( penRed, penGreen, penBlue, penAlpha ) ) );
606  properties.insert( QStringLiteral( "width_border" ), QString::number( penWidth ) );
607  }
608  }
609  QDomNodeList fillColorList = itemElem.elementsByTagName( QStringLiteral( "FillColor" ) );
610  if ( !fillColorList.isEmpty() )
611  {
612  QDomElement fillColorElem = fillColorList.at( 0 ).toElement();
613  bool redOk, greenOk, blueOk, alphaOk;
614  int fillRed, fillGreen, fillBlue, fillAlpha;
615 
616  fillRed = fillColorElem.attribute( QStringLiteral( "red" ) ).toInt( &redOk );
617  fillGreen = fillColorElem.attribute( QStringLiteral( "green" ) ).toInt( &greenOk );
618  fillBlue = fillColorElem.attribute( QStringLiteral( "blue" ) ).toInt( &blueOk );
619  fillAlpha = fillColorElem.attribute( QStringLiteral( "alpha" ) ).toInt( &alphaOk );
620 
621  if ( redOk && greenOk && blueOk && alphaOk )
622  {
623  properties.insert( QStringLiteral( "color" ), QgsSymbolLayerUtils::encodeColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) ) );
624  properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
625  }
626  }
627  if ( itemElem.hasAttribute( QStringLiteral( "transparentFill" ) ) )
628  {
629  //old style (pre 2.0) of specifying that shapes had no fill
630  bool hasOldTransparentFill = itemElem.attribute( QStringLiteral( "transparentFill" ), QStringLiteral( "0" ) ).toInt();
631  if ( hasOldTransparentFill )
632  {
633  properties.insert( QStringLiteral( "style" ), QStringLiteral( "no" ) );
634  }
635  }
636 
637  std::unique_ptr< QgsFillSymbol > shapeStyleSymbol( QgsFillSymbol::createSimple( properties ) );
638  layoutItem->setSymbol( shapeStyleSymbol.get() );
639  }
640  // Disable frame for shapes
641  layoutItem->setFrameEnabled( false );
642  layoutItem->setBackgroundEnabled( false );
643 
644  return true;
645 }
646 
647 bool QgsCompositionConverter::readPictureXml( QgsLayoutItemPicture *layoutItem, const QDomElement &itemElem, const QgsProject *project, const QgsStringMap &mapId2Uuid )
648 {
649  restoreGeneralComposeItemProperties( layoutItem, itemElem );
650 
651  layoutItem->mResizeMode = QgsLayoutItemPicture::ResizeMode( itemElem.attribute( QStringLiteral( "resizeMode" ), QStringLiteral( "0" ) ).toInt() );
652  //when loading from xml, default to anchor point of middle to match pre 2.4 behavior
653  bool positionModeOk = false;
654  layoutItem->mReferencePoint = static_cast< QgsLayoutItem::ReferencePoint >( itemElem.attribute( QStringLiteral( "positionMode" ) ).toInt( &positionModeOk ) );
655  if ( !positionModeOk )
656  {
657  layoutItem->mReferencePoint = QgsLayoutItem::ReferencePoint::UpperLeft;
658  }
659  bool anchorPointOk = false;
660 
661  layoutItem->setPictureAnchor( static_cast< QgsLayoutItem::ReferencePoint >( itemElem.attribute( QStringLiteral( "anchorPoint" ), QString::number( QgsLayoutItem::ReferencePoint::Middle ) ).toInt( &anchorPointOk ) ) );
662  if ( !anchorPointOk )
663  {
664  layoutItem->mPictureAnchor = QgsLayoutItem::ReferencePoint::UpperLeft;
665  }
666  layoutItem->mSvgFillColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "svgFillColor" ), QgsSymbolLayerUtils::encodeColor( QColor( 255, 255, 255 ) ) ) );
667  layoutItem->mSvgStrokeColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "svgBorderColor" ), QgsSymbolLayerUtils::encodeColor( QColor( 0, 0, 0 ) ) ) );
668  layoutItem->mSvgStrokeWidth = itemElem.attribute( QStringLiteral( "svgBorderWidth" ), QStringLiteral( "0.2" ) ).toDouble();
669 
670  QString imagePath = itemElem.attribute( QStringLiteral( "file" ) );
671  if ( project )
672  {
673  // convert from relative path to absolute. For SVG we also need to consider system SVG paths
674  QgsPathResolver pathResolver = project->pathResolver();
675  if ( imagePath.endsWith( QLatin1String( ".svg" ), Qt::CaseInsensitive ) )
676  imagePath = QgsSymbolLayerUtils::svgSymbolNameToPath( imagePath, pathResolver );
677  else
678  imagePath = pathResolver.readPath( imagePath );
679  }
680  layoutItem->setPicturePath( imagePath );
681  layoutItem->mPictureHeight = itemElem.attribute( QStringLiteral( "pictureHeight" ), QStringLiteral( "10" ) ).toDouble();
682  layoutItem->mPictureWidth = itemElem.attribute( QStringLiteral( "pictureWidth" ), QStringLiteral( "10" ) ).toDouble();
683 
684  //picture rotation
685  if ( !qgsDoubleNear( itemElem.attribute( QStringLiteral( "pictureRotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) )
686  {
687  layoutItem->mPictureRotation = itemElem.attribute( QStringLiteral( "pictureRotation" ), QStringLiteral( "0" ) ).toDouble();
688  }
689 
690  //rotation map
691  layoutItem->mNorthMode = static_cast< QgsLayoutItemPicture::NorthMode >( itemElem.attribute( QStringLiteral( "northMode" ), QStringLiteral( "0" ) ).toInt() );
692  layoutItem->mNorthOffset = itemElem.attribute( QStringLiteral( "northOffset" ), QStringLiteral( "0" ) ).toDouble();
693 
694  QString rotationMapId = itemElem.attribute( QStringLiteral( "mapId" ), QStringLiteral( "-1" ) );
695  if ( rotationMapId != QStringLiteral( "-1" ) )
696  {
697  // Find uuid for map with given id
698  QgsLayoutItemMap *mapInstance = qobject_cast<QgsLayoutItemMap *>( layoutItem->layout()->itemByUuid( mapId2Uuid[ rotationMapId ] ) );
699  if ( mapInstance )
700  {
701  layoutItem->setLinkedMap( mapInstance );
702  }
703  }
704  return true;
705 }
706 
707 bool QgsCompositionConverter::readArrowXml( QgsLayoutItemPolyline *layoutItem, const QDomElement &itemElem, const QgsProject *project )
708 {
709  readPolyXml<QgsLayoutItemPolyline, QgsLineSymbol>( layoutItem, itemElem, project );
710  QPolygonF polygon;
711  QDomNodeList startPointList = itemElem.elementsByTagName( QStringLiteral( "StartPoint" ) );
712  if ( ! startPointList.isEmpty() )
713  {
714  QDomElement node = startPointList.at( 0 ).toElement();
715  polygon.append( QPointF( node.attribute( QStringLiteral( "x" ) ).toDouble( ), node.attribute( QStringLiteral( "y" ) ).toDouble() ) );
716  }
717  QDomNodeList stopPointList = itemElem.elementsByTagName( QStringLiteral( "StopPoint" ) );
718  if ( ! stopPointList.isEmpty() )
719  {
720  QDomElement node = stopPointList.at( 0 ).toElement();
721  polygon.append( QPointF( node.attribute( QStringLiteral( "x" ) ).toDouble( ), node.attribute( QStringLiteral( "y" ) ).toDouble() ) );
722  }
723 
724  QgsCompositionConverter::MarkerMode markerMode = static_cast< QgsCompositionConverter::MarkerMode>( itemElem.attribute( QStringLiteral( "markerMode" ), QStringLiteral( "0" ) ).toInt( ) );
725 
726  if ( markerMode == QgsCompositionConverter::MarkerMode::DefaultMarker )
727  {
728  layoutItem->setEndMarker( QgsLayoutItemPolyline::MarkerMode::ArrowHead );
729  layoutItem->setStartMarker( QgsLayoutItemPolyline::MarkerMode::NoMarker );
730  layoutItem->setArrowHeadFillColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "arrowHeadFillColor" ), QgsSymbolLayerUtils::encodeColor( QColor( 255, 255, 255 ) ) ) ) );
731  layoutItem->setArrowHeadStrokeColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "arrowHeadOutlineColor" ), QgsSymbolLayerUtils::encodeColor( QColor( 255, 255, 255 ) ) ) ) );
732  layoutItem->setArrowHeadStrokeWidth( itemElem.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "1.0" ) ).toDouble( ) );
733  layoutItem->setArrowHeadWidth( itemElem.attribute( QStringLiteral( "arrowHeadWidth" ), QStringLiteral( "1.0" ) ).toDouble( ) );
734  }
735  else if ( markerMode == QgsCompositionConverter::MarkerMode::SVGMarker )
736  {
737  QString endMarkerFile = itemElem.attribute( QStringLiteral( "endMarkerFile" ) );
738  QString startMarkerFile = itemElem.attribute( QStringLiteral( "endMarkerFile" ) );
739 
740  // Fix the paths
741  if ( project )
742  {
743  // convert from relative path to absolute. For SVG we also need to consider system SVG paths
744  QgsPathResolver pathResolver = project->pathResolver();
745  if ( !endMarkerFile.isEmpty() )
746  {
747  if ( endMarkerFile.endsWith( QLatin1String( ".svg" ), Qt::CaseInsensitive ) )
748  endMarkerFile = QgsSymbolLayerUtils::svgSymbolNameToPath( endMarkerFile, pathResolver );
749  else
750  endMarkerFile = pathResolver.readPath( endMarkerFile );
751  }
752  if ( !startMarkerFile.isEmpty() )
753  {
754  if ( startMarkerFile.endsWith( QLatin1String( ".svg" ), Qt::CaseInsensitive ) )
755  startMarkerFile = QgsSymbolLayerUtils::svgSymbolNameToPath( startMarkerFile, pathResolver );
756  else
757  startMarkerFile = pathResolver.readPath( startMarkerFile );
758  }
759  }
760  if ( !endMarkerFile.isEmpty() )
761  {
762  layoutItem->setEndMarker( QgsLayoutItemPolyline::MarkerMode::SvgMarker );
763  layoutItem->setEndSvgMarkerPath( endMarkerFile );
764  }
765  if ( !startMarkerFile.isEmpty() )
766  {
767  layoutItem->setStartMarker( QgsLayoutItemPolyline::MarkerMode::SvgMarker );
768  layoutItem->setStartSvgMarkerPath( startMarkerFile );
769  }
770  }
771  else // NoMarker
772  {
773  layoutItem->setEndMarker( QgsLayoutItemPolyline::MarkerMode::NoMarker );
774  layoutItem->setStartMarker( QgsLayoutItemPolyline::MarkerMode::NoMarker );
775  }
776  // Calculate the margin
777  double margin = polygon.boundingRect().left() - layoutItem->pos().x();
778  polygon.translate( - polygon.boundingRect().left() + margin, - polygon.boundingRect().top() + margin );
779  layoutItem->setNodes( polygon );
780 
781  return true;
782 }
783 
784 bool QgsCompositionConverter::readMapXml( QgsLayoutItemMap *layoutItem, const QDomElement &itemElem, const QgsProject *project, QgsStringMap &mapId2Uuid )
785 {
786  restoreGeneralComposeItemProperties( layoutItem, itemElem );
787 
788  mapId2Uuid[ itemElem.attribute( QStringLiteral( "id" ) ) ] = layoutItem->uuid();
789 
790  // TODO: Unused but all the layouts readXML require it (I'd suggest to remove it from the API)
791  QDomDocument doc;
792 
793  QgsReadWriteContext context;
794 
795  if ( project )
796  context.setPathResolver( project->pathResolver() );
797 
798  //extent
799  QDomNodeList extentNodeList = itemElem.elementsByTagName( QStringLiteral( "Extent" ) );
800  if ( !extentNodeList.isEmpty() )
801  {
802  QDomElement extentElem = extentNodeList.at( 0 ).toElement();
803  double xmin, xmax, ymin, ymax;
804  xmin = extentElem.attribute( QStringLiteral( "xmin" ) ).toDouble();
805  xmax = extentElem.attribute( QStringLiteral( "xmax" ) ).toDouble();
806  ymin = extentElem.attribute( QStringLiteral( "ymin" ) ).toDouble();
807  ymax = extentElem.attribute( QStringLiteral( "ymax" ) ).toDouble();
808  layoutItem->setExtent( QgsRectangle( xmin, ymin, xmax, ymax ) );
809  }
810 
811  QDomNodeList crsNodeList = itemElem.elementsByTagName( QStringLiteral( "crs" ) );
812  if ( !crsNodeList.isEmpty() )
813  {
814  QDomElement crsElem = crsNodeList.at( 0 ).toElement();
815  layoutItem->crs().readXml( crsElem );
816  }
817  else
818  {
819  layoutItem->setCrs( QgsCoordinateReferenceSystem() );
820  }
821 
822  //map rotation
823  if ( !qgsDoubleNear( itemElem.attribute( QStringLiteral( "mapRotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) )
824  {
825  layoutItem->setMapRotation( itemElem.attribute( QStringLiteral( "mapRotation" ), QStringLiteral( "0" ) ).toDouble() );
826  }
827 
828  // follow map theme
829  layoutItem->setFollowVisibilityPreset( itemElem.attribute( QStringLiteral( "followPreset" ) ).compare( QLatin1String( "true" ) ) == 0 );
830  layoutItem->setFollowVisibilityPresetName( itemElem.attribute( QStringLiteral( "followPresetName" ) ) );
831 
832  //mKeepLayerSet flag
833  QString keepLayerSetFlag = itemElem.attribute( QStringLiteral( "keepLayerSet" ) );
834  if ( keepLayerSetFlag.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
835  {
836  layoutItem->setKeepLayerSet( true );
837  }
838  else
839  {
840  layoutItem->setKeepLayerSet( false );
841  }
842 
843  QString drawCanvasItemsFlag = itemElem.attribute( QStringLiteral( "drawCanvasItems" ), QStringLiteral( "true" ) );
844  if ( drawCanvasItemsFlag.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
845  {
846  layoutItem->setDrawAnnotations( true );
847  }
848  else
849  {
850  layoutItem->setDrawAnnotations( false );
851  }
852 
853  layoutItem->mLayerStyleOverrides.clear();
854 
855  //mLayers
856  layoutItem->mLayers.clear();
857 
858  QDomNodeList layerSetNodeList = itemElem.elementsByTagName( QStringLiteral( "LayerSet" ) );
859  if ( !layerSetNodeList.isEmpty() )
860  {
861  QDomElement layerSetElem = layerSetNodeList.at( 0 ).toElement();
862  QDomNodeList layerIdNodeList = layerSetElem.elementsByTagName( QStringLiteral( "Layer" ) );
863  layoutItem->mLayers.reserve( layerIdNodeList.size() );
864  for ( int i = 0; i < layerIdNodeList.size(); ++i )
865  {
866  QDomElement layerElem = layerIdNodeList.at( i ).toElement();
867  QString layerId = layerElem.text();
868  QString layerName = layerElem.attribute( QStringLiteral( "name" ) );
869  QString layerSource = layerElem.attribute( QStringLiteral( "source" ) );
870  QString layerProvider = layerElem.attribute( QStringLiteral( "provider" ) );
871 
872  QgsMapLayerRef ref( layerId, layerName, layerSource, layerProvider );
873  ref.resolveWeakly( project );
874  layoutItem->mLayers << ref;
875  }
876  }
877 
878  // override styles
879  QDomNodeList layerStylesNodeList = itemElem.elementsByTagName( QStringLiteral( "LayerStyles" ) );
880  layoutItem->mKeepLayerStyles = !layerStylesNodeList.isEmpty();
881  if ( layoutItem->mKeepLayerStyles )
882  {
883  QDomElement layerStylesElem = layerStylesNodeList.at( 0 ).toElement();
884  QDomNodeList layerStyleNodeList = layerStylesElem.elementsByTagName( QStringLiteral( "LayerStyle" ) );
885  for ( int i = 0; i < layerStyleNodeList.size(); ++i )
886  {
887  const QDomElement &layerStyleElement = layerStyleNodeList.at( i ).toElement();
888  QString layerId = layerStyleElement.attribute( QStringLiteral( "layerid" ) );
889  QString layerName = layerStyleElement.attribute( QStringLiteral( "name" ) );
890  QString layerSource = layerStyleElement.attribute( QStringLiteral( "source" ) );
891  QString layerProvider = layerStyleElement.attribute( QStringLiteral( "provider" ) );
892  QgsMapLayerRef ref( layerId, layerName, layerSource, layerProvider );
893  ref.resolveWeakly( project );
894 
895  QgsMapLayerStyle style;
896  style.readXml( layerStyleElement );
897  layoutItem->mLayerStyleOverrides.insert( ref.layerId, style.xmlData() );
898  }
899  }
900 
901  layoutItem->mDrawing = false;
902  layoutItem->mNumCachedLayers = 0;
903  layoutItem->mCacheInvalidated = true;
904 
905  //overviews
906  //read overview stack
907  QDomNodeList mapOverviewNodeList = itemElem.elementsByTagName( QStringLiteral( "ComposerMapOverview" ) );
908  for ( int i = 0; i < mapOverviewNodeList.size(); ++i )
909  {
910  QDomElement mapOverviewElem = mapOverviewNodeList.at( i ).toElement();
911  std::unique_ptr<QgsLayoutItemMapOverview> mapOverview( new QgsLayoutItemMapOverview( mapOverviewElem.attribute( QStringLiteral( "name" ) ), layoutItem ) );
912  mapOverview->readXml( mapOverviewElem, doc, context );
913  QString frameMapId = mapOverviewElem.attribute( QStringLiteral( "frameMap" ), QStringLiteral( "-1" ) );
914  if ( frameMapId != QStringLiteral( "-1" ) && mapId2Uuid.contains( frameMapId ) )
915  {
916  QgsLayoutItemMap *mapInstance = qobject_cast<QgsLayoutItemMap *>( layoutItem->layout()->itemByUuid( mapId2Uuid[ frameMapId ] ) );
917  if ( mapInstance )
918  {
919  mapOverview->setLinkedMap( mapInstance );
920  }
921  layoutItem->mOverviewStack->addOverview( mapOverview.release() );
922  }
923  }
924 
925  //grids
926  layoutItem->mGridStack->readXml( itemElem, doc, context );
927 
928  //load grid / grid annotation in old xml format
929  //only do this if the grid stack didn't load any grids, otherwise this will
930  //be the dummy element created by QGIS >= 2.5 (refs #10905)
931  QDomNodeList gridNodeList = itemElem.elementsByTagName( QStringLiteral( "Grid" ) );
932  if ( layoutItem->mGridStack->size() == 0 && !gridNodeList.isEmpty() )
933  {
934  QDomElement gridElem = gridNodeList.at( 0 ).toElement();
935  QgsLayoutItemMapGrid *mapGrid = new QgsLayoutItemMapGrid( QObject::tr( "Grid %1" ).arg( 1 ), layoutItem );
936  mapGrid->setEnabled( gridElem.attribute( QStringLiteral( "show" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
937  mapGrid->setStyle( QgsLayoutItemMapGrid::GridStyle( gridElem.attribute( QStringLiteral( "gridStyle" ), QStringLiteral( "0" ) ).toInt() ) );
938  mapGrid->setIntervalX( gridElem.attribute( QStringLiteral( "intervalX" ), QStringLiteral( "0" ) ).toDouble() );
939  mapGrid->setIntervalY( gridElem.attribute( QStringLiteral( "intervalY" ), QStringLiteral( "0" ) ).toDouble() );
940  mapGrid->setOffsetX( gridElem.attribute( QStringLiteral( "offsetX" ), QStringLiteral( "0" ) ).toDouble() );
941  mapGrid->setOffsetY( gridElem.attribute( QStringLiteral( "offsetY" ), QStringLiteral( "0" ) ).toDouble() );
942  mapGrid->setCrossLength( gridElem.attribute( QStringLiteral( "crossLength" ), QStringLiteral( "3" ) ).toDouble() );
943  mapGrid->setFrameStyle( static_cast< QgsLayoutItemMapGrid::FrameStyle >( gridElem.attribute( QStringLiteral( "gridFrameStyle" ), QStringLiteral( "0" ) ).toInt() ) );
944  mapGrid->setFrameWidth( gridElem.attribute( QStringLiteral( "gridFrameWidth" ), QStringLiteral( "2.0" ) ).toDouble() );
945  mapGrid->setFramePenSize( gridElem.attribute( QStringLiteral( "gridFramePenThickness" ), QStringLiteral( "0.5" ) ).toDouble() );
946  mapGrid->setFramePenColor( QgsSymbolLayerUtils::decodeColor( gridElem.attribute( QStringLiteral( "framePenColor" ), QStringLiteral( "0,0,0" ) ) ) );
947  mapGrid->setFrameFillColor1( QgsSymbolLayerUtils::decodeColor( gridElem.attribute( QStringLiteral( "frameFillColor1" ), QStringLiteral( "255,255,255,255" ) ) ) );
948  mapGrid->setFrameFillColor2( QgsSymbolLayerUtils::decodeColor( gridElem.attribute( QStringLiteral( "frameFillColor2" ), QStringLiteral( "0,0,0,255" ) ) ) );
949  mapGrid->setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( itemElem.attribute( QStringLiteral( "gridBlendMode" ), QStringLiteral( "0" ) ).toUInt() ) ) );
950  QDomElement gridSymbolElem = gridElem.firstChildElement( QStringLiteral( "symbol" ) );
951  QgsLineSymbol *lineSymbol = nullptr;
952  if ( gridSymbolElem.isNull() )
953  {
954  //old project file, read penWidth /penColorRed, penColorGreen, penColorBlue
955  lineSymbol = QgsLineSymbol::createSimple( QgsStringMap() );
956  lineSymbol->setWidth( gridElem.attribute( QStringLiteral( "penWidth" ), QStringLiteral( "0" ) ).toDouble() );
957  lineSymbol->setColor( QColor( gridElem.attribute( QStringLiteral( "penColorRed" ), QStringLiteral( "0" ) ).toInt(),
958  gridElem.attribute( QStringLiteral( "penColorGreen" ), QStringLiteral( "0" ) ).toInt(),
959  gridElem.attribute( QStringLiteral( "penColorBlue" ), QStringLiteral( "0" ) ).toInt() ) );
960  }
961  else
962  {
963  lineSymbol = QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( gridSymbolElem, context );
964  }
965  mapGrid->setLineSymbol( lineSymbol );
966 
967  //annotation
968  QDomNodeList annotationNodeList = gridElem.elementsByTagName( QStringLiteral( "Annotation" ) );
969  if ( !annotationNodeList.isEmpty() )
970  {
971  QDomElement annotationElem = annotationNodeList.at( 0 ).toElement();
972  mapGrid->setAnnotationEnabled( annotationElem.attribute( QStringLiteral( "show" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
973  mapGrid->setAnnotationFormat( QgsLayoutItemMapGrid::AnnotationFormat( annotationElem.attribute( QStringLiteral( "format" ), QStringLiteral( "0" ) ).toInt() ) );
974  mapGrid->setAnnotationPosition( QgsLayoutItemMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "leftPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Left );
975  mapGrid->setAnnotationPosition( QgsLayoutItemMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "rightPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Right );
976  mapGrid->setAnnotationPosition( QgsLayoutItemMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "topPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Top );
977  mapGrid->setAnnotationPosition( QgsLayoutItemMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "bottomPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Bottom );
978  mapGrid->setAnnotationDirection( QgsLayoutItemMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "leftDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Left );
979  mapGrid->setAnnotationDirection( QgsLayoutItemMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "rightDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Right );
980  mapGrid->setAnnotationDirection( QgsLayoutItemMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "topDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Top );
981  mapGrid->setAnnotationDirection( QgsLayoutItemMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "bottomDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Bottom );
982  mapGrid->setAnnotationFrameDistance( annotationElem.attribute( QStringLiteral( "frameDistance" ), QStringLiteral( "0" ) ).toDouble() );
983  QFont annotationFont;
984  annotationFont.fromString( annotationElem.attribute( QStringLiteral( "font" ), QString() ) );
985  mapGrid->setAnnotationFont( annotationFont );
986  mapGrid->setAnnotationFontColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
987 
988  mapGrid->setAnnotationPrecision( annotationElem.attribute( QStringLiteral( "precision" ), QStringLiteral( "3" ) ).toInt() );
989  }
990  layoutItem->mGridStack->addGrid( mapGrid );
991  }
992 
993  //atlas
994  QDomNodeList atlasNodeList = itemElem.elementsByTagName( QStringLiteral( "AtlasMap" ) );
995  if ( !atlasNodeList.isEmpty() )
996  {
997  QDomElement atlasElem = atlasNodeList.at( 0 ).toElement();
998  layoutItem->mAtlasDriven = ( atlasElem.attribute( QStringLiteral( "atlasDriven" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
999  if ( atlasElem.hasAttribute( QStringLiteral( "fixedScale" ) ) ) // deprecated XML
1000  {
1001  layoutItem->setAtlasScalingMode( atlasElem.attribute( QStringLiteral( "fixedScale" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) ? QgsLayoutItemMap::AtlasScalingMode::Fixed : QgsLayoutItemMap::AtlasScalingMode::Auto );
1002  }
1003  else if ( atlasElem.hasAttribute( QStringLiteral( "scalingMode" ) ) )
1004  {
1005  layoutItem->setAtlasScalingMode( static_cast<QgsLayoutItemMap::AtlasScalingMode>( atlasElem.attribute( QStringLiteral( "scalingMode" ) ).toInt() ) );
1006  }
1007  layoutItem->setAtlasMargin( atlasElem.attribute( QStringLiteral( "margin" ), QStringLiteral( "0.1" ) ).toDouble() );
1008  }
1009 
1010  layoutItem->updateBoundingRect();
1011 
1012  return true;
1013 }
1014 
1015 bool QgsCompositionConverter::readScaleBarXml( QgsLayoutItemScaleBar *layoutItem, const QDomElement &itemElem, const QgsProject *project, const QgsStringMap &mapId2Uuid )
1016 {
1017  Q_UNUSED( project )
1018  restoreGeneralComposeItemProperties( layoutItem, itemElem );
1019 
1020  layoutItem->setHeight( itemElem.attribute( QStringLiteral( "height" ), QStringLiteral( "5.0" ) ).toDouble() );
1021  layoutItem->setHeight( itemElem.attribute( QStringLiteral( "height" ), QStringLiteral( "5.0" ) ).toDouble() );
1022  layoutItem->setLabelBarSpace( itemElem.attribute( QStringLiteral( "labelBarSpace" ), QStringLiteral( "3.0" ) ).toDouble() );
1023  layoutItem->setBoxContentSpace( itemElem.attribute( QStringLiteral( "boxContentSpace" ), QStringLiteral( "1.0" ) ).toDouble() );
1024  layoutItem->setNumberOfSegments( itemElem.attribute( QStringLiteral( "numSegments" ), QStringLiteral( "2" ) ).toInt() );
1025  layoutItem->setNumberOfSegmentsLeft( itemElem.attribute( QStringLiteral( "numSegmentsLeft" ), QStringLiteral( "0" ) ).toInt() );
1026  layoutItem->setUnitsPerSegment( itemElem.attribute( QStringLiteral( "numUnitsPerSegment" ), QStringLiteral( "1.0" ) ).toDouble() );
1027  layoutItem->setSegmentSizeMode( static_cast<QgsScaleBarSettings::SegmentSizeMode>( itemElem.attribute( QStringLiteral( "segmentSizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
1028  layoutItem->setMinimumBarWidth( itemElem.attribute( QStringLiteral( "minBarWidth" ), QStringLiteral( "50" ) ).toDouble() );
1029  layoutItem->setMaximumBarWidth( itemElem.attribute( QStringLiteral( "maxBarWidth" ), QStringLiteral( "150" ) ).toDouble() );
1030  layoutItem->mSegmentMillimeters = itemElem.attribute( QStringLiteral( "segmentMillimeters" ), QStringLiteral( "0.0" ) ).toDouble();
1031  layoutItem->setMapUnitsPerScaleBarUnit( itemElem.attribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QStringLiteral( "1.0" ) ).toDouble() );
1032  layoutItem->setLineWidth( itemElem.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "0.3" ) ).toDouble() );
1033  layoutItem->setUnitLabel( itemElem.attribute( QStringLiteral( "unitLabel" ) ) );
1034  layoutItem->setLineJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( itemElem.attribute( QStringLiteral( "lineJoinStyle" ), QStringLiteral( "miter" ) ) ) );
1035  layoutItem->setLineCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( itemElem.attribute( QStringLiteral( "lineCapStyle" ), QStringLiteral( "square" ) ) ) );
1036  QFont f;
1037  if ( !QgsFontUtils::setFromXmlChildNode( f, itemElem, QStringLiteral( "scaleBarFont" ) ) )
1038  {
1039  f.fromString( itemElem.attribute( QStringLiteral( "font" ), QString() ) );
1040  }
1042  layoutItem->setFont( f );
1044 
1045  //colors
1046  //fill color
1047  QDomNodeList fillColorList = itemElem.elementsByTagName( QStringLiteral( "fillColor" ) );
1048  if ( !fillColorList.isEmpty() )
1049  {
1050  QDomElement fillColorElem = fillColorList.at( 0 ).toElement();
1051  bool redOk, greenOk, blueOk, alphaOk;
1052  int fillRed, fillGreen, fillBlue, fillAlpha;
1053 
1054  fillRed = fillColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1055  fillGreen = fillColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1056  fillBlue = fillColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1057  fillAlpha = fillColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1058 
1059  if ( redOk && greenOk && blueOk && alphaOk )
1060  {
1061  layoutItem->setFillColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
1062  }
1063  }
1064  else
1065  {
1066  layoutItem->setFillColor( QColor( itemElem.attribute( QStringLiteral( "brushColor" ), QStringLiteral( "#000000" ) ) ) );
1067  }
1068 
1069  //fill color 2
1070  QDomNodeList fillColor2List = itemElem.elementsByTagName( QStringLiteral( "fillColor2" ) );
1071  if ( !fillColor2List.isEmpty() )
1072  {
1073  QDomElement fillColor2Elem = fillColor2List.at( 0 ).toElement();
1074  bool redOk, greenOk, blueOk, alphaOk;
1075  int fillRed, fillGreen, fillBlue, fillAlpha;
1076 
1077  fillRed = fillColor2Elem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1078  fillGreen = fillColor2Elem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1079  fillBlue = fillColor2Elem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1080  fillAlpha = fillColor2Elem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1081 
1082  if ( redOk && greenOk && blueOk && alphaOk )
1083  {
1084  layoutItem->setFillColor2( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
1085  }
1086  }
1087  else
1088  {
1089  layoutItem->setFillColor2( QColor( itemElem.attribute( QStringLiteral( "brush2Color" ), QStringLiteral( "#ffffff" ) ) ) );
1090  }
1091 
1092  //stroke color
1093  QDomNodeList strokeColorList = itemElem.elementsByTagName( QStringLiteral( "strokeColor" ) );
1094  if ( !strokeColorList.isEmpty() )
1095  {
1096  QDomElement strokeColorElem = strokeColorList.at( 0 ).toElement();
1097  bool redOk, greenOk, blueOk, alphaOk;
1098  int strokeRed, strokeGreen, strokeBlue, strokeAlpha;
1099 
1100  strokeRed = strokeColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1101  strokeGreen = strokeColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1102  strokeBlue = strokeColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1103  strokeAlpha = strokeColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1104 
1105  if ( redOk && greenOk && blueOk && alphaOk )
1106  {
1107  layoutItem->setLineColor( QColor( strokeRed, strokeGreen, strokeBlue, strokeAlpha ) );
1108  QPen p = layoutItem->mSettings.pen();
1109  p.setColor( layoutItem->mSettings.lineColor() );
1110  layoutItem->setPen( p );
1111  }
1112  }
1113  else
1114  {
1115  layoutItem->setLineColor( QColor( itemElem.attribute( QStringLiteral( "penColor" ), QStringLiteral( "#000000" ) ) ) );
1116  QPen p = layoutItem->mSettings.pen();
1117  p.setColor( layoutItem->mSettings.lineColor() );
1118  layoutItem->setPen( p );
1119  }
1120 
1121  //font color
1122  QDomNodeList textColorList = itemElem.elementsByTagName( QStringLiteral( "textColor" ) );
1123  if ( !textColorList.isEmpty() )
1124  {
1125  QDomElement textColorElem = textColorList.at( 0 ).toElement();
1126  bool redOk, greenOk, blueOk, alphaOk;
1127  int textRed, textGreen, textBlue, textAlpha;
1128 
1129  textRed = textColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1130  textGreen = textColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1131  textBlue = textColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1132  textAlpha = textColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1133 
1134  if ( redOk && greenOk && blueOk && alphaOk )
1135  {
1137  layoutItem->setFontColor( QColor( textRed, textGreen, textBlue, textAlpha ) );
1139  }
1140  }
1141  else
1142  {
1143  QColor c;
1144  c.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
1146  layoutItem->setFontColor( c );
1148  }
1149 
1150  //style
1151  QString styleString = itemElem.attribute( QStringLiteral( "style" ), QString() );
1152  layoutItem->setStyle( QObject::tr( styleString.toLocal8Bit().data() ) );
1153 
1154  if ( itemElem.attribute( QStringLiteral( "unitType" ) ).isEmpty() )
1155  {
1157  switch ( itemElem.attribute( QStringLiteral( "units" ) ).toInt() )
1158  {
1159  case 0:
1161  break;
1162  case 1:
1164  break;
1165  case 2:
1167  break;
1168  case 3:
1170  break;
1171  }
1172  layoutItem->setUnits( u );
1173  }
1174  else
1175  {
1176  layoutItem->setUnits( QgsUnitTypes::decodeDistanceUnit( itemElem.attribute( QStringLiteral( "unitType" ) ) ) );
1177  }
1178  layoutItem->setAlignment( static_cast< QgsScaleBarSettings::Alignment >( itemElem.attribute( QStringLiteral( "alignment" ), QStringLiteral( "0" ) ).toInt() ) );
1179 
1180  //composer map: use uuid
1181  QString mapId = itemElem.attribute( QStringLiteral( "mapId" ), QStringLiteral( "-1" ) );
1182  if ( mapId != QStringLiteral( "-1" ) && mapId2Uuid.contains( mapId ) )
1183  {
1184  QgsLayoutItemMap *mapInstance = qobject_cast<QgsLayoutItemMap *>( layoutItem->layout()->itemByUuid( mapId2Uuid[ mapId ] ) );
1185  if ( mapInstance )
1186  {
1187  layoutItem->setLinkedMap( mapInstance );
1188  }
1189  }
1190 
1191  return true;
1192 }
1193 
1194 bool QgsCompositionConverter::readLegendXml( QgsLayoutItemLegend *layoutItem, const QDomElement &itemElem, const QgsProject *project, const QgsStringMap &mapId2Uuid )
1195 {
1196  restoreGeneralComposeItemProperties( layoutItem, itemElem );
1197 
1198  QgsPathResolver pathResolver;
1199  if ( project )
1200  pathResolver = project->pathResolver();
1201  QgsReadWriteContext context;
1202  context.setPathResolver( pathResolver );
1203  context.setProjectTranslator( const_cast<QgsProject *>( project ) );
1204 
1205  //composer map: use uuid
1206  QString mapId = itemElem.attribute( QStringLiteral( "map" ), QStringLiteral( "-1" ) );
1207  if ( mapId != QStringLiteral( "-1" ) && mapId2Uuid.contains( mapId ) )
1208  {
1209  QgsLayoutItemMap *mapInstance = qobject_cast<QgsLayoutItemMap *>( layoutItem->layout()->itemByUuid( mapId2Uuid[ mapId ] ) );
1210  if ( mapInstance )
1211  {
1212  layoutItem->setLinkedMap( mapInstance );
1213  }
1214  }
1215 
1216  //read general properties
1217  layoutItem->setTitle( itemElem.attribute( QStringLiteral( "title" ) ) );
1218  if ( !itemElem.attribute( QStringLiteral( "titleAlignment" ) ).isEmpty() )
1219  {
1220  layoutItem->setTitleAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "titleAlignment" ) ).toInt() ) );
1221  }
1222  int colCount = itemElem.attribute( QStringLiteral( "columnCount" ), QStringLiteral( "1" ) ).toInt();
1223  if ( colCount < 1 ) colCount = 1;
1224  layoutItem->setColumnCount( colCount );
1225  layoutItem->setSplitLayer( itemElem.attribute( QStringLiteral( "splitLayer" ), QStringLiteral( "0" ) ).toInt() == 1 );
1226  layoutItem->setEqualColumnWidth( itemElem.attribute( QStringLiteral( "equalColumnWidth" ), QStringLiteral( "0" ) ).toInt() == 1 );
1227 
1228  QDomNodeList stylesNodeList = itemElem.elementsByTagName( QStringLiteral( "styles" ) );
1229  if ( !stylesNodeList.isEmpty() )
1230  {
1231  QDomNode stylesNode = stylesNodeList.at( 0 );
1232  for ( int i = 0; i < stylesNode.childNodes().size(); i++ )
1233  {
1234  QDomElement styleElem = stylesNode.childNodes().at( i ).toElement();
1235  QgsLegendStyle style;
1236  style.readXml( styleElem, QDomDocument() );
1237  QString name = styleElem.attribute( QStringLiteral( "name" ) );
1239  if ( name == QLatin1String( "title" ) ) s = QgsLegendStyle::Title;
1240  else if ( name == QLatin1String( "group" ) ) s = QgsLegendStyle::Group;
1241  else if ( name == QLatin1String( "subgroup" ) ) s = QgsLegendStyle::Subgroup;
1242  else if ( name == QLatin1String( "symbol" ) ) s = QgsLegendStyle::Symbol;
1243  else if ( name == QLatin1String( "symbolLabel" ) ) s = QgsLegendStyle::SymbolLabel;
1244  else continue;
1245  layoutItem->setStyle( s, style );
1246  }
1247  }
1248 
1249  //font color
1250  QColor fontClr;
1251  fontClr.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
1252  layoutItem->setFontColor( fontClr );
1253 
1254  //spaces
1255  layoutItem->setBoxSpace( itemElem.attribute( QStringLiteral( "boxSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
1256  layoutItem->setColumnSpace( itemElem.attribute( QStringLiteral( "columnSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
1257 
1258  layoutItem->setSymbolWidth( itemElem.attribute( QStringLiteral( "symbolWidth" ), QStringLiteral( "7.0" ) ).toDouble() );
1259  layoutItem->setSymbolHeight( itemElem.attribute( QStringLiteral( "symbolHeight" ), QStringLiteral( "14.0" ) ).toDouble() );
1260  layoutItem->setWmsLegendWidth( itemElem.attribute( QStringLiteral( "wmsLegendWidth" ), QStringLiteral( "50" ) ).toDouble() );
1261  layoutItem->setWmsLegendHeight( itemElem.attribute( QStringLiteral( "wmsLegendHeight" ), QStringLiteral( "25" ) ).toDouble() );
1262  layoutItem->setLineSpacing( itemElem.attribute( QStringLiteral( "lineSpacing" ), QStringLiteral( "1.0" ) ).toDouble() );
1263 
1264  layoutItem->setDrawRasterStroke( itemElem.attribute( QStringLiteral( "rasterBorder" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
1265  layoutItem->setRasterStrokeColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "rasterBorderColor" ), QStringLiteral( "0,0,0" ) ) ) );
1266  layoutItem->setRasterStrokeWidth( itemElem.attribute( QStringLiteral( "rasterBorderWidth" ), QStringLiteral( "0" ) ).toDouble() );
1267 
1268  layoutItem->setWrapString( itemElem.attribute( QStringLiteral( "wrapChar" ) ) );
1269 
1270  layoutItem->mSizeToContents = itemElem.attribute( QStringLiteral( "resizeToContents" ), QStringLiteral( "1" ) ) != QLatin1String( "0" );
1271  layoutItem->mLegendFilterByMap = itemElem.attribute( QStringLiteral( "legendFilterByMap" ), QStringLiteral( "0" ) ).toInt();
1272  layoutItem->mFilterOutAtlas = itemElem.attribute( QStringLiteral( "legendFilterByAtlas" ), QStringLiteral( "0" ) ).toInt();
1273 
1274  // QGIS >= 2.6
1275  QDomElement layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree" ) );
1276  if ( layerTreeElem.isNull() )
1277  layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree-group" ) );
1278 
1279  if ( !layerTreeElem.isNull() )
1280  {
1281  QgsLayerTree *tree( QgsLayerTree::readXml( layerTreeElem, context ) );
1282  if ( project )
1283  tree->resolveReferences( project, true );
1284  layoutItem->setCustomLayerTree( tree );
1285  }
1286  else
1287  {
1288  layoutItem->setCustomLayerTree( nullptr );
1289  }
1290 
1291  return true;
1292 }
1293 
1294 bool QgsCompositionConverter::readAtlasXml( QgsLayoutAtlas *atlasItem, const QDomElement &itemElem, const QgsProject *project )
1295 {
1296  atlasItem->setEnabled( itemElem.attribute( QStringLiteral( "enabled" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1297 
1298  // look for stored layer name
1299  QString layerId = itemElem.attribute( QStringLiteral( "coverageLayer" ) );
1300  QString layerName = itemElem.attribute( QStringLiteral( "coverageLayerName" ) );
1301  QString layerSource = itemElem.attribute( QStringLiteral( "coverageLayerSource" ) );
1302  QString layerProvider = itemElem.attribute( QStringLiteral( "coverageLayerProvider" ) );
1303 
1304  QgsVectorLayerRef layerRef( layerId, layerName, layerSource, layerProvider );
1305  atlasItem->setCoverageLayer( layerRef.resolveWeakly( project ) );
1306 
1307  atlasItem->setPageNameExpression( itemElem.attribute( QStringLiteral( "pageNameExpression" ), QString() ) );
1308  QString errorString;
1309  atlasItem->setFilenameExpression( itemElem.attribute( QStringLiteral( "filenamePattern" ), QString() ), errorString );
1310  // note: no error reporting for errorString
1311  atlasItem->setSortFeatures( itemElem.attribute( QStringLiteral( "sortFeatures" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1312  if ( atlasItem->sortFeatures() )
1313  {
1314  atlasItem->setSortExpression( itemElem.attribute( QStringLiteral( "sortKey" ), QString() ) );
1315  atlasItem->setSortAscending( itemElem.attribute( QStringLiteral( "sortAscending" ), QStringLiteral( "true" ) ) == QLatin1String( "true" ) );
1316  }
1317  atlasItem->setFilterFeatures( itemElem.attribute( QStringLiteral( "filterFeatures" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1318  if ( atlasItem->filterFeatures( ) )
1319  {
1320  QString expErrorString;
1321  atlasItem->setFilterExpression( itemElem.attribute( QStringLiteral( "featureFilter" ), QString() ), expErrorString );
1322  // note: no error reporting for errorString
1323  }
1324 
1325  atlasItem->setHideCoverage( itemElem.attribute( QStringLiteral( "hideCoverage" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1326 
1327  return true;
1328 
1329 }
1330 
1331 bool QgsCompositionConverter::readHtmlXml( QgsLayoutItemHtml *layoutItem, const QDomElement &itemElem, const QgsProject *project )
1332 {
1333  Q_UNUSED( project )
1334  readOldComposerObjectXml( layoutItem, itemElem );
1335 
1336  //first create the frames
1337  layoutItem->setResizeMode( static_cast< QgsLayoutMultiFrame::ResizeMode >( itemElem.attribute( QStringLiteral( "resizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
1338  QDomNodeList frameList = itemElem.elementsByTagName( QStringLiteral( "ComposerFrame" ) );
1339  for ( int i = 0; i < frameList.size(); ++i )
1340  {
1341  QDomElement frameElem = frameList.at( i ).toElement();
1342  QgsLayoutFrame *newFrame = new QgsLayoutFrame( layoutItem->layout(), layoutItem );
1343  restoreGeneralComposeItemProperties( newFrame, frameElem );
1344  // Read frame XML
1345  double x = itemElem.attribute( QStringLiteral( "sectionX" ) ).toDouble();
1346  double y = itemElem.attribute( QStringLiteral( "sectionY" ) ).toDouble();
1347  double width = itemElem.attribute( QStringLiteral( "sectionWidth" ) ).toDouble();
1348  double height = itemElem.attribute( QStringLiteral( "sectionHeight" ) ).toDouble();
1349  newFrame->setContentSection( QRectF( x, y, width, height ) );
1350  newFrame->setHidePageIfEmpty( itemElem.attribute( QStringLiteral( "hidePageIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
1351  newFrame->setHideBackgroundIfEmpty( itemElem.attribute( QStringLiteral( "hideBackgroundIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
1352  layoutItem->addFrame( newFrame, false );
1353  }
1354 
1355  bool contentModeOK;
1356  layoutItem->setContentMode( static_cast< QgsLayoutItemHtml::ContentMode >( itemElem.attribute( QStringLiteral( "contentMode" ) ).toInt( &contentModeOK ) ) );
1357  if ( !contentModeOK )
1358  {
1359  layoutItem->setContentMode( QgsLayoutItemHtml::ContentMode::Url );
1360  }
1361  layoutItem->setEvaluateExpressions( itemElem.attribute( QStringLiteral( "evaluateExpressions" ), QStringLiteral( "true" ) ) == QLatin1String( "true" ) );
1362  layoutItem->setUseSmartBreaks( itemElem.attribute( QStringLiteral( "useSmartBreaks" ), QStringLiteral( "true" ) ) == QLatin1String( "true" ) );
1363  layoutItem->setMaxBreakDistance( itemElem.attribute( QStringLiteral( "maxBreakDistance" ), QStringLiteral( "10" ) ).toDouble() );
1364  layoutItem->setHtml( itemElem.attribute( QStringLiteral( "html" ) ) );
1365  layoutItem->setUserStylesheet( itemElem.attribute( QStringLiteral( "stylesheet" ) ) );
1366  layoutItem->setUserStylesheetEnabled( itemElem.attribute( QStringLiteral( "stylesheetEnabled" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1367 
1368  //finally load the set url
1369  QString urlString = itemElem.attribute( QStringLiteral( "url" ) );
1370  if ( !urlString.isEmpty() )
1371  {
1372  layoutItem->setUrl( urlString );
1373  }
1374  layoutItem->loadHtml( true );
1375 
1376  return true;
1377 }
1378 
1379 bool QgsCompositionConverter::readTableXml( QgsLayoutItemAttributeTable *layoutItem, const QDomElement &itemElem, const QgsProject *project )
1380 {
1381 
1382  Q_UNUSED( project )
1383  readOldComposerObjectXml( layoutItem, itemElem );
1384 
1385  //first create the frames
1386  layoutItem->setResizeMode( static_cast< QgsLayoutMultiFrame::ResizeMode >( itemElem.attribute( QStringLiteral( "resizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
1387  QDomNodeList frameList = itemElem.elementsByTagName( QStringLiteral( "ComposerFrame" ) );
1388  for ( int i = 0; i < frameList.size(); ++i )
1389  {
1390  QDomElement frameElem = frameList.at( i ).toElement();
1391  QgsLayoutFrame *newFrame = new QgsLayoutFrame( layoutItem->layout(), layoutItem );
1392  restoreGeneralComposeItemProperties( newFrame, frameElem );
1393  // Read frame XML
1394  double x = itemElem.attribute( QStringLiteral( "sectionX" ) ).toDouble();
1395  double y = itemElem.attribute( QStringLiteral( "sectionY" ) ).toDouble();
1396  double width = itemElem.attribute( QStringLiteral( "sectionWidth" ) ).toDouble();
1397  double height = itemElem.attribute( QStringLiteral( "sectionHeight" ) ).toDouble();
1398  newFrame->setContentSection( QRectF( x, y, width, height ) );
1399  newFrame->setHidePageIfEmpty( itemElem.attribute( QStringLiteral( "hidePageIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
1400  newFrame->setHideBackgroundIfEmpty( itemElem.attribute( QStringLiteral( "hideBackgroundIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
1401  layoutItem->addFrame( newFrame, false );
1402  }
1403 
1404  layoutItem->setEmptyTableBehavior( static_cast<QgsLayoutTable::EmptyTableMode>( itemElem.attribute( QStringLiteral( "emptyTableMode" ), QStringLiteral( "0" ) ).toInt() ) );
1405  layoutItem->setEmptyTableMessage( itemElem.attribute( QStringLiteral( "emptyTableMessage" ), QObject::tr( "No matching records" ) ) );
1406  layoutItem->setShowEmptyRows( itemElem.attribute( QStringLiteral( "showEmptyRows" ), QStringLiteral( "0" ) ).toInt() );
1407  if ( !QgsFontUtils::setFromXmlChildNode( layoutItem->mHeaderFont, itemElem, QStringLiteral( "headerFontProperties" ) ) )
1408  {
1409  layoutItem->mHeaderFont.fromString( itemElem.attribute( QStringLiteral( "headerFont" ), QString() ) );
1410  }
1411  layoutItem->setHeaderFontColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "headerFontColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
1412  layoutItem->setHeaderHAlignment( static_cast<QgsLayoutTable::HeaderHAlignment>( itemElem.attribute( QStringLiteral( "headerHAlignment" ), QStringLiteral( "0" ) ).toInt() ) ) ;
1413  layoutItem->setHeaderMode( static_cast<QgsLayoutTable::HeaderMode>( itemElem.attribute( QStringLiteral( "headerMode" ), QStringLiteral( "0" ) ).toInt() ) );
1414  if ( !QgsFontUtils::setFromXmlChildNode( layoutItem->mContentFont, itemElem, QStringLiteral( "contentFontProperties" ) ) )
1415  {
1416  layoutItem->mContentFont.fromString( itemElem.attribute( QStringLiteral( "contentFont" ), QString() ) );
1417  }
1418  layoutItem->setContentFontColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "contentFontColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
1419  layoutItem->setCellMargin( itemElem.attribute( QStringLiteral( "cellMargin" ), QStringLiteral( "1.0" ) ).toDouble() );
1420  layoutItem->setGridStrokeWidth( itemElem.attribute( QStringLiteral( "gridStrokeWidth" ), QStringLiteral( "0.5" ) ).toDouble() );
1421  layoutItem->setHorizontalGrid( itemElem.attribute( QStringLiteral( "horizontalGrid" ), QStringLiteral( "1" ) ).toInt() );
1422  layoutItem->setVerticalGrid( itemElem.attribute( QStringLiteral( "verticalGrid" ), QStringLiteral( "1" ) ).toInt() );
1423  layoutItem->setShowGrid( itemElem.attribute( QStringLiteral( "showGrid" ), QStringLiteral( "1" ) ).toInt() );
1424  layoutItem->setGridColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "gridColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
1425  layoutItem->setBackgroundColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "backgroundColor" ), QStringLiteral( "255,255,255,0" ) ) ) );
1426  layoutItem->setWrapBehavior( static_cast<QgsLayoutTable::WrapBehavior>( itemElem.attribute( QStringLiteral( "wrapBehavior" ), QStringLiteral( "0" ) ).toInt() ) );
1427 
1428  //restore column specifications
1429  layoutItem->mColumns.clear();
1430  QDomNodeList columnsList = itemElem.elementsByTagName( QStringLiteral( "displayColumns" ) );
1431  if ( !columnsList.isEmpty() )
1432  {
1433  QDomElement columnsElem = columnsList.at( 0 ).toElement();
1434  QDomNodeList columnEntryList = columnsElem.elementsByTagName( QStringLiteral( "column" ) );
1435  for ( int i = 0; i < columnEntryList.size(); ++i )
1436  {
1437  QDomElement columnElem = columnEntryList.at( i ).toElement();
1439  column->mHAlignment = static_cast< Qt::AlignmentFlag >( columnElem.attribute( QStringLiteral( "hAlignment" ), QString::number( Qt::AlignLeft ) ).toInt() );
1440  column->mVAlignment = static_cast< Qt::AlignmentFlag >( columnElem.attribute( QStringLiteral( "vAlignment" ), QString::number( Qt::AlignVCenter ) ).toInt() );
1441  column->mHeading = columnElem.attribute( QStringLiteral( "heading" ), QString() );
1442  column->mAttribute = columnElem.attribute( QStringLiteral( "attribute" ), QString() );
1443  column->mSortByRank = columnElem.attribute( QStringLiteral( "sortByRank" ), QStringLiteral( "0" ) ).toInt();
1444  column->mSortOrder = static_cast< Qt::SortOrder >( columnElem.attribute( QStringLiteral( "sortOrder" ), QString::number( Qt::AscendingOrder ) ).toInt() );
1445  column->mWidth = columnElem.attribute( QStringLiteral( "width" ), QStringLiteral( "0.0" ) ).toDouble();
1446 
1447  QDomNodeList bgColorList = columnElem.elementsByTagName( QStringLiteral( "backgroundColor" ) );
1448  if ( !bgColorList.isEmpty() )
1449  {
1450  QDomElement bgColorElem = bgColorList.at( 0 ).toElement();
1451  bool redOk, greenOk, blueOk, alphaOk;
1452  int bgRed, bgGreen, bgBlue, bgAlpha;
1453  bgRed = bgColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1454  bgGreen = bgColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1455  bgBlue = bgColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1456  bgAlpha = bgColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1457  if ( redOk && greenOk && blueOk && alphaOk )
1458  {
1459  column->mBackgroundColor = QColor( bgRed, bgGreen, bgBlue, bgAlpha );
1460  }
1461  }
1462  layoutItem->mColumns.append( column );
1463  }
1464  }
1465 
1466  //restore cell styles
1467  QDomNodeList stylesList = itemElem.elementsByTagName( QStringLiteral( "cellStyles" ) );
1468  if ( !stylesList.isEmpty() )
1469  {
1470  QDomElement stylesElem = stylesList.at( 0 ).toElement();
1471 
1472  QMap< QgsLayoutTable::CellStyleGroup, QString >::const_iterator it = layoutItem->mCellStyleNames.constBegin();
1473  for ( ; it != layoutItem->mCellStyleNames.constEnd(); ++it )
1474  {
1475  QString styleName = it.value();
1476  QDomNodeList styleList = stylesElem.elementsByTagName( styleName );
1477  if ( !styleList.isEmpty() )
1478  {
1479  QDomElement styleElem = styleList.at( 0 ).toElement();
1480  QgsLayoutTableStyle *style = layoutItem->mCellStyles.value( it.key() );
1481  if ( style )
1482  style->readXml( styleElem );
1483  }
1484  }
1485  }
1486 
1487  // look for stored layer name
1488  QString layerId = itemElem.attribute( QStringLiteral( "vectorLayer" ) );
1489  QString layerName = itemElem.attribute( QStringLiteral( "vectorLayerName" ) );
1490  QString layerSource = itemElem.attribute( QStringLiteral( "vectorLayerSource" ) );
1491  QString layerProvider = itemElem.attribute( QStringLiteral( "vectorLayerProvider" ) );
1492 
1493  QgsVectorLayerRef layerRef( layerId, layerName, layerSource, layerProvider );
1494  layoutItem->setVectorLayer( layerRef.resolveWeakly( project ) );
1495 
1496  return true;
1497 }
1498 
1499 
1500 template <class T, class T2>
1501 bool QgsCompositionConverter::readPolyXml( T *layoutItem, const QDomElement &itemElem, const QgsProject *project )
1502 {
1503  restoreGeneralComposeItemProperties( layoutItem, itemElem );
1504  QDomNodeList nodeList = itemElem.elementsByTagName( QStringLiteral( "node" ) );
1505  if ( !nodeList.isEmpty() )
1506  {
1507  QPolygonF polygon;
1508  for ( int i = 0; i < nodeList.length(); i++ )
1509  {
1510  QDomElement node = nodeList.at( i ).toElement();
1511  polygon.append( QPointF( node.attribute( QStringLiteral( "x" ) ).toDouble( ), node.attribute( QStringLiteral( "y" ) ).toDouble() ) );
1512  }
1513  layoutItem->setNodes( polygon );
1514  }
1515  if ( itemElem.elementsByTagName( QStringLiteral( "symbol" ) ).size() )
1516  {
1517  QDomElement symbolElement = itemElem.elementsByTagName( QStringLiteral( "symbol" ) ).at( 0 ).toElement();
1518  QgsReadWriteContext context;
1519  if ( project )
1520  context.setPathResolver( project->pathResolver( ) );
1521  T2 *styleSymbol = QgsSymbolLayerUtils::loadSymbol<T2>( symbolElement, context );
1522  if ( styleSymbol )
1523  layoutItem->setSymbol( styleSymbol );
1524  }
1525  // Disable frame for shapes
1526  layoutItem->setFrameEnabled( false );
1527  layoutItem->setBackgroundEnabled( false );
1528  return true;
1529 }
1530 
1531 
1532 bool QgsCompositionConverter::readXml( QgsLayoutItem *layoutItem, const QDomElement &itemElem )
1533 {
1534  if ( itemElem.isNull() )
1535  {
1536  return false;
1537  }
1538 
1539  readOldComposerObjectXml( layoutItem, itemElem );
1540 
1541  //uuid
1542  layoutItem->mUuid = itemElem.attribute( QStringLiteral( "uuid" ), QUuid::createUuid().toString() );
1543 
1544  // temporary for groups imported from templates
1545  layoutItem->mTemplateUuid = itemElem.attribute( QStringLiteral( "templateUuid" ) );
1546 
1547  //id
1548  QString id = itemElem.attribute( QStringLiteral( "id" ), QString() );
1549  layoutItem->setId( id );
1550 
1551  //frame
1552  QString frame = itemElem.attribute( QStringLiteral( "frame" ) );
1553  layoutItem->setFrameEnabled( frame.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 ) ;
1554 
1555  //frame
1556  QString background = itemElem.attribute( QStringLiteral( "background" ) );
1557  layoutItem->setBackgroundEnabled( background.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 );
1558 
1559  //position lock for mouse moves/resizes
1560  QString positionLock = itemElem.attribute( QStringLiteral( "positionLock" ) );
1561  layoutItem->setLocked( positionLock.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 );
1562 
1563  //visibility
1564  layoutItem->setVisibility( itemElem.attribute( QStringLiteral( "visibility" ), QStringLiteral( "1" ) ) != QStringLiteral( "0" ) );
1565 
1566  layoutItem->mParentGroupUuid = itemElem.attribute( QStringLiteral( "groupUuid" ) );
1567  if ( !layoutItem->mParentGroupUuid.isEmpty() )
1568  {
1569  if ( QgsLayoutItemGroup *group = layoutItem->parentGroup() )
1570  {
1571  group->addItem( layoutItem );
1572  }
1573  }
1574  layoutItem->mTemplateUuid = itemElem.attribute( QStringLiteral( "templateUuid" ) );
1575 
1576 
1577  QRectF position = itemPosition( layoutItem, itemElem );
1578 
1579  // TODO: missing?
1580  // mLastValidViewScaleFactor = itemElem.attribute( QStringLiteral( "lastValidViewScaleFactor" ), QStringLiteral( "-1" ) ).toDouble();
1581 
1582  layoutItem->setZValue( itemElem.attribute( QStringLiteral( "zValue" ) ).toDouble() );
1583 
1584  //pen
1585  QDomNodeList frameColorList = itemElem.elementsByTagName( QStringLiteral( "FrameColor" ) );
1586  if ( !frameColorList.isEmpty() )
1587  {
1588  QDomElement frameColorElem = frameColorList.at( 0 ).toElement();
1589  bool redOk, greenOk, blueOk, alphaOk, widthOk;
1590  int penRed, penGreen, penBlue, penAlpha;
1591  double penWidth;
1592 
1593  penWidth = itemElem.attribute( QStringLiteral( "outlineWidth" ) ).toDouble( &widthOk );
1594  penRed = frameColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1595  penGreen = frameColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1596  penBlue = frameColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1597  penAlpha = frameColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1598  layoutItem->setFrameJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( itemElem.attribute( QStringLiteral( "frameJoinStyle" ), QStringLiteral( "miter" ) ) ) );
1599 
1600  if ( redOk && greenOk && blueOk && alphaOk && widthOk )
1601  {
1602  layoutItem->setFrameStrokeColor( QColor( penRed, penGreen, penBlue, penAlpha ) );
1603  layoutItem->setFrameStrokeWidth( QgsLayoutMeasurement( penWidth ) );
1604  QPen framePen( layoutItem->frameStrokeColor() );
1605  framePen.setWidthF( layoutItem->frameStrokeWidth( ).length() );
1606  framePen.setJoinStyle( layoutItem->frameJoinStyle( ) );
1607  layoutItem->setPen( framePen );
1608  //apply any data defined settings
1609  layoutItem->refreshFrame( false );
1610  }
1611  }
1612 
1613  //brush
1614  QDomNodeList bgColorList = itemElem.elementsByTagName( QStringLiteral( "BackgroundColor" ) );
1615  if ( !bgColorList.isEmpty() )
1616  {
1617  QDomElement bgColorElem = bgColorList.at( 0 ).toElement();
1618  bool redOk, greenOk, blueOk, alphaOk;
1619  int bgRed, bgGreen, bgBlue, bgAlpha;
1620  bgRed = bgColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1621  bgGreen = bgColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1622  bgBlue = bgColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1623  bgAlpha = bgColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1624  if ( redOk && greenOk && blueOk && alphaOk )
1625  {
1626  layoutItem->mBackgroundColor = QColor( bgRed, bgGreen, bgBlue, bgAlpha );
1627  layoutItem->setBrush( QBrush( layoutItem->mBackgroundColor, Qt::SolidPattern ) );
1628  }
1629  //apply any data defined settings
1630  layoutItem->refreshBackgroundColor( false );
1631  }
1632 
1633  //blend mode
1634  layoutItem->setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( itemElem.attribute( QStringLiteral( "blendMode" ), QStringLiteral( "0" ) ).toUInt() ) ) );
1635 
1636  //opacity
1637  if ( itemElem.hasAttribute( QStringLiteral( "opacity" ) ) )
1638  {
1639  layoutItem->setItemOpacity( itemElem.attribute( QStringLiteral( "opacity" ), QStringLiteral( "1" ) ).toDouble() );
1640  }
1641  else
1642  {
1643  layoutItem->setItemOpacity( 1.0 - itemElem.attribute( QStringLiteral( "transparency" ), QStringLiteral( "0" ) ).toInt() / 100.0 );
1644  }
1645 
1646  layoutItem->mExcludeFromExports = itemElem.attribute( QStringLiteral( "excludeFromExports" ), QStringLiteral( "0" ) ).toInt();
1647  layoutItem->mEvaluatedExcludeFromExports = layoutItem->mExcludeFromExports;
1648 
1649  // positioning
1650  layoutItem->attemptSetSceneRect( position );
1651  //rotation
1652  layoutItem->setItemRotation( itemElem.attribute( QStringLiteral( "itemRotation" ), QStringLiteral( "0" ) ).toDouble(), false );
1653 
1654  layoutItem->mBlockUndoCommands = false;
1655 
1656  return true;
1657 }
1658 
1659 
1660 
1661 bool QgsCompositionConverter::readOldComposerObjectXml( QgsLayoutObject *layoutItem,
1662  const QDomElement &itemElem )
1663 {
1664  if ( itemElem.isNull() )
1665  {
1666  return false;
1667  }
1668 
1669  //old (pre 3.0) data defined properties
1670  QgsCompositionConverter::readOldDataDefinedPropertyMap( itemElem, layoutItem->mDataDefinedProperties );
1671 
1672  QDomNode propsNode = itemElem.namedItem( QStringLiteral( "dataDefinedProperties" ) );
1673  if ( !propsNode.isNull() )
1674  {
1675  layoutItem->mDataDefinedProperties.readXml( propsNode.toElement(), sPropertyDefinitions );
1676  }
1678  {
1679  // upgrade transparency -> opacity
1681  exp = QStringLiteral( "100.0 - (%1)" ).arg( exp );
1684  }
1685 
1686  //custom properties
1687  layoutItem->mCustomProperties.readXml( itemElem );
1688 
1689  return true;
1690 }
1691 
1692 
1693 void QgsCompositionConverter::readOldDataDefinedPropertyMap( const QDomElement &itemElem, QgsPropertyCollection &dataDefinedProperties )
1694 {
1695  const QgsPropertiesDefinition defs = QgsCompositionConverter::propertyDefinitions();
1696  QgsPropertiesDefinition::const_iterator i = defs.constBegin();
1697  for ( ; i != defs.constEnd(); ++i )
1698  {
1699  QString elemName = i.value().name();
1700  QDomNodeList ddNodeList = itemElem.elementsByTagName( elemName );
1701  if ( !ddNodeList.isEmpty() )
1702  {
1703  QDomElement ddElem = ddNodeList.at( 0 ).toElement();
1704  QgsProperty prop = readOldDataDefinedProperty( static_cast< QgsCompositionConverter::DataDefinedProperty >( i.key() ), ddElem );
1705  if ( prop )
1706  dataDefinedProperties.setProperty( i.key(), prop );
1707  }
1708  }
1709 }
1710 
1711 QgsProperty QgsCompositionConverter::readOldDataDefinedProperty( const QgsCompositionConverter::DataDefinedProperty property, const QDomElement &ddElem )
1712 {
1714  {
1715  //invalid property
1716  return QgsProperty();
1717  }
1718 
1719  QString active = ddElem.attribute( QStringLiteral( "active" ) );
1720  bool isActive = false;
1721  if ( active.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
1722  {
1723  isActive = true;
1724  }
1725  QString field = ddElem.attribute( QStringLiteral( "field" ) );
1726  QString expr = ddElem.attribute( QStringLiteral( "expr" ) );
1727 
1728  QString useExpr = ddElem.attribute( QStringLiteral( "useExpr" ) );
1729  bool isExpression = false;
1730  if ( useExpr.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
1731  {
1732  isExpression = true;
1733  }
1734 
1735  if ( isExpression )
1736  return QgsProperty::fromExpression( expr, isActive );
1737  else
1738  return QgsProperty::fromField( field, isActive );
1739 }
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
void setCoverageLayer(QgsVectorLayer *layer)
Sets the coverage layer to use for the atlas features.
void setColumnSpace(double spacing)
Sets the legend column spacing.
void setShapeType(QgsLayoutItemShape::Shape type)
Sets the type of shape (e.g.
void setFramePenSize(const double width)
Sets the width of the stroke drawn in the grid frame.
The class is used as a container of context for various read/write operations on other objects...
void setEqualColumnWidth(bool equalize)
Sets whether column widths should be equalized.
void setFontColor(const QColor &color)
Sets the legend font color.
void setIntervalY(double interval)
Sets the interval between grid lines in the y-direction.
void setFollowVisibilityPresetName(const QString &name)
Sets preset name for map rendering.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
void setLineWidth(double width)
Sets the line width in millimeters for lines in the scalebar.
void setWrapBehavior(WrapBehavior behavior)
Sets the wrap behavior for the table, which controls how text within cells is automatically wrapped...
void setTitle(const QString &title)
Sets the legend title.
void setOffsetX(double offset)
Sets the offset for grid lines in the x-direction.
void setPathResolver(const QgsPathResolver &resolver)
Sets up path resolver for conversion between relative and absolute paths.
Positive integer values (including 0)
Definition: qgsproperty.h:55
QMap< CellStyleGroup, QgsLayoutTableStyle *> mCellStyles
void setSplitLayer(bool enabled)
Sets whether the legend items from a single layer can be split over multiple columns.
void setLineJoinStyle(Qt::PenJoinStyle style)
Sets the join style used when drawing the lines in the scalebar.
void setAnnotationFontColor(const QColor &color)
Sets the font color used for drawing grid annotations.
void setFrameFillColor1(const QColor &color)
Sets the first fill color used for the grid frame.
Base class for graphical items within a QgsLayout.
void setSymbolWidth(double width)
Sets the legend symbol width.
An individual overview which is drawn above the map content in a QgsLayoutItemMap, and shows the extent of another QgsLayoutItemMap.
void setVAlign(Qt::AlignmentFlag alignment)
Sets for the vertical alignment of the label.
void setUserStylesheet(const QString &stylesheet)
Sets the user stylesheet CSS rules to use while rendering the HTML content.
void refreshBackgroundColor(bool updateItem=true)
Refresh item&#39;s background color, considering data defined colors.
void readXml(const QDomNode &parentNode, const QString &keyStartsWith=QString())
Read store contents from XML.
void setUserStylesheetEnabled(bool enabled)
Sets whether user stylesheets are enabled for the HTML content.
void setProjectTranslator(QgsProjectTranslator *projectTranslator)
Sets the project translator.
QPen pen() const
Returns the pen used for drawing outlines in the scalebar.
void setCellMargin(double margin)
Sets the margin distance in mm between cell borders and their contents.
A layout item subclass for text labels.
Preset paper size for composition.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
virtual bool readXml(const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions)
Reads property collection state from an XML element.
QString xmlData() const
Returns XML content of the style.
void readXml(const QDomElement &styleElement)
Read style configuration (for project file reading)
Q_DECL_DEPRECATED void setFontColor(const QColor &color)
Sets the color used for drawing text in the scalebar.
static QgsLineSymbol * createSimple(const QgsStringMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties. ...
Definition: qgssymbol.cpp:1299
TYPE * resolveWeakly(const QgsProject *project, MatchType matchType=MatchType::All)
Resolves the map layer by attempting to find a matching layer in a project using a weak match...
void setExtent(const QgsRectangle &extent)
Sets a new extent for the map.
QgsObjectCustomProperties mCustomProperties
Custom properties for object.
static QgsFillSymbol * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
Definition: qgssymbol.cpp:1310
void setLinkedMap(QgsLayoutItemMap *map)
Sets the map item linked to the scalebar.
void setSortAscending(bool ascending)
Sets whether features should be sorted in an ascending order.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
void setBoxContentSpace(double space)
Sets the space (margin) between the scalebar box and content in millimeters.
QgsLayoutSize sizeWithUnits() const
Returns the item&#39;s current size, including units.
void setHeaderFontColor(const QColor &color)
Sets the color used to draw header text in the table.
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:237
void setLineCapStyle(Qt::PenCapStyle style)
Sets the cap style used when drawing the lines in the scalebar.
bool frameEnabled() const
Returns true if the item includes a frame.
A container for grouping several QgsLayoutItems.
Styling option for a layout table cell.
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
Non-zero positive integer values.
Definition: qgsproperty.h:56
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:731
void setEmptyTableMessage(const QString &message)
Sets the message for empty tables with no content rows.
void setHtml(const QString &html)
Sets the html to display in the item when the item is using the QgsLayoutItemHtml::ManualHtml mode...
A layout item subclass that displays SVG files or raster format images (jpg, png, ...
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
static std::unique_ptr< QgsPrintLayout > createLayoutFromCompositionXml(const QDomElement &composerElement, QgsProject *project)
createLayoutFromCompositionXml is a factory that creates layout instances from a QGIS 2...
static QDomDocument convertCompositionTemplate(const QDomDocument &document, QgsProject *project)
Convert a composition template document to a layout template.
void setHeight(double height)
Sets the scalebar height (in millimeters).
void setAnnotationPosition(AnnotationPosition position, BorderSide side)
Sets the position for the grid annotations on a specified side of the map frame.
Contains detailed styling information relating to how a layout legend should be rendered.
void loadHtml(bool useCache=false, const QgsExpressionContext *context=nullptr)
Reloads the html source from the url and redraws the item.
void setFilterFeatures(bool filtered)
Sets whether features should be filtered in the coverage layer.
virtual void setFrameStrokeWidth(QgsLayoutMeasurement width)
Sets the frame stroke width.
void setVerticalGrid(bool verticalGrid)
Sets whether the grid&#39;s vertical lines should be drawn in the table.
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:20
void setBlendMode(const QPainter::CompositionMode mode)
Sets the blending mode used for drawing the grid.
Color with alpha channel.
Definition: qgsproperty.h:64
void setStyle(QgsLegendStyle::Style component, const QgsLegendStyle &style)
Sets the style of component to style for the legend.
void setAlignment(QgsScaleBarSettings::Alignment alignment)
Sets the scalebar alignment.
bool filterFeatures() const
Returns true if features should be filtered in the coverage layer.
void attemptMoveBy(double deltaX, double deltaY)
Attempts to shift the item&#39;s position by a specified deltaX and deltaY, in layout units...
QList< QgsLayoutItemPage *> pages()
Returns a list of pages in the collection.
void setKeepLayerSet(bool enabled)
Sets whether the stored layer set should be used or the current layer set of the associated project...
void setFrameStrokeColor(const QColor &color)
Sets the frame stroke color.
Layout item for node based polygon shapes.
QColor lineColor() const
Returns the color used for lines in the scalebar.
void setMarginX(double margin)
Sets the horizontal margin between the edge of the frame and the label contents, in layout units...
static Q_INVOKABLE QgsUnitTypes::DistanceUnit decodeDistanceUnit(const QString &string, bool *ok=nullptr)
Decodes a distance unit from a string.
void setPictureAnchor(QgsLayoutItem::ReferencePoint anchor)
Sets the picture&#39;s anchor point, which controls how it is placed within the picture item&#39;s frame...
Positive double value (including 0)
Definition: qgsproperty.h:58
void resolveReferences(const QgsProject *project, bool looseMatching=false) override
Calls resolveReferences() on child tree nodes.
void setLineColor(const QColor &color)
Sets the color used for lines in the scalebar.
void setSegmentSizeMode(QgsScaleBarSettings::SegmentSizeMode mode)
Sets the size mode for scale bar segments.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:694
void setStyle(const QString &name)
Sets the scale bar style by name.
Rotation (value between 0-360 degrees)
Definition: qgsproperty.h:60
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
void setSortExpression(const QString &expression)
Sets the expression (or field name) to use for sorting features.
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:1095
Stores properties of a column for a QgsLayoutTable.
Any string value.
Definition: qgsproperty.h:61
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
void setFrameWidth(const double width)
Sets the grid frame width (in layout units).
void setContentSection(const QRectF &section)
Sets the visible part of the multiframe&#39;s content which is visible within this frame (relative to the...
QgsLayoutMeasurement frameStrokeWidth() const
Returns the frame&#39;s stroke width.
void setDrawRasterStroke(bool enabled)
Sets whether a stroke will be drawn around raster symbol items.
double spaceBetweenPages() const
Returns the space between pages, in layout units.
static QString encodeColor(const QColor &color)
This class provides a method of storing points, consisting of an x and y coordinate, for use in QGIS layouts.
void setAnnotationFont(const QFont &font)
Sets the font used for drawing grid annotations.
ReferencePoint
Fixed position reference point.
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 setFillColor(const QColor &color)
Sets the color used for fills in the scalebar.
bool setFilenameExpression(const QString &expression, QString &errorString)
Sets the filename expression used for generating output filenames for each atlas page.
void setHeaderMode(HeaderMode mode)
Sets the display mode for headers in the table.
Stores style information (renderer, opacity, labeling, diagrams etc.) applicable to a map layer...
void setMaximumBarWidth(double maxWidth)
Sets the maximum width (in millimeters) for scale bar segments.
void setEvaluateExpressions(bool evaluateExpressions)
Sets whether the html item will evaluate QGIS expressions prior to rendering the HTML content...
Layout graphical items for displaying a map.
Layout item for node based polyline shapes.
virtual void setId(const QString &id)
Set the item&#39;s id name.
QString layerId
Original layer ID.
QgsPropertyCollection mDataDefinedProperties
const QgsLayout * layout() const
Returns the layout the object is attached to.
void setNumberOfSegments(int segments)
Sets the number of segments included in the scalebar.
void setHAlign(Qt::AlignmentFlag alignment)
Sets the horizontal alignment of the label.
void setLocked(bool locked)
Sets whether the item is locked, preventing mouse interactions with the item.
Namespace with helper functions for layer tree operations.
Definition: qgslayertree.h:32
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.
QgsPathResolver pathResolver() const
Returns path resolver object with considering whether the project uses absolute or relative paths and...
void setHorizontalGrid(bool horizontalGrid)
Sets whether the grid&#39;s horizontal lines should be drawn in the table.
void setFrameJoinStyle(Qt::PenJoinStyle style)
Sets the join style used when drawing the item&#39;s frame.
bool hasBackground() const
Returns true if the item has a background.
void setMapUnitsPerScaleBarUnit(double units)
Sets the number of map units per scale bar unit used by the scalebar.
void setUseSmartBreaks(bool useSmartBreaks)
Sets whether the html item should use smart breaks.
void setFrameFillColor2(const QColor &color)
Sets the second fill color used for the grid frame.
void setWidth(double width)
Sets the width for the whole line symbol.
Definition: qgssymbol.cpp:1789
QgsLayoutPageCollection * pageCollection()
Returns a pointer to the layout&#39;s page collection, which stores and manages page items in the layout...
Definition: qgslayout.cpp:458
void setBlendMode(QPainter::CompositionMode mode)
Sets the item&#39;s composition blending mode.
void setHeaderHAlignment(HeaderHAlignment alignment)
Sets the horizontal alignment for table headers.
void attemptSetSceneRect(const QRectF &rect, bool includesFrame=false)
Attempts to update the item&#39;s position and size to match the passed rect in layout coordinates...
void setResizeMode(ResizeMode mode)
Sets the resize mode for the multiframe, and recalculates frame sizes to match.
Layout item for basic filled shapes (e.g.
void setFramePenColor(const QColor &color)
Sets the color of the stroke drawn in the grid frame.
Class used to render QgsLayout as an atlas, by iterating over the features from an associated vector ...
void setMinimumBarWidth(double minWidth)
Sets the minimum width (in millimeters) for scale bar segments.
void setMode(Mode mode)
Sets the label&#39;s current mode, allowing the label to switch between font based and HTML based renderi...
void setRasterStrokeColor(const QColor &color)
Sets the stroke color for the stroke drawn around raster symbol items.
virtual void setItemRotation(double rotation, bool adjustPosition=true)
Sets the layout item&#39;s rotation, in degrees clockwise.
Symbol icon (excluding label)
void setAnnotationEnabled(const bool enabled)
Sets whether annotations should be shown for the grid.
void setLinkedMap(QgsLayoutItemMap *map)
Sets the map object for rotation.
void setMarginY(double margin)
Sets the vertical margin between the edge of the frame and the label contents, in layout units...
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc.
Definition: qgsproject.h:91
void setFrameStyle(const FrameStyle style)
Sets the grid frame style.
A layout table subclass that displays attributes from a vector layer.
void setHideBackgroundIfEmpty(bool hideBackgroundIfEmpty)
Sets whether the background and frame stroke should be hidden if this frame is empty.
static bool setFromXmlChildNode(QFont &font, const QDomElement &element, const QString &childNode)
Sets the properties of a font to match the properties stored in an XML child node.
void setContentFontColor(const QColor &color)
Sets the color used to draw text in table body cells.
Legend subgroup title.
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the map&#39;s preset crs (coordinate reference system).
void setHideCoverage(bool hide)
Sets whether the coverage layer should be hidden in map items in the layouts.
static Qt::PenCapStyle decodePenCapStyle(const QString &str)
void setLineSpacing(double spacing)
Sets the spacing in-between multiple lines.
QFont mHeaderFont
Header font.
void setPicturePath(const QString &path)
Sets the source path of the image (may be svg or a raster format).
void setUnitLabel(const QString &label)
Sets the label for units.
AnnotationFormat
Format for displaying grid annotations.
A store for object properties.
Definition: qgsproperty.h:229
void setFillColor2(const QColor &color)
Sets the secondary color used for fills in the scalebar.
QColor frameStrokeColor() const
Returns the frame&#39;s stroke color.
void setAtlasScalingMode(AtlasScalingMode mode)
Sets the current atlas scaling mode.
void setStyle(GridStyle style)
Sets the grid style, which controls how the grid is drawn over the map&#39;s contents.
Double value (including negative values)
Definition: qgsproperty.h:57
void setGridStrokeWidth(double width)
Sets the width in mm for grid lines in the table.
void setAnnotationDirection(AnnotationDirection direction, BorderSide side)
Sets the direction for drawing frame annotations for the specified map side.
void setWrapString(const QString &string)
Sets the legend text wrapping string.
virtual void setVisibility(bool visible)
Sets whether the item is visible.
Style
Component of legends which can be styled.
void setContentMode(ContentMode mode)
Sets the source mode for item&#39;s HTML content.
void setVectorLayer(QgsVectorLayer *layer)
Sets the vector layer from which to display feature attributes.
An individual grid which is drawn above the map content in a QgsLayoutItemMap.
AnnotationDirection
Direction of grid annotations.
Definition for a property.
Definition: qgsproperty.h:46
QFont mContentFont
Table contents font.
void setLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol used for drawing grid lines.
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
void setColumnCount(int count)
Sets the legend column count.
AnnotationPosition
Position for grid annotations.
void setUrl(const QUrl &url)
Sets the url for content to display in the item when the item is using the QgsLayoutItemHtml::Url mod...
void setBackgroundEnabled(bool drawBackground)
Sets whether this item has a background drawn under it or not.
Q_DECL_DEPRECATED void setFont(const QFont &font)
Sets the font used for drawing text in the scalebar.
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:66
Number of pages in composition.
void setAtlasMargin(double margin)
Sets the margin size (percentage) used when the map is in atlas mode.
void setFontColor(const QColor &color)
Sets the label font color.
bool setFilterExpression(const QString &expression, QString &errorString)
Sets the expression used for filtering features in the coverage layer.
void readXml(const QDomElement &elem, const QDomDocument &doc)
Reads the component&#39;s style definition from an XML element.
void setFollowVisibilityPreset(bool follow)
Sets whether the map should follow a map theme.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:732
void setAnnotationPrecision(const int precision)
Sets the coordinate precision for grid annotations.
Unknown distance unit.
Definition: qgsunittypes.h:77
MarkerMode
The MarkerMode enum is the old QGIS 2.x arrow marker mode.
QgsLayoutTableColumns mColumns
Columns to show in table.
static QList< QgsLayoutObject * > addItemsFromCompositionXml(QgsPrintLayout *layout, const QDomElement &parentElement, QPointF *position=nullptr, bool pasteInPlace=false)
addItemsFromCompositionXml parse a QGIS 2.x composition XML in the parentElement, converts the 2...
double length() const
Returns the length of the measurement.
void setMapRotation(double rotation)
Sets the rotation for the map - this does not affect the layout item shape, only the way the map is d...
void setLinkedMap(QgsLayoutItemMap *map)
Sets the map to associate with the legend.
bool readXml(const QDomElement &styleElem)
Reads the style&#39;s properties from XML.
void setSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used to draw the shape.
NorthMode
Method for syncing rotation to a map&#39;s North direction.
Dummy property with no effect on item.
void setDrawAnnotations(bool draw)
Sets whether annotations are drawn within the map.
void setCrossLength(const double length)
Sets the length (in layout units) of the cross segments drawn for the grid.
Property requires a string value.
Definition: qgsproperty.h:91
void setAnnotationFormat(const AnnotationFormat format)
Sets the format for drawing grid annotations.
Qt::PenJoinStyle frameJoinStyle() const
Returns the join style used for drawing the item&#39;s frame.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
void setUnits(QgsUnitTypes::DistanceUnit units)
Sets the distance units used by the scalebar.
DataDefinedProperty
Composition data defined properties for different item types.
void setFont(const QFont &font)
Sets the label&#39;s current font.
static QgsLayerTree * readXml(QDomElement &element, const QgsReadWriteContext &context)
Load the layer tree from an XML element.
void updateBoundingRect()
Updates the bounding rect of this item. Call this function before doing any changes related to annota...
void setEnabled(bool enabled)
Sets whether the atlas is enabled.
virtual void attemptMove(const QgsLayoutPoint &point, bool useReferencePoint=true, bool includesFrame=false, int page=-1)
Attempts to move the item to a specified point.
ResizeMode
Controls how pictures are scaled within the item&#39;s frame.
void setReferencePoint(ReferencePoint point)
Sets the reference point for positioning of the layout item.
virtual QString uuid() const
Returns the item identification string.
This class represents a coordinate reference system (CRS).
void addLayoutItem(QgsLayoutItem *item)
Adds an item to the layout.
Definition: qgslayout.cpp:539
void refreshFrame(bool updateItem=true)
Refresh item&#39;s frame, considering data defined colors and frame size.
static QgsLayoutItemPage * create(QgsLayout *layout)
Returns a new page item for the specified layout.
virtual void setFrameEnabled(bool drawFrame)
Sets whether this item has a frame drawn around it or not.
void setMaxBreakDistance(double distance)
Sets the maximum distance allowed when calculating where to place page breaks in the html...
QgsProject * project() const
The project associated with the layout.
Definition: qgslayout.cpp:131
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
void setRasterStrokeWidth(double width)
Sets the stroke width for the stroke drawn around raster symbol items.
A layout item subclass for scale bars.
A base class for objects which belong to a layout.
void setNumberOfSegmentsLeft(int segments)
Sets the number of segments included in the left part of the scalebar.
void setBackgroundColor(const QColor &color)
Sets the color used for background of table.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
void setWmsLegendHeight(double height)
Sets the WMS legend height.
void setWmsLegendWidth(double width)
Sets the WMS legend width.
void setAnnotationFrameDistance(const double distance)
Sets the distance between the map frame and annotations.
void setOffsetY(double offset)
Sets the offset for grid lines in the y-direction.
void setIntervalX(double interval)
Sets the interval between grid lines in the x-direction.
void setPageSize(const QgsLayoutSize &size)
Sets the size of the page.
GridStyle
Grid drawing style.
static QString svgSymbolNameToPath(const QString &name, const QgsPathResolver &pathResolver)
Determines an SVG symbol&#39;s path from its name.
Print layout, a QgsLayout subclass for static or atlas-based layouts.
A layout item subclass for map legends.
virtual void addFrame(QgsLayoutFrame *frame, bool recalcFrameSizes=true)
Adds a frame to the multiframe.
void setSortFeatures(bool enabled)
Sets whether features should be sorted in the atlas.
Page number for item placement.
void setSymbolHeight(double height)
Sets the legend symbol height.
Symbol label (excluding icon)
Resolves relative paths into absolute paths and vice versa.
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
Definition: qgslayoutsize.h:40
void setEmptyTableBehavior(EmptyTableMode mode)
Sets the behavior mode for empty tables with no content rows.
void setBoxSpace(double space)
Sets the legend box space.
void setShowGrid(bool showGrid)
Sets whether grid lines should be drawn in the table.
void setPageNameExpression(const QString &expression)
Sets the expression (or field name) used for calculating the page name.
double height() const
Returns the height of the size.
Definition: qgslayoutsize.h:90
QgsLayoutItemGroup * parentGroup() const
Returns the item&#39;s parent group, if the item is part of a QgsLayoutItemGroup group.
Base class for frame items, which form a layout multiframe item.
void setUnitsPerSegment(double units)
Sets the number of scalebar units per segment.
void setEnabled(bool enabled) override
Controls whether the item will be drawn.
A layout multiframe subclass for HTML content.
void setHidePageIfEmpty(bool hidePageIfEmpty)
Sets whether the page should be hidden (ie, not included in layout exports) if this frame is empty...
void setTitleAlignment(Qt::AlignmentFlag alignment)
Sets the alignment of the legend title.
bool sortFeatures() const
Returns true if features should be sorted in the atlas.
void setGridColor(const QColor &color)
Sets the color used for grid lines in the table.
void setText(const QString &text)
Sets the label&#39;s preset text.
void setItemOpacity(double opacity)
Sets the item&#39;s opacity.
void setShowEmptyRows(bool showEmpty)
Sets whether empty rows should be drawn.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
Legend group title.
void setCornerRadius(QgsLayoutMeasurement radius)
Sets the corner radius for rounded rectangle corners.
static QColor decodeColor(const QString &str)
Item representing the paper in a layout.
void setColor(const QColor &color)
Sets the color for the symbol.
Definition: qgssymbol.cpp:481
void setLabelBarSpace(double space)
Sets the spacing (in millimeters) between labels and the scalebar.