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