QGIS API Documentation  3.9.0-Master (224899f119)
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  if ( composerElement.elementsByTagName( QStringLiteral( "symbol" ) ).size() )
143  {
144  QDomElement symbolElement = composerElement.elementsByTagName( QStringLiteral( "symbol" ) ).at( 0 ).toElement();
145  QgsReadWriteContext context;
146  if ( project )
147  context.setPathResolver( project->pathResolver() );
148  std::unique_ptr< QgsFillSymbol > symbol( QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElement, context ) );
149  if ( symbol )
150  layout->pageCollection()->setPageStyleSymbol( symbol.get() );
151  }
152 
153  QString name = composerElement.attribute( QStringLiteral( "name" ) );
154  // Try title
155  if ( name.isEmpty() )
156  name = composerElement.attribute( QStringLiteral( "title" ) );
157  // Try title on parent element
158  if ( name.isEmpty() )
159  name = parentElement.attribute( QStringLiteral( "title" ) );
160  layout->setName( name );
161  QgsLayoutSize pageSize( paperWidth, paperHeight );
162  for ( int j = 0; j < pages; j++ )
163  {
164  QgsLayoutItemPage *page = QgsLayoutItemPage::create( layout.get() );
165  page->setPageSize( pageSize );
166  layout->pageCollection()->addPage( page );
167  //custom snap lines
168  QDomNodeList snapLineNodes = composerElement.elementsByTagName( QStringLiteral( "SnapLine" ) );
169  for ( int i = 0; i < snapLineNodes.size(); ++i )
170  {
171  QDomElement snapLineElem = snapLineNodes.at( i ).toElement();
172  double x1 = snapLineElem.attribute( QStringLiteral( "x1" ) ).toDouble();
173  double y1 = snapLineElem.attribute( QStringLiteral( "y1" ) ).toDouble();
174  double x2 = snapLineElem.attribute( QStringLiteral( "x2" ) ).toDouble();
175  // Not necessary: double y2 = snapLineElem.attribute( QStringLiteral( "y2" ) ).toDouble();
176  Qt::Orientation orientation( x1 == x2 ? Qt::Orientation::Vertical : Qt::Orientation::Horizontal );
177  QgsLayoutMeasurement position( x1 == x2 ? x1 : y1 );
178  std::unique_ptr< QgsLayoutGuide > guide = qgis::make_unique< QgsLayoutGuide >( orientation, position, page );
179  layout->guides().addGuide( guide.release() );
180  }
181  }
182  addItemsFromCompositionXml( layout.get(), composerElement );
183 
184  // Read atlas from the parent element (Composer)
185  if ( parentElement.elementsByTagName( QStringLiteral( "Atlas" ) ).size() )
186  {
187  QDomElement atlasElement = parentElement.elementsByTagName( QStringLiteral( "Atlas" ) ).at( 0 ).toElement();
188  readAtlasXml( layout->atlas(), atlasElement, layout->project() );
189  }
190 
191  layout->undoStack()->blockCommands( false );
192  return layout;
193 }
194 
195 
196 void QgsCompositionConverter::adjustPos( QgsPrintLayout *layout, QgsLayoutItem *layoutItem, QPointF *position, bool &pasteInPlace, int zOrderOffset, QPointF &pasteShiftPos, int &pageNumber )
197 {
198  if ( position )
199  {
200  if ( pasteInPlace )
201  {
202  layoutItem->attemptMove( QgsLayoutPoint( *position ), true, false, pageNumber );
203  }
204  else
205  {
206  layoutItem->attemptMoveBy( pasteShiftPos.x(), pasteShiftPos.y() );
207  }
208  }
209 
210  layout->addLayoutItem( layoutItem );
211  layoutItem->setZValue( layoutItem->zValue() + zOrderOffset );
212 }
213 
214 void QgsCompositionConverter::restoreGeneralComposeItemProperties( QgsLayoutItem *layoutItem, const QDomElement &itemElem )
215 {
216  //restore general composer item properties
217  QDomNodeList composerItemList = itemElem.elementsByTagName( QStringLiteral( "ComposerItem" ) );
218  if ( !composerItemList.isEmpty() )
219  {
220  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
221 
222  //rotation
223  if ( !qgsDoubleNear( composerItemElem.attribute( QStringLiteral( "rotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) )
224  {
225  //check for old (pre 2.1) rotation attribute
226  layoutItem->setItemRotation( composerItemElem.attribute( QStringLiteral( "rotation" ), QStringLiteral( "0" ) ).toDouble(), false );
227  }
228  QgsCompositionConverter::readXml( layoutItem, composerItemElem );
229  }
230 }
231 
232 QRectF QgsCompositionConverter::itemPosition( QgsLayoutItem *layoutItem, const QDomElement &itemElem )
233 {
234  int page;
235  double x, y, pagex, pagey, width, height;
236  bool xOk, yOk, pageOk, pagexOk, pageyOk, widthOk, heightOk, positionModeOk;
237 
238  x = itemElem.attribute( QStringLiteral( "x" ) ).toDouble( &xOk );
239  y = itemElem.attribute( QStringLiteral( "y" ) ).toDouble( &yOk );
240  page = itemElem.attribute( QStringLiteral( "page" ) ).toInt( &pageOk );
241  pagex = itemElem.attribute( QStringLiteral( "pagex" ) ).toDouble( &pagexOk );
242  pagey = itemElem.attribute( QStringLiteral( "pagey" ) ).toDouble( &pageyOk );
243  width = itemElem.attribute( QStringLiteral( "width" ) ).toDouble( &widthOk );
244  height = itemElem.attribute( QStringLiteral( "height" ) ).toDouble( &heightOk );
245 
246 
247  layoutItem->mReferencePoint = static_cast< QgsLayoutItem::ReferencePoint >( itemElem.attribute( QStringLiteral( "positionMode" ) ).toInt( &positionModeOk ) );
248  if ( !positionModeOk )
249  {
250  layoutItem->setReferencePoint( QgsLayoutItem::ReferencePoint::UpperLeft );
251  }
252 
253  if ( pageOk && pagexOk && pageyOk )
254  {
255  xOk = true;
256  yOk = true;
257  x = pagex;
258  // position in the page (1-based)
259  if ( page <= layoutItem->layout()->pageCollection()->pageCount() )
260  {
261  QgsLayoutItemPage *pageObject = layoutItem->layout()->pageCollection()->pages().at( page - 1 );
262  y = ( page - 1 )
263  * ( pageObject->sizeWithUnits().height()
264  + layoutItem->layout()->pageCollection()->spaceBetweenPages() )
265  + pagey;
266  }
267  else
268  {
269  y = pagey;
270  }
271  }
272  return QRectF( x, y, width, height );
273 }
274 
275 QPointF QgsCompositionConverter::minPointFromXml( const QDomElement &elem )
276 {
277  double minX = std::numeric_limits<double>::max();
278  double minY = std::numeric_limits<double>::max();
279  QDomNodeList composerItemList = elem.elementsByTagName( QStringLiteral( "ComposerItem" ) );
280  for ( int i = 0; i < composerItemList.size(); ++i )
281  {
282  QDomElement currentComposerItemElem = composerItemList.at( i ).toElement();
283  double x, y;
284  bool xOk, yOk;
285  x = currentComposerItemElem.attribute( QStringLiteral( "x" ) ).toDouble( &xOk );
286  y = currentComposerItemElem.attribute( QStringLiteral( "y" ) ).toDouble( &yOk );
287  if ( !xOk || !yOk )
288  {
289  continue;
290  }
291  minX = std::min( minX, x );
292  minY = std::min( minY, y );
293  }
294  if ( minX < std::numeric_limits<double>::max() )
295  {
296  return QPointF( minX, minY );
297  }
298  else
299  {
300  return QPointF( 0, 0 );
301  }
302 }
303 
304 QList<QgsLayoutObject *> QgsCompositionConverter::addItemsFromCompositionXml( QgsPrintLayout *layout, const QDomElement &parentElement, QPointF *position, bool pasteInPlace )
305 {
306 
307  initPropertyDefinitions();
308 
309  QList< QgsLayoutObject * > newItems;
310 
311  //if we are adding items to a layout which already contains items, we need to make sure
312  //these items are placed at the top of the layout and that zValues are not duplicated
313  //so, calculate an offset which needs to be added to the zValue of created items
314  int zOrderOffset = layout->mItemsModel->zOrderListSize();
315 
316  QPointF pasteShiftPos;
317  int pageNumber = -1;
318  if ( position )
319  {
320  //If we are placing items relative to a certain point, then calculate how much we need
321  //to shift the items by so that they are placed at this point
322  //First, calculate the minimum position from the xml
323  QPointF minItemPos = minPointFromXml( parentElement );
324  //next, calculate how much each item needs to be shifted from its original position
325  //so that it's placed at the correct relative position
326  pasteShiftPos = *position - minItemPos;
327  if ( pasteInPlace )
328  {
329  pageNumber = layout->mPageCollection->pageNumberForPoint( *position );
330  }
331  }
332 
333  QgsStringMap mapIdUiidMap;
334 
335  // Map (this needs to come first to build the uuid <-> ID map for map composer items
336  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerMap" ) ).size(); i++ )
337  {
338  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerMap" ) ).at( i ) );
339  QgsLayoutItemMap *layoutItem = new QgsLayoutItemMap( layout );
340  readMapXml( layoutItem, itemNode.toElement(), layout->project(), mapIdUiidMap );
341  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
342  newItems << layoutItem ;
343  }
344 
345  // Label
346  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerLabel" ) ).size(); i++ )
347  {
348  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerLabel" ) ).at( i ) );
349  QgsLayoutItemLabel *layoutItem = new QgsLayoutItemLabel( layout );
350  readLabelXml( layoutItem, itemNode.toElement(), layout->project() );
351  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
352  newItems << layoutItem ;
353  }
354 
355  // Shape
356  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerShape" ) ).size(); i++ )
357  {
358  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerShape" ) ).at( i ) );
359  QgsLayoutItemShape *layoutItem = new QgsLayoutItemShape( layout );
360  readShapeXml( layoutItem, itemNode.toElement(), layout->project() );
361  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
362  newItems << layoutItem ;
363  }
364 
365  // Picture
366  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerPicture" ) ).size(); i++ )
367  {
368  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerPicture" ) ).at( i ) );
369  QgsLayoutItemPicture *layoutItem = new QgsLayoutItemPicture( layout );
370  readPictureXml( layoutItem, itemNode.toElement(), layout->project(), mapIdUiidMap );
371  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
372  newItems << layoutItem ;
373  }
374 
375  // Polygon
376  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerPolygon" ) ).size(); i++ )
377  {
378  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerPolygon" ) ).at( i ) );
379  QgsLayoutItemPolygon *layoutItem = new QgsLayoutItemPolygon( layout );
380  readPolyXml<QgsLayoutItemPolygon, QgsFillSymbol>( layoutItem, itemNode.toElement(), layout->project() );
381  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
382  newItems << layoutItem ;
383  }
384 
385  // Polyline
386  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerPolyline" ) ).size(); i++ )
387  {
388  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerPolyline" ) ).at( i ) );
389  QgsLayoutItemPolyline *layoutItem = new QgsLayoutItemPolyline( layout );
390  readPolyXml<QgsLayoutItemPolyline, QgsLineSymbol>( layoutItem, itemNode.toElement(), layout->project() );
391  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
392  newItems << layoutItem ;
393  }
394 
395  // Arrow
396  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerArrow" ) ).size(); i++ )
397  {
398  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerArrow" ) ).at( i ) );
399  QgsLayoutItemPolyline *layoutItem = new QgsLayoutItemPolyline( layout );
400  readArrowXml( layoutItem, itemNode.toElement(), layout->project() );
401  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
402  newItems << layoutItem ;
403  }
404 
405  // Scalebar
406  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerScaleBar" ) ).size(); i++ )
407  {
408  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerScaleBar" ) ).at( i ) );
409  QgsLayoutItemScaleBar *layoutItem = new QgsLayoutItemScaleBar( layout );
410  readScaleBarXml( layoutItem, itemNode.toElement(), layout->project(), mapIdUiidMap );
411  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
412  newItems << layoutItem ;
413  }
414 
415  // Legend
416  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerLegend" ) ).size(); i++ )
417  {
418  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerLegend" ) ).at( i ) );
419  QgsLayoutItemLegend *layoutItem = new QgsLayoutItemLegend( layout );
420  readLegendXml( layoutItem, itemNode.toElement(), layout->project(), mapIdUiidMap );
421  adjustPos( layout, layoutItem, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
422  newItems << layoutItem ;
423  }
424 
425  // Html
426  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerHtml" ) ).size(); i++ )
427  {
428  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerHtml" ) ).at( i ) );
429  QgsLayoutItemHtml *layoutItem = new QgsLayoutItemHtml( layout );
430  readHtmlXml( layoutItem, itemNode.toElement(), layout->project() );
431  // Adjust position for frames
432  const QList<QgsLayoutFrame *> framesList( layoutItem->frames() );
433  for ( const auto &frame : framesList )
434  {
435  adjustPos( layout, frame, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
436  }
437  newItems << layoutItem ;
438  }
439 
440  // Attribute Table
441  for ( int i = 0; i < parentElement.elementsByTagName( QStringLiteral( "ComposerAttributeTableV2" ) ).size(); i++ )
442  {
443  QDomNode itemNode( parentElement.elementsByTagName( QStringLiteral( "ComposerAttributeTableV2" ) ).at( i ) );
444  QgsLayoutItemAttributeTable *layoutItem = new QgsLayoutItemAttributeTable( layout );
445  readTableXml( layoutItem, itemNode.toElement(), layout->project() );
446  // Adjust position for frames
447  const QList<QgsLayoutFrame *> framesList( layoutItem->frames() );
448  for ( const auto &frame : framesList )
449  {
450  adjustPos( layout, frame, position, pasteInPlace, zOrderOffset, pasteShiftPos, pageNumber );
451  }
452  newItems << layoutItem ;
453  }
454 
455  return newItems;
456 }
457 
458 bool QgsCompositionConverter::isCompositionTemplate( const QDomDocument &document )
459 {
460  return document.elementsByTagName( QStringLiteral( "Composition" ) ).count() > 0;
461 }
462 
463 QDomDocument QgsCompositionConverter::convertCompositionTemplate( const QDomDocument &document, QgsProject *project )
464 {
465  QDomDocument doc;
466  QgsReadWriteContext context;
467  if ( project )
468  context.setPathResolver( project->pathResolver() );
469  if ( document.elementsByTagName( QStringLiteral( "Composition" ) ).count( ) > 0 )
470  {
471  QDomElement composerElem = document.elementsByTagName( QStringLiteral( "Composition" ) ).at( 0 ).toElement( );
472 
473  std::unique_ptr<QgsLayout> layout = createLayoutFromCompositionXml( composerElem,
474  project );
475  QDomElement elem = layout->writeXml( doc, context );
476  doc.appendChild( elem );
477  }
478  return doc;
479 }
480 
481 bool QgsCompositionConverter::readLabelXml( QgsLayoutItemLabel *layoutItem, const QDomElement &itemElem, const QgsProject *project )
482 {
483  Q_UNUSED( project )
484  if ( itemElem.isNull() )
485  {
486  return false;
487  }
488 
489  restoreGeneralComposeItemProperties( layoutItem, itemElem );
490 
491  //text
492  layoutItem->setText( itemElem.attribute( QStringLiteral( "labelText" ) ) );
493 
494  //html state
495  layoutItem->setMode( itemElem.attribute( QStringLiteral( "htmlState" ) ).toInt() == Qt::Checked ? QgsLayoutItemLabel::Mode::ModeHtml : QgsLayoutItemLabel::Mode::ModeFont );
496 
497  //margin
498  bool marginXOk = false;
499  bool marginYOk = false;
500  double marginX = itemElem.attribute( QStringLiteral( "marginX" ) ).toDouble( &marginXOk );
501  double marginY = itemElem.attribute( QStringLiteral( "marginY" ) ).toDouble( &marginYOk );
502  if ( !marginXOk || !marginYOk )
503  {
504  //upgrade old projects where margins where stored in a single attribute
505  double margin = itemElem.attribute( QStringLiteral( "margin" ), QStringLiteral( "1.0" ) ).toDouble();
506  marginX = margin;
507  marginY = margin;
508  }
509  layoutItem->setMarginX( marginX );
510  layoutItem->setMarginY( marginY );
511 
512  //Horizontal alignment
513  layoutItem->setHAlign( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "halign" ) ).toInt() ) );
514 
515  //Vertical alignment
516  layoutItem->setVAlign( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "valign" ) ).toInt() ) );
517 
518 
519  QFont font;
520  //font
521  QgsFontUtils::setFromXmlChildNode( font, itemElem, QStringLiteral( "LabelFont" ) );
522  layoutItem->setFont( font );
523 
524  //font color
525  QDomNodeList fontColorList = itemElem.elementsByTagName( QStringLiteral( "FontColor" ) );
526  if ( !fontColorList.isEmpty() )
527  {
528  QDomElement fontColorElem = fontColorList.at( 0 ).toElement();
529  int red = fontColorElem.attribute( QStringLiteral( "red" ), QStringLiteral( "0" ) ).toInt();
530  int green = fontColorElem.attribute( QStringLiteral( "green" ), QStringLiteral( "0" ) ).toInt();
531  int blue = fontColorElem.attribute( QStringLiteral( "blue" ), QStringLiteral( "0" ) ).toInt();
532  layoutItem->setFontColor( QColor( red, green, blue ) );
533  }
534  else
535  {
536  layoutItem->setFontColor( QColor( 0, 0, 0 ) );
537  }
538 
539  return true;
540 }
541 
542 bool QgsCompositionConverter::readShapeXml( QgsLayoutItemShape *layoutItem, const QDomElement &itemElem, const QgsProject *project )
543 {
544  Q_UNUSED( project )
545  layoutItem->setShapeType( static_cast<QgsLayoutItemShape::Shape>( itemElem.attribute( QStringLiteral( "shapeType" ), QStringLiteral( "0" ) ).toInt() ) );
546  layoutItem->setCornerRadius( QgsLayoutMeasurement( itemElem.attribute( QStringLiteral( "cornerRadius" ), QStringLiteral( "0" ) ).toDouble() ) );
547 
548  restoreGeneralComposeItemProperties( layoutItem, itemElem );
549 
550  QgsReadWriteContext context;
551  if ( project )
552  context.setPathResolver( project->pathResolver() );
553 
554  if ( itemElem.elementsByTagName( QStringLiteral( "symbol" ) ).size() )
555  {
556  QDomElement symbolElement = itemElem.elementsByTagName( QStringLiteral( "symbol" ) ).at( 0 ).toElement();
557  QgsFillSymbol *shapeStyleSymbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElement, context );
558  if ( shapeStyleSymbol )
559  layoutItem->setSymbol( shapeStyleSymbol );
560  }
561  else
562  {
563  //upgrade project file from 2.0 to use symbol styling
564  QgsStringMap properties;
565  properties.insert( QStringLiteral( "color" ), QgsSymbolLayerUtils::encodeColor( layoutItem->brush().color() ) );
566  if ( layoutItem->hasBackground() )
567  {
568  properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
569  }
570  else
571  {
572  properties.insert( QStringLiteral( "style" ), QStringLiteral( "no" ) );
573  }
574  if ( layoutItem->frameEnabled() )
575  {
576  properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "solid" ) );
577  }
578  else
579  {
580  properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "no" ) );
581  }
582  properties.insert( QStringLiteral( "color_border" ), QgsSymbolLayerUtils::encodeColor( layoutItem->pen().color() ) );
583  properties.insert( QStringLiteral( "width_border" ), QString::number( layoutItem->pen().widthF() ) );
584 
585  //for pre 2.0 projects, shape color and outline were specified in a different element...
586  QDomNodeList outlineColorList = itemElem.elementsByTagName( QStringLiteral( "OutlineColor" ) );
587  if ( !outlineColorList.isEmpty() )
588  {
589  QDomElement frameColorElem = outlineColorList.at( 0 ).toElement();
590  bool redOk, greenOk, blueOk, alphaOk, widthOk;
591  int penRed, penGreen, penBlue, penAlpha;
592  double penWidth;
593 
594  penWidth = itemElem.attribute( QStringLiteral( "outlineWidth" ) ).toDouble( &widthOk );
595  penRed = frameColorElem.attribute( QStringLiteral( "red" ) ).toInt( &redOk );
596  penGreen = frameColorElem.attribute( QStringLiteral( "green" ) ).toInt( &greenOk );
597  penBlue = frameColorElem.attribute( QStringLiteral( "blue" ) ).toInt( &blueOk );
598  penAlpha = frameColorElem.attribute( QStringLiteral( "alpha" ) ).toInt( &alphaOk );
599 
600  if ( redOk && greenOk && blueOk && alphaOk && widthOk )
601  {
602  properties.insert( QStringLiteral( "color_border" ), QgsSymbolLayerUtils::encodeColor( QColor( penRed, penGreen, penBlue, penAlpha ) ) );
603  properties.insert( QStringLiteral( "width_border" ), QString::number( penWidth ) );
604  }
605  }
606  QDomNodeList fillColorList = itemElem.elementsByTagName( QStringLiteral( "FillColor" ) );
607  if ( !fillColorList.isEmpty() )
608  {
609  QDomElement fillColorElem = fillColorList.at( 0 ).toElement();
610  bool redOk, greenOk, blueOk, alphaOk;
611  int fillRed, fillGreen, fillBlue, fillAlpha;
612 
613  fillRed = fillColorElem.attribute( QStringLiteral( "red" ) ).toInt( &redOk );
614  fillGreen = fillColorElem.attribute( QStringLiteral( "green" ) ).toInt( &greenOk );
615  fillBlue = fillColorElem.attribute( QStringLiteral( "blue" ) ).toInt( &blueOk );
616  fillAlpha = fillColorElem.attribute( QStringLiteral( "alpha" ) ).toInt( &alphaOk );
617 
618  if ( redOk && greenOk && blueOk && alphaOk )
619  {
620  properties.insert( QStringLiteral( "color" ), QgsSymbolLayerUtils::encodeColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) ) );
621  properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
622  }
623  }
624  if ( itemElem.hasAttribute( QStringLiteral( "transparentFill" ) ) )
625  {
626  //old style (pre 2.0) of specifying that shapes had no fill
627  bool hasOldTransparentFill = itemElem.attribute( QStringLiteral( "transparentFill" ), QStringLiteral( "0" ) ).toInt();
628  if ( hasOldTransparentFill )
629  {
630  properties.insert( QStringLiteral( "style" ), QStringLiteral( "no" ) );
631  }
632  }
633 
634  layoutItem->setSymbol( QgsFillSymbol::createSimple( properties ) );
635  }
636  // Disable frame for shapes
637  layoutItem->setFrameEnabled( false );
638  layoutItem->setBackgroundEnabled( false );
639 
640  return true;
641 }
642 
643 bool QgsCompositionConverter::readPictureXml( QgsLayoutItemPicture *layoutItem, const QDomElement &itemElem, const QgsProject *project, const QgsStringMap &mapId2Uuid )
644 {
645  restoreGeneralComposeItemProperties( layoutItem, itemElem );
646 
647  layoutItem->mResizeMode = QgsLayoutItemPicture::ResizeMode( itemElem.attribute( QStringLiteral( "resizeMode" ), QStringLiteral( "0" ) ).toInt() );
648  //when loading from xml, default to anchor point of middle to match pre 2.4 behavior
649  bool positionModeOk = false;
650  layoutItem->mReferencePoint = static_cast< QgsLayoutItem::ReferencePoint >( itemElem.attribute( QStringLiteral( "positionMode" ) ).toInt( &positionModeOk ) );
651  if ( !positionModeOk )
652  {
653  layoutItem->mReferencePoint = QgsLayoutItem::ReferencePoint::UpperLeft;
654  }
655  bool anchorPointOk = false;
656 
657  layoutItem->setPictureAnchor( static_cast< QgsLayoutItem::ReferencePoint >( itemElem.attribute( QStringLiteral( "anchorPoint" ), QString::number( QgsLayoutItem::ReferencePoint::Middle ) ).toInt( &anchorPointOk ) ) );
658  if ( !anchorPointOk )
659  {
660  layoutItem->mPictureAnchor = QgsLayoutItem::ReferencePoint::UpperLeft;
661  }
662  layoutItem->mSvgFillColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "svgFillColor" ), QgsSymbolLayerUtils::encodeColor( QColor( 255, 255, 255 ) ) ) );
663  layoutItem->mSvgStrokeColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "svgBorderColor" ), QgsSymbolLayerUtils::encodeColor( QColor( 0, 0, 0 ) ) ) );
664  layoutItem->mSvgStrokeWidth = itemElem.attribute( QStringLiteral( "svgBorderWidth" ), QStringLiteral( "0.2" ) ).toDouble();
665 
666  QString imagePath = itemElem.attribute( QStringLiteral( "file" ) );
667  if ( project )
668  {
669  // convert from relative path to absolute. For SVG we also need to consider system SVG paths
670  QgsPathResolver pathResolver = project->pathResolver();
671  if ( imagePath.endsWith( QLatin1String( ".svg" ), Qt::CaseInsensitive ) )
672  imagePath = QgsSymbolLayerUtils::svgSymbolNameToPath( imagePath, pathResolver );
673  else
674  imagePath = pathResolver.readPath( imagePath );
675  }
676  layoutItem->setPicturePath( imagePath );
677  layoutItem->mPictureHeight = itemElem.attribute( QStringLiteral( "pictureHeight" ), QStringLiteral( "10" ) ).toDouble();
678  layoutItem->mPictureWidth = itemElem.attribute( QStringLiteral( "pictureWidth" ), QStringLiteral( "10" ) ).toDouble();
679 
680  //picture rotation
681  if ( !qgsDoubleNear( itemElem.attribute( QStringLiteral( "pictureRotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) )
682  {
683  layoutItem->mPictureRotation = itemElem.attribute( QStringLiteral( "pictureRotation" ), QStringLiteral( "0" ) ).toDouble();
684  }
685 
686  //rotation map
687  layoutItem->mNorthMode = static_cast< QgsLayoutItemPicture::NorthMode >( itemElem.attribute( QStringLiteral( "northMode" ), QStringLiteral( "0" ) ).toInt() );
688  layoutItem->mNorthOffset = itemElem.attribute( QStringLiteral( "northOffset" ), QStringLiteral( "0" ) ).toDouble();
689 
690  QString rotationMapId = itemElem.attribute( QStringLiteral( "mapId" ), QStringLiteral( "-1" ) );
691  if ( rotationMapId != QStringLiteral( "-1" ) )
692  {
693  // Find uuid for map with given id
694  QgsLayoutItemMap *mapInstance = qobject_cast<QgsLayoutItemMap *>( layoutItem->layout()->itemByUuid( mapId2Uuid[ rotationMapId ] ) );
695  if ( mapInstance )
696  {
697  layoutItem->setLinkedMap( mapInstance );
698  }
699  }
700  return true;
701 }
702 
703 bool QgsCompositionConverter::readArrowXml( QgsLayoutItemPolyline *layoutItem, const QDomElement &itemElem, const QgsProject *project )
704 {
705  readPolyXml<QgsLayoutItemPolyline, QgsLineSymbol>( layoutItem, itemElem, project );
706  QPolygonF polygon;
707  QDomNodeList startPointList = itemElem.elementsByTagName( QStringLiteral( "StartPoint" ) );
708  if ( ! startPointList.isEmpty() )
709  {
710  QDomElement node = startPointList.at( 0 ).toElement();
711  polygon.append( QPointF( node.attribute( QStringLiteral( "x" ) ).toDouble( ), node.attribute( QStringLiteral( "y" ) ).toDouble() ) );
712  }
713  QDomNodeList stopPointList = itemElem.elementsByTagName( QStringLiteral( "StopPoint" ) );
714  if ( ! stopPointList.isEmpty() )
715  {
716  QDomElement node = stopPointList.at( 0 ).toElement();
717  polygon.append( QPointF( node.attribute( QStringLiteral( "x" ) ).toDouble( ), node.attribute( QStringLiteral( "y" ) ).toDouble() ) );
718  }
719 
720  QgsCompositionConverter::MarkerMode markerMode = static_cast< QgsCompositionConverter::MarkerMode>( itemElem.attribute( QStringLiteral( "markerMode" ), QStringLiteral( "0" ) ).toInt( ) );
721 
722  if ( markerMode == QgsCompositionConverter::MarkerMode::DefaultMarker )
723  {
724  layoutItem->setEndMarker( QgsLayoutItemPolyline::MarkerMode::ArrowHead );
725  layoutItem->setStartMarker( QgsLayoutItemPolyline::MarkerMode::NoMarker );
726  layoutItem->setArrowHeadFillColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "arrowHeadFillColor" ), QgsSymbolLayerUtils::encodeColor( QColor( 255, 255, 255 ) ) ) ) );
727  layoutItem->setArrowHeadStrokeColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "arrowHeadOutlineColor" ), QgsSymbolLayerUtils::encodeColor( QColor( 255, 255, 255 ) ) ) ) );
728  layoutItem->setArrowHeadStrokeWidth( itemElem.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "1.0" ) ).toDouble( ) );
729  layoutItem->setArrowHeadWidth( itemElem.attribute( QStringLiteral( "arrowHeadWidth" ), QStringLiteral( "1.0" ) ).toDouble( ) );
730  }
731  else if ( markerMode == QgsCompositionConverter::MarkerMode::SVGMarker )
732  {
733  QString endMarkerFile = itemElem.attribute( QStringLiteral( "endMarkerFile" ) );
734  QString startMarkerFile = itemElem.attribute( QStringLiteral( "endMarkerFile" ) );
735 
736  // Fix the paths
737  if ( project )
738  {
739  // convert from relative path to absolute. For SVG we also need to consider system SVG paths
740  QgsPathResolver pathResolver = project->pathResolver();
741  if ( !endMarkerFile.isEmpty() )
742  {
743  if ( endMarkerFile.endsWith( QLatin1String( ".svg" ), Qt::CaseInsensitive ) )
744  endMarkerFile = QgsSymbolLayerUtils::svgSymbolNameToPath( endMarkerFile, pathResolver );
745  else
746  endMarkerFile = pathResolver.readPath( endMarkerFile );
747  }
748  if ( !startMarkerFile.isEmpty() )
749  {
750  if ( startMarkerFile.endsWith( QLatin1String( ".svg" ), Qt::CaseInsensitive ) )
751  startMarkerFile = QgsSymbolLayerUtils::svgSymbolNameToPath( startMarkerFile, pathResolver );
752  else
753  startMarkerFile = pathResolver.readPath( startMarkerFile );
754  }
755  }
756  if ( !endMarkerFile.isEmpty() )
757  {
758  layoutItem->setEndMarker( QgsLayoutItemPolyline::MarkerMode::SvgMarker );
759  layoutItem->setEndSvgMarkerPath( endMarkerFile );
760  }
761  if ( !startMarkerFile.isEmpty() )
762  {
763  layoutItem->setStartMarker( QgsLayoutItemPolyline::MarkerMode::SvgMarker );
764  layoutItem->setStartSvgMarkerPath( startMarkerFile );
765  }
766  }
767  else // NoMarker
768  {
769  layoutItem->setEndMarker( QgsLayoutItemPolyline::MarkerMode::NoMarker );
770  layoutItem->setStartMarker( QgsLayoutItemPolyline::MarkerMode::NoMarker );
771  }
772  // Calculate the margin
773  double margin = polygon.boundingRect().left() - layoutItem->pos().x();
774  polygon.translate( - polygon.boundingRect().left() + margin, - polygon.boundingRect().top() + margin );
775  layoutItem->setNodes( polygon );
776 
777  return true;
778 }
779 
780 bool QgsCompositionConverter::readMapXml( QgsLayoutItemMap *layoutItem, const QDomElement &itemElem, const QgsProject *project, QgsStringMap &mapId2Uuid )
781 {
782  restoreGeneralComposeItemProperties( layoutItem, itemElem );
783 
784  mapId2Uuid[ itemElem.attribute( QStringLiteral( "id" ) ) ] = layoutItem->uuid();
785 
786  // TODO: Unused but all the layouts readXML require it (I'd suggest to remove it from the API)
787  QDomDocument doc;
788 
789  QgsReadWriteContext context;
790 
791  if ( project )
792  context.setPathResolver( project->pathResolver() );
793 
794  //extent
795  QDomNodeList extentNodeList = itemElem.elementsByTagName( QStringLiteral( "Extent" ) );
796  if ( !extentNodeList.isEmpty() )
797  {
798  QDomElement extentElem = extentNodeList.at( 0 ).toElement();
799  double xmin, xmax, ymin, ymax;
800  xmin = extentElem.attribute( QStringLiteral( "xmin" ) ).toDouble();
801  xmax = extentElem.attribute( QStringLiteral( "xmax" ) ).toDouble();
802  ymin = extentElem.attribute( QStringLiteral( "ymin" ) ).toDouble();
803  ymax = extentElem.attribute( QStringLiteral( "ymax" ) ).toDouble();
804  layoutItem->setExtent( QgsRectangle( xmin, ymin, xmax, ymax ) );
805  }
806 
807  QDomNodeList crsNodeList = itemElem.elementsByTagName( QStringLiteral( "crs" ) );
808  if ( !crsNodeList.isEmpty() )
809  {
810  QDomElement crsElem = crsNodeList.at( 0 ).toElement();
811  layoutItem->crs().readXml( crsElem );
812  }
813  else
814  {
815  layoutItem->setCrs( QgsCoordinateReferenceSystem() );
816  }
817 
818  //map rotation
819  if ( !qgsDoubleNear( itemElem.attribute( QStringLiteral( "mapRotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) )
820  {
821  layoutItem->setMapRotation( itemElem.attribute( QStringLiteral( "mapRotation" ), QStringLiteral( "0" ) ).toDouble() );
822  }
823 
824  // follow map theme
825  layoutItem->setFollowVisibilityPreset( itemElem.attribute( QStringLiteral( "followPreset" ) ).compare( QLatin1String( "true" ) ) == 0 );
826  layoutItem->setFollowVisibilityPresetName( itemElem.attribute( QStringLiteral( "followPresetName" ) ) );
827 
828  //mKeepLayerSet flag
829  QString keepLayerSetFlag = itemElem.attribute( QStringLiteral( "keepLayerSet" ) );
830  if ( keepLayerSetFlag.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
831  {
832  layoutItem->setKeepLayerSet( true );
833  }
834  else
835  {
836  layoutItem->setKeepLayerSet( false );
837  }
838 
839  QString drawCanvasItemsFlag = itemElem.attribute( QStringLiteral( "drawCanvasItems" ), QStringLiteral( "true" ) );
840  if ( drawCanvasItemsFlag.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
841  {
842  layoutItem->setDrawAnnotations( true );
843  }
844  else
845  {
846  layoutItem->setDrawAnnotations( false );
847  }
848 
849  layoutItem->mLayerStyleOverrides.clear();
850 
851  //mLayers
852  layoutItem->mLayers.clear();
853 
854  QDomNodeList layerSetNodeList = itemElem.elementsByTagName( QStringLiteral( "LayerSet" ) );
855  if ( !layerSetNodeList.isEmpty() )
856  {
857  QDomElement layerSetElem = layerSetNodeList.at( 0 ).toElement();
858  QDomNodeList layerIdNodeList = layerSetElem.elementsByTagName( QStringLiteral( "Layer" ) );
859  layoutItem->mLayers.reserve( layerIdNodeList.size() );
860  for ( int i = 0; i < layerIdNodeList.size(); ++i )
861  {
862  QDomElement layerElem = layerIdNodeList.at( i ).toElement();
863  QString layerId = layerElem.text();
864  QString layerName = layerElem.attribute( QStringLiteral( "name" ) );
865  QString layerSource = layerElem.attribute( QStringLiteral( "source" ) );
866  QString layerProvider = layerElem.attribute( QStringLiteral( "provider" ) );
867 
868  QgsMapLayerRef ref( layerId, layerName, layerSource, layerProvider );
869  ref.resolveWeakly( project );
870  layoutItem->mLayers << ref;
871  }
872  }
873 
874  // override styles
875  QDomNodeList layerStylesNodeList = itemElem.elementsByTagName( QStringLiteral( "LayerStyles" ) );
876  layoutItem->mKeepLayerStyles = !layerStylesNodeList.isEmpty();
877  if ( layoutItem->mKeepLayerStyles )
878  {
879  QDomElement layerStylesElem = layerStylesNodeList.at( 0 ).toElement();
880  QDomNodeList layerStyleNodeList = layerStylesElem.elementsByTagName( QStringLiteral( "LayerStyle" ) );
881  for ( int i = 0; i < layerStyleNodeList.size(); ++i )
882  {
883  const QDomElement &layerStyleElement = layerStyleNodeList.at( i ).toElement();
884  QString layerId = layerStyleElement.attribute( QStringLiteral( "layerid" ) );
885  QString layerName = layerStyleElement.attribute( QStringLiteral( "name" ) );
886  QString layerSource = layerStyleElement.attribute( QStringLiteral( "source" ) );
887  QString layerProvider = layerStyleElement.attribute( QStringLiteral( "provider" ) );
888  QgsMapLayerRef ref( layerId, layerName, layerSource, layerProvider );
889  ref.resolveWeakly( project );
890 
891  QgsMapLayerStyle style;
892  style.readXml( layerStyleElement );
893  layoutItem->mLayerStyleOverrides.insert( ref.layerId, style.xmlData() );
894  }
895  }
896 
897  layoutItem->mDrawing = false;
898  layoutItem->mNumCachedLayers = 0;
899  layoutItem->mCacheInvalidated = true;
900 
901  //overviews
902  //read overview stack
903  QDomNodeList mapOverviewNodeList = itemElem.elementsByTagName( QStringLiteral( "ComposerMapOverview" ) );
904  for ( int i = 0; i < mapOverviewNodeList.size(); ++i )
905  {
906  QDomElement mapOverviewElem = mapOverviewNodeList.at( i ).toElement();
907  std::unique_ptr<QgsLayoutItemMapOverview> mapOverview( new QgsLayoutItemMapOverview( mapOverviewElem.attribute( QStringLiteral( "name" ) ), layoutItem ) );
908  mapOverview->readXml( mapOverviewElem, doc, context );
909  QString frameMapId = mapOverviewElem.attribute( QStringLiteral( "frameMap" ), QStringLiteral( "-1" ) );
910  if ( frameMapId != QStringLiteral( "-1" ) && mapId2Uuid.contains( frameMapId ) )
911  {
912  QgsLayoutItemMap *mapInstance = qobject_cast<QgsLayoutItemMap *>( layoutItem->layout()->itemByUuid( mapId2Uuid[ frameMapId ] ) );
913  if ( mapInstance )
914  {
915  mapOverview->setLinkedMap( mapInstance );
916  }
917  layoutItem->mOverviewStack->addOverview( mapOverview.release() );
918  }
919  }
920 
921  //grids
922  layoutItem->mGridStack->readXml( itemElem, doc, context );
923 
924  //load grid / grid annotation in old xml format
925  //only do this if the grid stack didn't load any grids, otherwise this will
926  //be the dummy element created by QGIS >= 2.5 (refs #10905)
927  QDomNodeList gridNodeList = itemElem.elementsByTagName( QStringLiteral( "Grid" ) );
928  if ( layoutItem->mGridStack->size() == 0 && !gridNodeList.isEmpty() )
929  {
930  QDomElement gridElem = gridNodeList.at( 0 ).toElement();
931  QgsLayoutItemMapGrid *mapGrid = new QgsLayoutItemMapGrid( QObject::tr( "Grid %1" ).arg( 1 ), layoutItem );
932  mapGrid->setEnabled( gridElem.attribute( QStringLiteral( "show" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
933  mapGrid->setStyle( QgsLayoutItemMapGrid::GridStyle( gridElem.attribute( QStringLiteral( "gridStyle" ), QStringLiteral( "0" ) ).toInt() ) );
934  mapGrid->setIntervalX( gridElem.attribute( QStringLiteral( "intervalX" ), QStringLiteral( "0" ) ).toDouble() );
935  mapGrid->setIntervalY( gridElem.attribute( QStringLiteral( "intervalY" ), QStringLiteral( "0" ) ).toDouble() );
936  mapGrid->setOffsetX( gridElem.attribute( QStringLiteral( "offsetX" ), QStringLiteral( "0" ) ).toDouble() );
937  mapGrid->setOffsetY( gridElem.attribute( QStringLiteral( "offsetY" ), QStringLiteral( "0" ) ).toDouble() );
938  mapGrid->setCrossLength( gridElem.attribute( QStringLiteral( "crossLength" ), QStringLiteral( "3" ) ).toDouble() );
939  mapGrid->setFrameStyle( static_cast< QgsLayoutItemMapGrid::FrameStyle >( gridElem.attribute( QStringLiteral( "gridFrameStyle" ), QStringLiteral( "0" ) ).toInt() ) );
940  mapGrid->setFrameWidth( gridElem.attribute( QStringLiteral( "gridFrameWidth" ), QStringLiteral( "2.0" ) ).toDouble() );
941  mapGrid->setFramePenSize( gridElem.attribute( QStringLiteral( "gridFramePenThickness" ), QStringLiteral( "0.5" ) ).toDouble() );
942  mapGrid->setFramePenColor( QgsSymbolLayerUtils::decodeColor( gridElem.attribute( QStringLiteral( "framePenColor" ), QStringLiteral( "0,0,0" ) ) ) );
943  mapGrid->setFrameFillColor1( QgsSymbolLayerUtils::decodeColor( gridElem.attribute( QStringLiteral( "frameFillColor1" ), QStringLiteral( "255,255,255,255" ) ) ) );
944  mapGrid->setFrameFillColor2( QgsSymbolLayerUtils::decodeColor( gridElem.attribute( QStringLiteral( "frameFillColor2" ), QStringLiteral( "0,0,0,255" ) ) ) );
945  mapGrid->setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( itemElem.attribute( QStringLiteral( "gridBlendMode" ), QStringLiteral( "0" ) ).toUInt() ) ) );
946  QDomElement gridSymbolElem = gridElem.firstChildElement( QStringLiteral( "symbol" ) );
947  QgsLineSymbol *lineSymbol = nullptr;
948  if ( gridSymbolElem.isNull() )
949  {
950  //old project file, read penWidth /penColorRed, penColorGreen, penColorBlue
951  lineSymbol = QgsLineSymbol::createSimple( QgsStringMap() );
952  lineSymbol->setWidth( gridElem.attribute( QStringLiteral( "penWidth" ), QStringLiteral( "0" ) ).toDouble() );
953  lineSymbol->setColor( QColor( gridElem.attribute( QStringLiteral( "penColorRed" ), QStringLiteral( "0" ) ).toInt(),
954  gridElem.attribute( QStringLiteral( "penColorGreen" ), QStringLiteral( "0" ) ).toInt(),
955  gridElem.attribute( QStringLiteral( "penColorBlue" ), QStringLiteral( "0" ) ).toInt() ) );
956  }
957  else
958  {
959  lineSymbol = QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( gridSymbolElem, context );
960  }
961  mapGrid->setLineSymbol( lineSymbol );
962 
963  //annotation
964  QDomNodeList annotationNodeList = gridElem.elementsByTagName( QStringLiteral( "Annotation" ) );
965  if ( !annotationNodeList.isEmpty() )
966  {
967  QDomElement annotationElem = annotationNodeList.at( 0 ).toElement();
968  mapGrid->setAnnotationEnabled( annotationElem.attribute( QStringLiteral( "show" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
969  mapGrid->setAnnotationFormat( QgsLayoutItemMapGrid::AnnotationFormat( annotationElem.attribute( QStringLiteral( "format" ), QStringLiteral( "0" ) ).toInt() ) );
970  mapGrid->setAnnotationPosition( QgsLayoutItemMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "leftPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Left );
971  mapGrid->setAnnotationPosition( QgsLayoutItemMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "rightPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Right );
972  mapGrid->setAnnotationPosition( QgsLayoutItemMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "topPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Top );
973  mapGrid->setAnnotationPosition( QgsLayoutItemMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "bottomPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Bottom );
974  mapGrid->setAnnotationDirection( QgsLayoutItemMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "leftDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Left );
975  mapGrid->setAnnotationDirection( QgsLayoutItemMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "rightDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Right );
976  mapGrid->setAnnotationDirection( QgsLayoutItemMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "topDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Top );
977  mapGrid->setAnnotationDirection( QgsLayoutItemMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "bottomDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsLayoutItemMapGrid::Bottom );
978  mapGrid->setAnnotationFrameDistance( annotationElem.attribute( QStringLiteral( "frameDistance" ), QStringLiteral( "0" ) ).toDouble() );
979  QFont annotationFont;
980  annotationFont.fromString( annotationElem.attribute( QStringLiteral( "font" ), QString() ) );
981  mapGrid->setAnnotationFont( annotationFont );
982  mapGrid->setAnnotationFontColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
983 
984  mapGrid->setAnnotationPrecision( annotationElem.attribute( QStringLiteral( "precision" ), QStringLiteral( "3" ) ).toInt() );
985  }
986  layoutItem->mGridStack->addGrid( mapGrid );
987  }
988 
989  //atlas
990  QDomNodeList atlasNodeList = itemElem.elementsByTagName( QStringLiteral( "AtlasMap" ) );
991  if ( !atlasNodeList.isEmpty() )
992  {
993  QDomElement atlasElem = atlasNodeList.at( 0 ).toElement();
994  layoutItem->mAtlasDriven = ( atlasElem.attribute( QStringLiteral( "atlasDriven" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
995  if ( atlasElem.hasAttribute( QStringLiteral( "fixedScale" ) ) ) // deprecated XML
996  {
997  layoutItem->setAtlasScalingMode( atlasElem.attribute( QStringLiteral( "fixedScale" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) ? QgsLayoutItemMap::AtlasScalingMode::Fixed : QgsLayoutItemMap::AtlasScalingMode::Auto );
998  }
999  else if ( atlasElem.hasAttribute( QStringLiteral( "scalingMode" ) ) )
1000  {
1001  layoutItem->setAtlasScalingMode( static_cast<QgsLayoutItemMap::AtlasScalingMode>( atlasElem.attribute( QStringLiteral( "scalingMode" ) ).toInt() ) );
1002  }
1003  layoutItem->setAtlasMargin( atlasElem.attribute( QStringLiteral( "margin" ), QStringLiteral( "0.1" ) ).toDouble() );
1004  }
1005 
1006  layoutItem->updateBoundingRect();
1007 
1008  return true;
1009 }
1010 
1011 bool QgsCompositionConverter::readScaleBarXml( QgsLayoutItemScaleBar *layoutItem, const QDomElement &itemElem, const QgsProject *project, const QgsStringMap &mapId2Uuid )
1012 {
1013  Q_UNUSED( project )
1014  restoreGeneralComposeItemProperties( layoutItem, itemElem );
1015 
1016  layoutItem->setHeight( itemElem.attribute( QStringLiteral( "height" ), QStringLiteral( "5.0" ) ).toDouble() );
1017  layoutItem->setHeight( itemElem.attribute( QStringLiteral( "height" ), QStringLiteral( "5.0" ) ).toDouble() );
1018  layoutItem->setLabelBarSpace( itemElem.attribute( QStringLiteral( "labelBarSpace" ), QStringLiteral( "3.0" ) ).toDouble() );
1019  layoutItem->setBoxContentSpace( itemElem.attribute( QStringLiteral( "boxContentSpace" ), QStringLiteral( "1.0" ) ).toDouble() );
1020  layoutItem->setNumberOfSegments( itemElem.attribute( QStringLiteral( "numSegments" ), QStringLiteral( "2" ) ).toInt() );
1021  layoutItem->setNumberOfSegmentsLeft( itemElem.attribute( QStringLiteral( "numSegmentsLeft" ), QStringLiteral( "0" ) ).toInt() );
1022  layoutItem->setUnitsPerSegment( itemElem.attribute( QStringLiteral( "numUnitsPerSegment" ), QStringLiteral( "1.0" ) ).toDouble() );
1023  layoutItem->setSegmentSizeMode( static_cast<QgsScaleBarSettings::SegmentSizeMode>( itemElem.attribute( QStringLiteral( "segmentSizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
1024  layoutItem->setMinimumBarWidth( itemElem.attribute( QStringLiteral( "minBarWidth" ), QStringLiteral( "50" ) ).toDouble() );
1025  layoutItem->setMaximumBarWidth( itemElem.attribute( QStringLiteral( "maxBarWidth" ), QStringLiteral( "150" ) ).toDouble() );
1026  layoutItem->mSegmentMillimeters = itemElem.attribute( QStringLiteral( "segmentMillimeters" ), QStringLiteral( "0.0" ) ).toDouble();
1027  layoutItem->setMapUnitsPerScaleBarUnit( itemElem.attribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QStringLiteral( "1.0" ) ).toDouble() );
1028  layoutItem->setLineWidth( itemElem.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "0.3" ) ).toDouble() );
1029  layoutItem->setUnitLabel( itemElem.attribute( QStringLiteral( "unitLabel" ) ) );
1030  layoutItem->setLineJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( itemElem.attribute( QStringLiteral( "lineJoinStyle" ), QStringLiteral( "miter" ) ) ) );
1031  layoutItem->setLineCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( itemElem.attribute( QStringLiteral( "lineCapStyle" ), QStringLiteral( "square" ) ) ) );
1032  QFont f;
1033  if ( !QgsFontUtils::setFromXmlChildNode( f, itemElem, QStringLiteral( "scaleBarFont" ) ) )
1034  {
1035  f.fromString( itemElem.attribute( QStringLiteral( "font" ), QString() ) );
1036  }
1038  layoutItem->setFont( f );
1040 
1041  //colors
1042  //fill color
1043  QDomNodeList fillColorList = itemElem.elementsByTagName( QStringLiteral( "fillColor" ) );
1044  if ( !fillColorList.isEmpty() )
1045  {
1046  QDomElement fillColorElem = fillColorList.at( 0 ).toElement();
1047  bool redOk, greenOk, blueOk, alphaOk;
1048  int fillRed, fillGreen, fillBlue, fillAlpha;
1049 
1050  fillRed = fillColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1051  fillGreen = fillColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1052  fillBlue = fillColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1053  fillAlpha = fillColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1054 
1055  if ( redOk && greenOk && blueOk && alphaOk )
1056  {
1057  layoutItem->setFillColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
1058  }
1059  }
1060  else
1061  {
1062  layoutItem->setFillColor( QColor( itemElem.attribute( QStringLiteral( "brushColor" ), QStringLiteral( "#000000" ) ) ) );
1063  }
1064 
1065  //fill color 2
1066  QDomNodeList fillColor2List = itemElem.elementsByTagName( QStringLiteral( "fillColor2" ) );
1067  if ( !fillColor2List.isEmpty() )
1068  {
1069  QDomElement fillColor2Elem = fillColor2List.at( 0 ).toElement();
1070  bool redOk, greenOk, blueOk, alphaOk;
1071  int fillRed, fillGreen, fillBlue, fillAlpha;
1072 
1073  fillRed = fillColor2Elem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1074  fillGreen = fillColor2Elem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1075  fillBlue = fillColor2Elem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1076  fillAlpha = fillColor2Elem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1077 
1078  if ( redOk && greenOk && blueOk && alphaOk )
1079  {
1080  layoutItem->setFillColor2( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
1081  }
1082  }
1083  else
1084  {
1085  layoutItem->setFillColor2( QColor( itemElem.attribute( QStringLiteral( "brush2Color" ), QStringLiteral( "#ffffff" ) ) ) );
1086  }
1087 
1088  //stroke color
1089  QDomNodeList strokeColorList = itemElem.elementsByTagName( QStringLiteral( "strokeColor" ) );
1090  if ( !strokeColorList.isEmpty() )
1091  {
1092  QDomElement strokeColorElem = strokeColorList.at( 0 ).toElement();
1093  bool redOk, greenOk, blueOk, alphaOk;
1094  int strokeRed, strokeGreen, strokeBlue, strokeAlpha;
1095 
1096  strokeRed = strokeColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1097  strokeGreen = strokeColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1098  strokeBlue = strokeColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1099  strokeAlpha = strokeColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1100 
1101  if ( redOk && greenOk && blueOk && alphaOk )
1102  {
1103  layoutItem->setLineColor( QColor( strokeRed, strokeGreen, strokeBlue, strokeAlpha ) );
1104  QPen p = layoutItem->mSettings.pen();
1105  p.setColor( layoutItem->mSettings.lineColor() );
1106  layoutItem->setPen( p );
1107  }
1108  }
1109  else
1110  {
1111  layoutItem->setLineColor( QColor( itemElem.attribute( QStringLiteral( "penColor" ), QStringLiteral( "#000000" ) ) ) );
1112  QPen p = layoutItem->mSettings.pen();
1113  p.setColor( layoutItem->mSettings.lineColor() );
1114  layoutItem->setPen( p );
1115  }
1116 
1117  //font color
1118  QDomNodeList textColorList = itemElem.elementsByTagName( QStringLiteral( "textColor" ) );
1119  if ( !textColorList.isEmpty() )
1120  {
1121  QDomElement textColorElem = textColorList.at( 0 ).toElement();
1122  bool redOk, greenOk, blueOk, alphaOk;
1123  int textRed, textGreen, textBlue, textAlpha;
1124 
1125  textRed = textColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1126  textGreen = textColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1127  textBlue = textColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1128  textAlpha = textColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1129 
1130  if ( redOk && greenOk && blueOk && alphaOk )
1131  {
1133  layoutItem->setFontColor( QColor( textRed, textGreen, textBlue, textAlpha ) );
1135  }
1136  }
1137  else
1138  {
1139  QColor c;
1140  c.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
1142  layoutItem->setFontColor( c );
1144  }
1145 
1146  //style
1147  QString styleString = itemElem.attribute( QStringLiteral( "style" ), QString() );
1148  layoutItem->setStyle( QObject::tr( styleString.toLocal8Bit().data() ) );
1149 
1150  if ( itemElem.attribute( QStringLiteral( "unitType" ) ).isEmpty() )
1151  {
1153  switch ( itemElem.attribute( QStringLiteral( "units" ) ).toInt() )
1154  {
1155  case 0:
1157  break;
1158  case 1:
1160  break;
1161  case 2:
1163  break;
1164  case 3:
1166  break;
1167  }
1168  layoutItem->setUnits( u );
1169  }
1170  else
1171  {
1172  layoutItem->setUnits( QgsUnitTypes::decodeDistanceUnit( itemElem.attribute( QStringLiteral( "unitType" ) ) ) );
1173  }
1174  layoutItem->setAlignment( static_cast< QgsScaleBarSettings::Alignment >( itemElem.attribute( QStringLiteral( "alignment" ), QStringLiteral( "0" ) ).toInt() ) );
1175 
1176  //composer map: use uuid
1177  QString mapId = itemElem.attribute( QStringLiteral( "mapId" ), QStringLiteral( "-1" ) );
1178  if ( mapId != QStringLiteral( "-1" ) && mapId2Uuid.contains( mapId ) )
1179  {
1180  QgsLayoutItemMap *mapInstance = qobject_cast<QgsLayoutItemMap *>( layoutItem->layout()->itemByUuid( mapId2Uuid[ mapId ] ) );
1181  if ( mapInstance )
1182  {
1183  layoutItem->setLinkedMap( mapInstance );
1184  }
1185  }
1186 
1187  return true;
1188 }
1189 
1190 bool QgsCompositionConverter::readLegendXml( QgsLayoutItemLegend *layoutItem, const QDomElement &itemElem, const QgsProject *project, const QgsStringMap &mapId2Uuid )
1191 {
1192  restoreGeneralComposeItemProperties( layoutItem, itemElem );
1193 
1194  QgsPathResolver pathResolver;
1195  if ( project )
1196  pathResolver = project->pathResolver();
1197  QgsReadWriteContext context;
1198  context.setPathResolver( pathResolver );
1199  context.setProjectTranslator( const_cast<QgsProject *>( project ) );
1200 
1201  //composer map: use uuid
1202  QString mapId = itemElem.attribute( QStringLiteral( "map" ), QStringLiteral( "-1" ) );
1203  if ( mapId != QStringLiteral( "-1" ) && mapId2Uuid.contains( mapId ) )
1204  {
1205  QgsLayoutItemMap *mapInstance = qobject_cast<QgsLayoutItemMap *>( layoutItem->layout()->itemByUuid( mapId2Uuid[ mapId ] ) );
1206  if ( mapInstance )
1207  {
1208  layoutItem->setLinkedMap( mapInstance );
1209  }
1210  }
1211 
1212  //read general properties
1213  layoutItem->setTitle( itemElem.attribute( QStringLiteral( "title" ) ) );
1214  if ( !itemElem.attribute( QStringLiteral( "titleAlignment" ) ).isEmpty() )
1215  {
1216  layoutItem->setTitleAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "titleAlignment" ) ).toInt() ) );
1217  }
1218  int colCount = itemElem.attribute( QStringLiteral( "columnCount" ), QStringLiteral( "1" ) ).toInt();
1219  if ( colCount < 1 ) colCount = 1;
1220  layoutItem->setColumnCount( colCount );
1221  layoutItem->setSplitLayer( itemElem.attribute( QStringLiteral( "splitLayer" ), QStringLiteral( "0" ) ).toInt() == 1 );
1222  layoutItem->setEqualColumnWidth( itemElem.attribute( QStringLiteral( "equalColumnWidth" ), QStringLiteral( "0" ) ).toInt() == 1 );
1223 
1224  QDomNodeList stylesNodeList = itemElem.elementsByTagName( QStringLiteral( "styles" ) );
1225  if ( !stylesNodeList.isEmpty() )
1226  {
1227  QDomNode stylesNode = stylesNodeList.at( 0 );
1228  for ( int i = 0; i < stylesNode.childNodes().size(); i++ )
1229  {
1230  QDomElement styleElem = stylesNode.childNodes().at( i ).toElement();
1231  QgsLegendStyle style;
1232  style.readXml( styleElem, QDomDocument() );
1233  QString name = styleElem.attribute( QStringLiteral( "name" ) );
1235  if ( name == QLatin1String( "title" ) ) s = QgsLegendStyle::Title;
1236  else if ( name == QLatin1String( "group" ) ) s = QgsLegendStyle::Group;
1237  else if ( name == QLatin1String( "subgroup" ) ) s = QgsLegendStyle::Subgroup;
1238  else if ( name == QLatin1String( "symbol" ) ) s = QgsLegendStyle::Symbol;
1239  else if ( name == QLatin1String( "symbolLabel" ) ) s = QgsLegendStyle::SymbolLabel;
1240  else continue;
1241  layoutItem->setStyle( s, style );
1242  }
1243  }
1244 
1245  //font color
1246  QColor fontClr;
1247  fontClr.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
1248  layoutItem->setFontColor( fontClr );
1249 
1250  //spaces
1251  layoutItem->setBoxSpace( itemElem.attribute( QStringLiteral( "boxSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
1252  layoutItem->setColumnSpace( itemElem.attribute( QStringLiteral( "columnSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
1253 
1254  layoutItem->setSymbolWidth( itemElem.attribute( QStringLiteral( "symbolWidth" ), QStringLiteral( "7.0" ) ).toDouble() );
1255  layoutItem->setSymbolHeight( itemElem.attribute( QStringLiteral( "symbolHeight" ), QStringLiteral( "14.0" ) ).toDouble() );
1256  layoutItem->setWmsLegendWidth( itemElem.attribute( QStringLiteral( "wmsLegendWidth" ), QStringLiteral( "50" ) ).toDouble() );
1257  layoutItem->setWmsLegendHeight( itemElem.attribute( QStringLiteral( "wmsLegendHeight" ), QStringLiteral( "25" ) ).toDouble() );
1258  layoutItem->setLineSpacing( itemElem.attribute( QStringLiteral( "lineSpacing" ), QStringLiteral( "1.0" ) ).toDouble() );
1259 
1260  layoutItem->setDrawRasterStroke( itemElem.attribute( QStringLiteral( "rasterBorder" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
1261  layoutItem->setRasterStrokeColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "rasterBorderColor" ), QStringLiteral( "0,0,0" ) ) ) );
1262  layoutItem->setRasterStrokeWidth( itemElem.attribute( QStringLiteral( "rasterBorderWidth" ), QStringLiteral( "0" ) ).toDouble() );
1263 
1264  layoutItem->setWrapString( itemElem.attribute( QStringLiteral( "wrapChar" ) ) );
1265 
1266  layoutItem->mSizeToContents = itemElem.attribute( QStringLiteral( "resizeToContents" ), QStringLiteral( "1" ) ) != QLatin1String( "0" );
1267  layoutItem->mLegendFilterByMap = itemElem.attribute( QStringLiteral( "legendFilterByMap" ), QStringLiteral( "0" ) ).toInt();
1268  layoutItem->mFilterOutAtlas = itemElem.attribute( QStringLiteral( "legendFilterByAtlas" ), QStringLiteral( "0" ) ).toInt();
1269 
1270  // QGIS >= 2.6
1271  QDomElement layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree" ) );
1272  if ( layerTreeElem.isNull() )
1273  layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree-group" ) );
1274 
1275  if ( !layerTreeElem.isNull() )
1276  {
1277  QgsLayerTree *tree( QgsLayerTree::readXml( layerTreeElem, context ) );
1278  if ( project )
1279  tree->resolveReferences( project, true );
1280  layoutItem->setCustomLayerTree( tree );
1281  }
1282  else
1283  {
1284  layoutItem->setCustomLayerTree( nullptr );
1285  }
1286 
1287  return true;
1288 }
1289 
1290 bool QgsCompositionConverter::readAtlasXml( QgsLayoutAtlas *atlasItem, const QDomElement &itemElem, const QgsProject *project )
1291 {
1292  atlasItem->setEnabled( itemElem.attribute( QStringLiteral( "enabled" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1293 
1294  // look for stored layer name
1295  QString layerId = itemElem.attribute( QStringLiteral( "coverageLayer" ) );
1296  QString layerName = itemElem.attribute( QStringLiteral( "coverageLayerName" ) );
1297  QString layerSource = itemElem.attribute( QStringLiteral( "coverageLayerSource" ) );
1298  QString layerProvider = itemElem.attribute( QStringLiteral( "coverageLayerProvider" ) );
1299 
1300  QgsVectorLayerRef layerRef( layerId, layerName, layerSource, layerProvider );
1301  atlasItem->setCoverageLayer( layerRef.resolveWeakly( project ) );
1302 
1303  atlasItem->setPageNameExpression( itemElem.attribute( QStringLiteral( "pageNameExpression" ), QString() ) );
1304  QString errorString;
1305  atlasItem->setFilenameExpression( itemElem.attribute( QStringLiteral( "filenamePattern" ), QString() ), errorString );
1306  // note: no error reporting for errorString
1307  atlasItem->setSortFeatures( itemElem.attribute( QStringLiteral( "sortFeatures" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1308  if ( atlasItem->sortFeatures() )
1309  {
1310  atlasItem->setSortExpression( itemElem.attribute( QStringLiteral( "sortKey" ), QString() ) );
1311  atlasItem->setSortAscending( itemElem.attribute( QStringLiteral( "sortAscending" ), QStringLiteral( "true" ) ) == QLatin1String( "true" ) );
1312  }
1313  atlasItem->setFilterFeatures( itemElem.attribute( QStringLiteral( "filterFeatures" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1314  if ( atlasItem->filterFeatures( ) )
1315  {
1316  QString expErrorString;
1317  atlasItem->setFilterExpression( itemElem.attribute( QStringLiteral( "featureFilter" ), QString() ), expErrorString );
1318  // note: no error reporting for errorString
1319  }
1320 
1321  atlasItem->setHideCoverage( itemElem.attribute( QStringLiteral( "hideCoverage" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1322 
1323  return true;
1324 
1325 }
1326 
1327 bool QgsCompositionConverter::readHtmlXml( QgsLayoutItemHtml *layoutItem, const QDomElement &itemElem, const QgsProject *project )
1328 {
1329  Q_UNUSED( project )
1330  readOldComposerObjectXml( layoutItem, itemElem );
1331 
1332  //first create the frames
1333  layoutItem->setResizeMode( static_cast< QgsLayoutMultiFrame::ResizeMode >( itemElem.attribute( QStringLiteral( "resizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
1334  QDomNodeList frameList = itemElem.elementsByTagName( QStringLiteral( "ComposerFrame" ) );
1335  for ( int i = 0; i < frameList.size(); ++i )
1336  {
1337  QDomElement frameElem = frameList.at( i ).toElement();
1338  QgsLayoutFrame *newFrame = new QgsLayoutFrame( layoutItem->layout(), layoutItem );
1339  restoreGeneralComposeItemProperties( newFrame, frameElem );
1340  // Read frame XML
1341  double x = itemElem.attribute( QStringLiteral( "sectionX" ) ).toDouble();
1342  double y = itemElem.attribute( QStringLiteral( "sectionY" ) ).toDouble();
1343  double width = itemElem.attribute( QStringLiteral( "sectionWidth" ) ).toDouble();
1344  double height = itemElem.attribute( QStringLiteral( "sectionHeight" ) ).toDouble();
1345  newFrame->setContentSection( QRectF( x, y, width, height ) );
1346  newFrame->setHidePageIfEmpty( itemElem.attribute( QStringLiteral( "hidePageIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
1347  newFrame->setHideBackgroundIfEmpty( itemElem.attribute( QStringLiteral( "hideBackgroundIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
1348  layoutItem->addFrame( newFrame, false );
1349  }
1350 
1351  bool contentModeOK;
1352  layoutItem->setContentMode( static_cast< QgsLayoutItemHtml::ContentMode >( itemElem.attribute( QStringLiteral( "contentMode" ) ).toInt( &contentModeOK ) ) );
1353  if ( !contentModeOK )
1354  {
1355  layoutItem->setContentMode( QgsLayoutItemHtml::ContentMode::Url );
1356  }
1357  layoutItem->setEvaluateExpressions( itemElem.attribute( QStringLiteral( "evaluateExpressions" ), QStringLiteral( "true" ) ) == QLatin1String( "true" ) );
1358  layoutItem->setUseSmartBreaks( itemElem.attribute( QStringLiteral( "useSmartBreaks" ), QStringLiteral( "true" ) ) == QLatin1String( "true" ) );
1359  layoutItem->setMaxBreakDistance( itemElem.attribute( QStringLiteral( "maxBreakDistance" ), QStringLiteral( "10" ) ).toDouble() );
1360  layoutItem->setHtml( itemElem.attribute( QStringLiteral( "html" ) ) );
1361  layoutItem->setUserStylesheet( itemElem.attribute( QStringLiteral( "stylesheet" ) ) );
1362  layoutItem->setUserStylesheetEnabled( itemElem.attribute( QStringLiteral( "stylesheetEnabled" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1363 
1364  //finally load the set url
1365  QString urlString = itemElem.attribute( QStringLiteral( "url" ) );
1366  if ( !urlString.isEmpty() )
1367  {
1368  layoutItem->setUrl( urlString );
1369  }
1370  layoutItem->loadHtml( true );
1371 
1372  return true;
1373 }
1374 
1375 bool QgsCompositionConverter::readTableXml( QgsLayoutItemAttributeTable *layoutItem, const QDomElement &itemElem, const QgsProject *project )
1376 {
1377 
1378  Q_UNUSED( project )
1379  readOldComposerObjectXml( layoutItem, itemElem );
1380 
1381  //first create the frames
1382  layoutItem->setResizeMode( static_cast< QgsLayoutMultiFrame::ResizeMode >( itemElem.attribute( QStringLiteral( "resizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
1383  QDomNodeList frameList = itemElem.elementsByTagName( QStringLiteral( "ComposerFrame" ) );
1384  for ( int i = 0; i < frameList.size(); ++i )
1385  {
1386  QDomElement frameElem = frameList.at( i ).toElement();
1387  QgsLayoutFrame *newFrame = new QgsLayoutFrame( layoutItem->layout(), layoutItem );
1388  restoreGeneralComposeItemProperties( newFrame, frameElem );
1389  // Read frame XML
1390  double x = itemElem.attribute( QStringLiteral( "sectionX" ) ).toDouble();
1391  double y = itemElem.attribute( QStringLiteral( "sectionY" ) ).toDouble();
1392  double width = itemElem.attribute( QStringLiteral( "sectionWidth" ) ).toDouble();
1393  double height = itemElem.attribute( QStringLiteral( "sectionHeight" ) ).toDouble();
1394  newFrame->setContentSection( QRectF( x, y, width, height ) );
1395  newFrame->setHidePageIfEmpty( itemElem.attribute( QStringLiteral( "hidePageIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
1396  newFrame->setHideBackgroundIfEmpty( itemElem.attribute( QStringLiteral( "hideBackgroundIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
1397  layoutItem->addFrame( newFrame, false );
1398  }
1399 
1400  layoutItem->setEmptyTableBehavior( static_cast<QgsLayoutTable::EmptyTableMode>( itemElem.attribute( QStringLiteral( "emptyTableMode" ), QStringLiteral( "0" ) ).toInt() ) );
1401  layoutItem->setEmptyTableMessage( itemElem.attribute( QStringLiteral( "emptyTableMessage" ), QObject::tr( "No matching records" ) ) );
1402  layoutItem->setShowEmptyRows( itemElem.attribute( QStringLiteral( "showEmptyRows" ), QStringLiteral( "0" ) ).toInt() );
1403  if ( !QgsFontUtils::setFromXmlChildNode( layoutItem->mHeaderFont, itemElem, QStringLiteral( "headerFontProperties" ) ) )
1404  {
1405  layoutItem->mHeaderFont.fromString( itemElem.attribute( QStringLiteral( "headerFont" ), QString() ) );
1406  }
1407  layoutItem->setHeaderFontColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "headerFontColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
1408  layoutItem->setHeaderHAlignment( static_cast<QgsLayoutTable::HeaderHAlignment>( itemElem.attribute( QStringLiteral( "headerHAlignment" ), QStringLiteral( "0" ) ).toInt() ) ) ;
1409  layoutItem->setHeaderMode( static_cast<QgsLayoutTable::HeaderMode>( itemElem.attribute( QStringLiteral( "headerMode" ), QStringLiteral( "0" ) ).toInt() ) );
1410  if ( !QgsFontUtils::setFromXmlChildNode( layoutItem->mContentFont, itemElem, QStringLiteral( "contentFontProperties" ) ) )
1411  {
1412  layoutItem->mContentFont.fromString( itemElem.attribute( QStringLiteral( "contentFont" ), QString() ) );
1413  }
1414  layoutItem->setContentFontColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "contentFontColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
1415  layoutItem->setCellMargin( itemElem.attribute( QStringLiteral( "cellMargin" ), QStringLiteral( "1.0" ) ).toDouble() );
1416  layoutItem->setGridStrokeWidth( itemElem.attribute( QStringLiteral( "gridStrokeWidth" ), QStringLiteral( "0.5" ) ).toDouble() );
1417  layoutItem->setHorizontalGrid( itemElem.attribute( QStringLiteral( "horizontalGrid" ), QStringLiteral( "1" ) ).toInt() );
1418  layoutItem->setVerticalGrid( itemElem.attribute( QStringLiteral( "verticalGrid" ), QStringLiteral( "1" ) ).toInt() );
1419  layoutItem->setShowGrid( itemElem.attribute( QStringLiteral( "showGrid" ), QStringLiteral( "1" ) ).toInt() );
1420  layoutItem->setGridColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "gridColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
1421  layoutItem->setBackgroundColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "backgroundColor" ), QStringLiteral( "255,255,255,0" ) ) ) );
1422  layoutItem->setWrapBehavior( static_cast<QgsLayoutTable::WrapBehavior>( itemElem.attribute( QStringLiteral( "wrapBehavior" ), QStringLiteral( "0" ) ).toInt() ) );
1423 
1424  //restore column specifications
1425  layoutItem->mColumns.clear();
1426  QDomNodeList columnsList = itemElem.elementsByTagName( QStringLiteral( "displayColumns" ) );
1427  if ( !columnsList.isEmpty() )
1428  {
1429  QDomElement columnsElem = columnsList.at( 0 ).toElement();
1430  QDomNodeList columnEntryList = columnsElem.elementsByTagName( QStringLiteral( "column" ) );
1431  for ( int i = 0; i < columnEntryList.size(); ++i )
1432  {
1433  QDomElement columnElem = columnEntryList.at( i ).toElement();
1435  column->mHAlignment = static_cast< Qt::AlignmentFlag >( columnElem.attribute( QStringLiteral( "hAlignment" ), QString::number( Qt::AlignLeft ) ).toInt() );
1436  column->mVAlignment = static_cast< Qt::AlignmentFlag >( columnElem.attribute( QStringLiteral( "vAlignment" ), QString::number( Qt::AlignVCenter ) ).toInt() );
1437  column->mHeading = columnElem.attribute( QStringLiteral( "heading" ), QString() );
1438  column->mAttribute = columnElem.attribute( QStringLiteral( "attribute" ), QString() );
1439  column->mSortByRank = columnElem.attribute( QStringLiteral( "sortByRank" ), QStringLiteral( "0" ) ).toInt();
1440  column->mSortOrder = static_cast< Qt::SortOrder >( columnElem.attribute( QStringLiteral( "sortOrder" ), QString::number( Qt::AscendingOrder ) ).toInt() );
1441  column->mWidth = columnElem.attribute( QStringLiteral( "width" ), QStringLiteral( "0.0" ) ).toDouble();
1442 
1443  QDomNodeList bgColorList = columnElem.elementsByTagName( QStringLiteral( "backgroundColor" ) );
1444  if ( !bgColorList.isEmpty() )
1445  {
1446  QDomElement bgColorElem = bgColorList.at( 0 ).toElement();
1447  bool redOk, greenOk, blueOk, alphaOk;
1448  int bgRed, bgGreen, bgBlue, bgAlpha;
1449  bgRed = bgColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1450  bgGreen = bgColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1451  bgBlue = bgColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1452  bgAlpha = bgColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1453  if ( redOk && greenOk && blueOk && alphaOk )
1454  {
1455  column->mBackgroundColor = QColor( bgRed, bgGreen, bgBlue, bgAlpha );
1456  }
1457  }
1458  layoutItem->mColumns.append( column );
1459  }
1460  }
1461 
1462  //restore cell styles
1463  QDomNodeList stylesList = itemElem.elementsByTagName( QStringLiteral( "cellStyles" ) );
1464  if ( !stylesList.isEmpty() )
1465  {
1466  QDomElement stylesElem = stylesList.at( 0 ).toElement();
1467 
1468  QMap< QgsLayoutTable::CellStyleGroup, QString >::const_iterator it = layoutItem->mCellStyleNames.constBegin();
1469  for ( ; it != layoutItem->mCellStyleNames.constEnd(); ++it )
1470  {
1471  QString styleName = it.value();
1472  QDomNodeList styleList = stylesElem.elementsByTagName( styleName );
1473  if ( !styleList.isEmpty() )
1474  {
1475  QDomElement styleElem = styleList.at( 0 ).toElement();
1476  QgsLayoutTableStyle *style = layoutItem->mCellStyles.value( it.key() );
1477  if ( style )
1478  style->readXml( styleElem );
1479  }
1480  }
1481  }
1482 
1483  // look for stored layer name
1484  QString layerId = itemElem.attribute( QStringLiteral( "vectorLayer" ) );
1485  QString layerName = itemElem.attribute( QStringLiteral( "vectorLayerName" ) );
1486  QString layerSource = itemElem.attribute( QStringLiteral( "vectorLayerSource" ) );
1487  QString layerProvider = itemElem.attribute( QStringLiteral( "vectorLayerProvider" ) );
1488 
1489  QgsVectorLayerRef layerRef( layerId, layerName, layerSource, layerProvider );
1490  layoutItem->setVectorLayer( layerRef.resolveWeakly( project ) );
1491 
1492  return true;
1493 }
1494 
1495 
1496 template <class T, class T2>
1497 bool QgsCompositionConverter::readPolyXml( T *layoutItem, const QDomElement &itemElem, const QgsProject *project )
1498 {
1499  restoreGeneralComposeItemProperties( layoutItem, itemElem );
1500  QDomNodeList nodeList = itemElem.elementsByTagName( QStringLiteral( "node" ) );
1501  if ( !nodeList.isEmpty() )
1502  {
1503  QPolygonF polygon;
1504  for ( int i = 0; i < nodeList.length(); i++ )
1505  {
1506  QDomElement node = nodeList.at( i ).toElement();
1507  polygon.append( QPointF( node.attribute( QStringLiteral( "x" ) ).toDouble( ), node.attribute( QStringLiteral( "y" ) ).toDouble() ) );
1508  }
1509  layoutItem->setNodes( polygon );
1510  }
1511  if ( itemElem.elementsByTagName( QStringLiteral( "symbol" ) ).size() )
1512  {
1513  QDomElement symbolElement = itemElem.elementsByTagName( QStringLiteral( "symbol" ) ).at( 0 ).toElement();
1514  QgsReadWriteContext context;
1515  if ( project )
1516  context.setPathResolver( project->pathResolver( ) );
1517  T2 *styleSymbol = QgsSymbolLayerUtils::loadSymbol<T2>( symbolElement, context );
1518  if ( styleSymbol )
1519  layoutItem->setSymbol( styleSymbol );
1520  }
1521  // Disable frame for shapes
1522  layoutItem->setFrameEnabled( false );
1523  layoutItem->setBackgroundEnabled( false );
1524  return true;
1525 }
1526 
1527 
1528 bool QgsCompositionConverter::readXml( QgsLayoutItem *layoutItem, const QDomElement &itemElem )
1529 {
1530  if ( itemElem.isNull() )
1531  {
1532  return false;
1533  }
1534 
1535  readOldComposerObjectXml( layoutItem, itemElem );
1536 
1537  //uuid
1538  layoutItem->mUuid = itemElem.attribute( QStringLiteral( "uuid" ), QUuid::createUuid().toString() );
1539 
1540  // temporary for groups imported from templates
1541  layoutItem->mTemplateUuid = itemElem.attribute( QStringLiteral( "templateUuid" ) );
1542 
1543  //id
1544  QString id = itemElem.attribute( QStringLiteral( "id" ), QString() );
1545  layoutItem->setId( id );
1546 
1547  //frame
1548  QString frame = itemElem.attribute( QStringLiteral( "frame" ) );
1549  layoutItem->setFrameEnabled( frame.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 ) ;
1550 
1551  //frame
1552  QString background = itemElem.attribute( QStringLiteral( "background" ) );
1553  layoutItem->setBackgroundEnabled( background.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 );
1554 
1555  //position lock for mouse moves/resizes
1556  QString positionLock = itemElem.attribute( QStringLiteral( "positionLock" ) );
1557  layoutItem->setLocked( positionLock.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 );
1558 
1559  //visibility
1560  layoutItem->setVisibility( itemElem.attribute( QStringLiteral( "visibility" ), QStringLiteral( "1" ) ) != QStringLiteral( "0" ) );
1561 
1562  layoutItem->mParentGroupUuid = itemElem.attribute( QStringLiteral( "groupUuid" ) );
1563  if ( !layoutItem->mParentGroupUuid.isEmpty() )
1564  {
1565  if ( QgsLayoutItemGroup *group = layoutItem->parentGroup() )
1566  {
1567  group->addItem( layoutItem );
1568  }
1569  }
1570  layoutItem->mTemplateUuid = itemElem.attribute( QStringLiteral( "templateUuid" ) );
1571 
1572 
1573  QRectF position = itemPosition( layoutItem, itemElem );
1574 
1575  // TODO: missing?
1576  // mLastValidViewScaleFactor = itemElem.attribute( QStringLiteral( "lastValidViewScaleFactor" ), QStringLiteral( "-1" ) ).toDouble();
1577 
1578  layoutItem->setZValue( itemElem.attribute( QStringLiteral( "zValue" ) ).toDouble() );
1579 
1580  //pen
1581  QDomNodeList frameColorList = itemElem.elementsByTagName( QStringLiteral( "FrameColor" ) );
1582  if ( !frameColorList.isEmpty() )
1583  {
1584  QDomElement frameColorElem = frameColorList.at( 0 ).toElement();
1585  bool redOk, greenOk, blueOk, alphaOk, widthOk;
1586  int penRed, penGreen, penBlue, penAlpha;
1587  double penWidth;
1588 
1589  penWidth = itemElem.attribute( QStringLiteral( "outlineWidth" ) ).toDouble( &widthOk );
1590  penRed = frameColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1591  penGreen = frameColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1592  penBlue = frameColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1593  penAlpha = frameColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1594  layoutItem->setFrameJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( itemElem.attribute( QStringLiteral( "frameJoinStyle" ), QStringLiteral( "miter" ) ) ) );
1595 
1596  if ( redOk && greenOk && blueOk && alphaOk && widthOk )
1597  {
1598  layoutItem->setFrameStrokeColor( QColor( penRed, penGreen, penBlue, penAlpha ) );
1599  layoutItem->setFrameStrokeWidth( QgsLayoutMeasurement( penWidth ) );
1600  QPen framePen( layoutItem->frameStrokeColor() );
1601  framePen.setWidthF( layoutItem->frameStrokeWidth( ).length() );
1602  framePen.setJoinStyle( layoutItem->frameJoinStyle( ) );
1603  layoutItem->setPen( framePen );
1604  //apply any data defined settings
1605  layoutItem->refreshFrame( false );
1606  }
1607  }
1608 
1609  //brush
1610  QDomNodeList bgColorList = itemElem.elementsByTagName( QStringLiteral( "BackgroundColor" ) );
1611  if ( !bgColorList.isEmpty() )
1612  {
1613  QDomElement bgColorElem = bgColorList.at( 0 ).toElement();
1614  bool redOk, greenOk, blueOk, alphaOk;
1615  int bgRed, bgGreen, bgBlue, bgAlpha;
1616  bgRed = bgColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1617  bgGreen = bgColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1618  bgBlue = bgColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1619  bgAlpha = bgColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1620  if ( redOk && greenOk && blueOk && alphaOk )
1621  {
1622  layoutItem->mBackgroundColor = QColor( bgRed, bgGreen, bgBlue, bgAlpha );
1623  layoutItem->setBrush( QBrush( layoutItem->mBackgroundColor, Qt::SolidPattern ) );
1624  }
1625  //apply any data defined settings
1626  layoutItem->refreshBackgroundColor( false );
1627  }
1628 
1629  //blend mode
1630  layoutItem->setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( itemElem.attribute( QStringLiteral( "blendMode" ), QStringLiteral( "0" ) ).toUInt() ) ) );
1631 
1632  //opacity
1633  if ( itemElem.hasAttribute( QStringLiteral( "opacity" ) ) )
1634  {
1635  layoutItem->setItemOpacity( itemElem.attribute( QStringLiteral( "opacity" ), QStringLiteral( "1" ) ).toDouble() );
1636  }
1637  else
1638  {
1639  layoutItem->setItemOpacity( 1.0 - itemElem.attribute( QStringLiteral( "transparency" ), QStringLiteral( "0" ) ).toInt() / 100.0 );
1640  }
1641 
1642  layoutItem->mExcludeFromExports = itemElem.attribute( QStringLiteral( "excludeFromExports" ), QStringLiteral( "0" ) ).toInt();
1643  layoutItem->mEvaluatedExcludeFromExports = layoutItem->mExcludeFromExports;
1644 
1645  // positioning
1646  layoutItem->attemptSetSceneRect( position );
1647  //rotation
1648  layoutItem->setItemRotation( itemElem.attribute( QStringLiteral( "itemRotation" ), QStringLiteral( "0" ) ).toDouble(), false );
1649 
1650  layoutItem->mBlockUndoCommands = false;
1651 
1652  return true;
1653 }
1654 
1655 
1656 
1657 bool QgsCompositionConverter::readOldComposerObjectXml( QgsLayoutObject *layoutItem,
1658  const QDomElement &itemElem )
1659 {
1660  if ( itemElem.isNull() )
1661  {
1662  return false;
1663  }
1664 
1665  //old (pre 3.0) data defined properties
1666  QgsCompositionConverter::readOldDataDefinedPropertyMap( itemElem, layoutItem->mDataDefinedProperties );
1667 
1668  QDomNode propsNode = itemElem.namedItem( QStringLiteral( "dataDefinedProperties" ) );
1669  if ( !propsNode.isNull() )
1670  {
1671  layoutItem->mDataDefinedProperties.readXml( propsNode.toElement(), sPropertyDefinitions );
1672  }
1674  {
1675  // upgrade transparency -> opacity
1677  exp = QStringLiteral( "100.0 - (%1)" ).arg( exp );
1680  }
1681 
1682  //custom properties
1683  layoutItem->mCustomProperties.readXml( itemElem );
1684 
1685  return true;
1686 }
1687 
1688 
1689 void QgsCompositionConverter::readOldDataDefinedPropertyMap( const QDomElement &itemElem, QgsPropertyCollection &dataDefinedProperties )
1690 {
1691  const QgsPropertiesDefinition defs = QgsCompositionConverter::propertyDefinitions();
1692  QgsPropertiesDefinition::const_iterator i = defs.constBegin();
1693  for ( ; i != defs.constEnd(); ++i )
1694  {
1695  QString elemName = i.value().name();
1696  QDomNodeList ddNodeList = itemElem.elementsByTagName( elemName );
1697  if ( !ddNodeList.isEmpty() )
1698  {
1699  QDomElement ddElem = ddNodeList.at( 0 ).toElement();
1700  QgsProperty prop = readOldDataDefinedProperty( static_cast< QgsCompositionConverter::DataDefinedProperty >( i.key() ), ddElem );
1701  if ( prop )
1702  dataDefinedProperties.setProperty( i.key(), prop );
1703  }
1704  }
1705 }
1706 
1707 QgsProperty QgsCompositionConverter::readOldDataDefinedProperty( const QgsCompositionConverter::DataDefinedProperty property, const QDomElement &ddElem )
1708 {
1710  {
1711  //invalid property
1712  return QgsProperty();
1713  }
1714 
1715  QString active = ddElem.attribute( QStringLiteral( "active" ) );
1716  bool isActive = false;
1717  if ( active.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
1718  {
1719  isActive = true;
1720  }
1721  QString field = ddElem.attribute( QStringLiteral( "field" ) );
1722  QString expr = ddElem.attribute( QStringLiteral( "expr" ) );
1723 
1724  QString useExpr = ddElem.attribute( QStringLiteral( "useExpr" ) );
1725  bool isExpression = false;
1726  if ( useExpr.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
1727  {
1728  isExpression = true;
1729  }
1730 
1731  if ( isExpression )
1732  return QgsProperty::fromExpression( expr, isActive );
1733  else
1734  return QgsProperty::fromField( field, isActive );
1735 }
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:1215
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:1226
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:265
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 composer table cell.
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
TYPE * resolveWeakly(const QgsProject *project)
Resolves the map layer by attempting to find a matching layer in a project using a weak match...
Non-zero positive integer values.
Definition: qgsproperty.h:56
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:634
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:597
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:1059
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:1706
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...
Reads and writes project states.
Definition: qgsproject.h:90
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:54
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:635
void setAnnotationPrecision(const int precision)
Sets the coordinate precision for grid annotations.
Unknown distance unit.
Definition: qgsunittypes.h:65
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.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgssymbol.h:1154
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 setEnabled(bool enabled)
Controls whether the item will be drawn.
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.
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:471
void setLabelBarSpace(double space)
Sets the spacing (in millimeters) between labels and the scalebar.