QGIS API Documentation  3.0.2-Girona (307d082)
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  }
1034  layoutItem->setFont( f );
1035 
1036  //colors
1037  //fill color
1038  QDomNodeList fillColorList = itemElem.elementsByTagName( QStringLiteral( "fillColor" ) );
1039  if ( !fillColorList.isEmpty() )
1040  {
1041  QDomElement fillColorElem = fillColorList.at( 0 ).toElement();
1042  bool redOk, greenOk, blueOk, alphaOk;
1043  int fillRed, fillGreen, fillBlue, fillAlpha;
1044 
1045  fillRed = fillColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1046  fillGreen = fillColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1047  fillBlue = fillColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1048  fillAlpha = fillColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1049 
1050  if ( redOk && greenOk && blueOk && alphaOk )
1051  {
1052  layoutItem->setFillColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
1053  }
1054  }
1055  else
1056  {
1057  layoutItem->setFillColor( QColor( itemElem.attribute( QStringLiteral( "brushColor" ), QStringLiteral( "#000000" ) ) ) );
1058  }
1059 
1060  //fill color 2
1061  QDomNodeList fillColor2List = itemElem.elementsByTagName( QStringLiteral( "fillColor2" ) );
1062  if ( !fillColor2List.isEmpty() )
1063  {
1064  QDomElement fillColor2Elem = fillColor2List.at( 0 ).toElement();
1065  bool redOk, greenOk, blueOk, alphaOk;
1066  int fillRed, fillGreen, fillBlue, fillAlpha;
1067 
1068  fillRed = fillColor2Elem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1069  fillGreen = fillColor2Elem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1070  fillBlue = fillColor2Elem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1071  fillAlpha = fillColor2Elem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1072 
1073  if ( redOk && greenOk && blueOk && alphaOk )
1074  {
1075  layoutItem->setFillColor2( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
1076  }
1077  }
1078  else
1079  {
1080  layoutItem->setFillColor2( QColor( itemElem.attribute( QStringLiteral( "brush2Color" ), QStringLiteral( "#ffffff" ) ) ) );
1081  }
1082 
1083  //stroke color
1084  QDomNodeList strokeColorList = itemElem.elementsByTagName( QStringLiteral( "strokeColor" ) );
1085  if ( !strokeColorList.isEmpty() )
1086  {
1087  QDomElement strokeColorElem = strokeColorList.at( 0 ).toElement();
1088  bool redOk, greenOk, blueOk, alphaOk;
1089  int strokeRed, strokeGreen, strokeBlue, strokeAlpha;
1090 
1091  strokeRed = strokeColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1092  strokeGreen = strokeColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1093  strokeBlue = strokeColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1094  strokeAlpha = strokeColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1095 
1096  if ( redOk && greenOk && blueOk && alphaOk )
1097  {
1098  layoutItem->setLineColor( QColor( strokeRed, strokeGreen, strokeBlue, strokeAlpha ) );
1099  QPen p = layoutItem->mSettings.pen();
1100  p.setColor( layoutItem->mSettings.lineColor() );
1101  layoutItem->setPen( p );
1102  }
1103  }
1104  else
1105  {
1106  layoutItem->setLineColor( QColor( itemElem.attribute( QStringLiteral( "penColor" ), QStringLiteral( "#000000" ) ) ) );
1107  QPen p = layoutItem->mSettings.pen();
1108  p.setColor( layoutItem->mSettings.lineColor() );
1109  layoutItem->setPen( p );
1110  }
1111 
1112  //font color
1113  QDomNodeList textColorList = itemElem.elementsByTagName( QStringLiteral( "textColor" ) );
1114  if ( !textColorList.isEmpty() )
1115  {
1116  QDomElement textColorElem = textColorList.at( 0 ).toElement();
1117  bool redOk, greenOk, blueOk, alphaOk;
1118  int textRed, textGreen, textBlue, textAlpha;
1119 
1120  textRed = textColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1121  textGreen = textColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1122  textBlue = textColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1123  textAlpha = textColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1124 
1125  if ( redOk && greenOk && blueOk && alphaOk )
1126  {
1127  layoutItem->setFontColor( QColor( textRed, textGreen, textBlue, textAlpha ) );
1128  }
1129  }
1130  else
1131  {
1132  QColor c;
1133  c.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
1134  layoutItem->setFontColor( c );
1135  }
1136 
1137  //style
1138  QString styleString = itemElem.attribute( QStringLiteral( "style" ), QLatin1String( "" ) );
1139  layoutItem->setStyle( QObject::tr( styleString.toLocal8Bit().data() ) );
1140 
1141  if ( itemElem.attribute( QStringLiteral( "unitType" ) ).isEmpty() )
1142  {
1144  switch ( itemElem.attribute( QStringLiteral( "units" ) ).toInt() )
1145  {
1146  case 0:
1148  break;
1149  case 1:
1151  break;
1152  case 2:
1154  break;
1155  case 3:
1157  break;
1158  }
1159  layoutItem->setUnits( u );
1160  }
1161  else
1162  {
1163  layoutItem->setUnits( QgsUnitTypes::decodeDistanceUnit( itemElem.attribute( QStringLiteral( "unitType" ) ) ) );
1164  }
1165  layoutItem->setAlignment( static_cast< QgsScaleBarSettings::Alignment >( itemElem.attribute( QStringLiteral( "alignment" ), QStringLiteral( "0" ) ).toInt() ) );
1166 
1167  //composer map: use uuid
1168  QString mapId = itemElem.attribute( QStringLiteral( "mapId" ), QStringLiteral( "-1" ) );
1169  if ( mapId != QStringLiteral( "-1" ) && mapId2Uuid.contains( mapId ) )
1170  {
1171  QgsLayoutItemMap *mapInstance = qobject_cast<QgsLayoutItemMap *>( layoutItem->layout()->itemByUuid( mapId2Uuid[ mapId ] ) );
1172  if ( mapInstance )
1173  {
1174  layoutItem->setLinkedMap( mapInstance );
1175  }
1176  }
1177 
1178  return true;
1179 }
1180 
1181 bool QgsCompositionConverter::readLegendXml( QgsLayoutItemLegend *layoutItem, const QDomElement &itemElem, const QgsProject *project, const QgsStringMap &mapId2Uuid )
1182 {
1183  restoreGeneralComposeItemProperties( layoutItem, itemElem );
1184 
1185  QgsPathResolver pathResolver;
1186  if ( project )
1187  pathResolver = project->pathResolver();
1188  QgsReadWriteContext context;
1189  context.setPathResolver( pathResolver );
1190 
1191  //composer map: use uuid
1192  QString mapId = itemElem.attribute( QStringLiteral( "map" ), QStringLiteral( "-1" ) );
1193  if ( mapId != QStringLiteral( "-1" ) && mapId2Uuid.contains( mapId ) )
1194  {
1195  QgsLayoutItemMap *mapInstance = qobject_cast<QgsLayoutItemMap *>( layoutItem->layout()->itemByUuid( mapId2Uuid[ mapId ] ) );
1196  if ( mapInstance )
1197  {
1198  layoutItem->setLinkedMap( mapInstance );
1199  }
1200  }
1201 
1202  //read general properties
1203  layoutItem->setTitle( itemElem.attribute( QStringLiteral( "title" ) ) );
1204  if ( !itemElem.attribute( QStringLiteral( "titleAlignment" ) ).isEmpty() )
1205  {
1206  layoutItem->setTitleAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "titleAlignment" ) ).toInt() ) );
1207  }
1208  int colCount = itemElem.attribute( QStringLiteral( "columnCount" ), QStringLiteral( "1" ) ).toInt();
1209  if ( colCount < 1 ) colCount = 1;
1210  layoutItem->setColumnCount( colCount );
1211  layoutItem->setSplitLayer( itemElem.attribute( QStringLiteral( "splitLayer" ), QStringLiteral( "0" ) ).toInt() == 1 );
1212  layoutItem->setEqualColumnWidth( itemElem.attribute( QStringLiteral( "equalColumnWidth" ), QStringLiteral( "0" ) ).toInt() == 1 );
1213 
1214  QDomNodeList stylesNodeList = itemElem.elementsByTagName( QStringLiteral( "styles" ) );
1215  if ( !stylesNodeList.isEmpty() )
1216  {
1217  QDomNode stylesNode = stylesNodeList.at( 0 );
1218  for ( int i = 0; i < stylesNode.childNodes().size(); i++ )
1219  {
1220  QDomElement styleElem = stylesNode.childNodes().at( i ).toElement();
1221  QgsLegendStyle style;
1222  style.readXml( styleElem, QDomDocument() );
1223  QString name = styleElem.attribute( QStringLiteral( "name" ) );
1225  if ( name == QLatin1String( "title" ) ) s = QgsLegendStyle::Title;
1226  else if ( name == QLatin1String( "group" ) ) s = QgsLegendStyle::Group;
1227  else if ( name == QLatin1String( "subgroup" ) ) s = QgsLegendStyle::Subgroup;
1228  else if ( name == QLatin1String( "symbol" ) ) s = QgsLegendStyle::Symbol;
1229  else if ( name == QLatin1String( "symbolLabel" ) ) s = QgsLegendStyle::SymbolLabel;
1230  else continue;
1231  layoutItem->setStyle( s, style );
1232  }
1233  }
1234 
1235  //font color
1236  QColor fontClr;
1237  fontClr.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
1238  layoutItem->setFontColor( fontClr );
1239 
1240  //spaces
1241  layoutItem->setBoxSpace( itemElem.attribute( QStringLiteral( "boxSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
1242  layoutItem->setColumnSpace( itemElem.attribute( QStringLiteral( "columnSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
1243 
1244  layoutItem->setSymbolWidth( itemElem.attribute( QStringLiteral( "symbolWidth" ), QStringLiteral( "7.0" ) ).toDouble() );
1245  layoutItem->setSymbolHeight( itemElem.attribute( QStringLiteral( "symbolHeight" ), QStringLiteral( "14.0" ) ).toDouble() );
1246  layoutItem->setWmsLegendWidth( itemElem.attribute( QStringLiteral( "wmsLegendWidth" ), QStringLiteral( "50" ) ).toDouble() );
1247  layoutItem->setWmsLegendHeight( itemElem.attribute( QStringLiteral( "wmsLegendHeight" ), QStringLiteral( "25" ) ).toDouble() );
1248  layoutItem->setLineSpacing( itemElem.attribute( QStringLiteral( "lineSpacing" ), QStringLiteral( "1.0" ) ).toDouble() );
1249 
1250  layoutItem->setDrawRasterStroke( itemElem.attribute( QStringLiteral( "rasterBorder" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
1251  layoutItem->setRasterStrokeColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "rasterBorderColor" ), QStringLiteral( "0,0,0" ) ) ) );
1252  layoutItem->setRasterStrokeWidth( itemElem.attribute( QStringLiteral( "rasterBorderWidth" ), QStringLiteral( "0" ) ).toDouble() );
1253 
1254  layoutItem->setWrapString( itemElem.attribute( QStringLiteral( "wrapChar" ) ) );
1255 
1256  layoutItem->mSizeToContents = itemElem.attribute( QStringLiteral( "resizeToContents" ), QStringLiteral( "1" ) ) != QLatin1String( "0" );
1257  layoutItem->mLegendFilterByMap = itemElem.attribute( QStringLiteral( "legendFilterByMap" ), QStringLiteral( "0" ) ).toInt();
1258  layoutItem->mFilterOutAtlas = itemElem.attribute( QStringLiteral( "legendFilterByAtlas" ), QStringLiteral( "0" ) ).toInt();
1259 
1260  // QGIS >= 2.6
1261  QDomElement layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree" ) );
1262  if ( layerTreeElem.isNull() )
1263  layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree-group" ) );
1264 
1265  if ( !layerTreeElem.isNull() )
1266  {
1267  QgsLayerTree *tree( QgsLayerTree::readXml( layerTreeElem, context ) );
1268  if ( project )
1269  tree->resolveReferences( project, true );
1270  layoutItem->setCustomLayerTree( tree );
1271  }
1272  else
1273  {
1274  layoutItem->setCustomLayerTree( nullptr );
1275  }
1276 
1277  return true;
1278 }
1279 
1280 bool QgsCompositionConverter::readAtlasXml( QgsLayoutAtlas *atlasItem, const QDomElement &itemElem, const QgsProject *project )
1281 {
1282  atlasItem->setEnabled( itemElem.attribute( QStringLiteral( "enabled" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1283 
1284  // look for stored layer name
1285  QString layerId = itemElem.attribute( QStringLiteral( "coverageLayer" ) );
1286  QString layerName = itemElem.attribute( QStringLiteral( "coverageLayerName" ) );
1287  QString layerSource = itemElem.attribute( QStringLiteral( "coverageLayerSource" ) );
1288  QString layerProvider = itemElem.attribute( QStringLiteral( "coverageLayerProvider" ) );
1289 
1290  QgsVectorLayerRef layerRef( layerId, layerName, layerSource, layerProvider );
1291  atlasItem->setCoverageLayer( layerRef.resolveWeakly( project ) );
1292 
1293  atlasItem->setPageNameExpression( itemElem.attribute( QStringLiteral( "pageNameExpression" ), QString() ) );
1294  QString errorString;
1295  atlasItem->setFilenameExpression( itemElem.attribute( QStringLiteral( "filenamePattern" ), QLatin1String( "" ) ), errorString );
1296  // note: no error reporting for errorString
1297  atlasItem->setSortFeatures( itemElem.attribute( QStringLiteral( "sortFeatures" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1298  if ( atlasItem->sortFeatures() )
1299  {
1300  atlasItem->setSortExpression( itemElem.attribute( QStringLiteral( "sortKey" ), QLatin1String( "" ) ) );
1301  atlasItem->setSortAscending( itemElem.attribute( QStringLiteral( "sortAscending" ), QStringLiteral( "true" ) ) == QLatin1String( "true" ) );
1302  }
1303  atlasItem->setFilterFeatures( itemElem.attribute( QStringLiteral( "filterFeatures" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1304  if ( atlasItem->filterFeatures( ) )
1305  {
1306  QString expErrorString;
1307  atlasItem->setFilterExpression( itemElem.attribute( QStringLiteral( "featureFilter" ), QLatin1String( "" ) ), expErrorString );
1308  // note: no error reporting for errorString
1309  }
1310 
1311  atlasItem->setHideCoverage( itemElem.attribute( QStringLiteral( "hideCoverage" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1312 
1313  return true;
1314 
1315 }
1316 
1317 bool QgsCompositionConverter::readHtmlXml( QgsLayoutItemHtml *layoutItem, const QDomElement &itemElem, const QgsProject *project )
1318 {
1319  Q_UNUSED( project );
1320  readOldComposerObjectXml( layoutItem, itemElem );
1321 
1322  //first create the frames
1323  layoutItem->setResizeMode( static_cast< QgsLayoutMultiFrame::ResizeMode >( itemElem.attribute( QStringLiteral( "resizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
1324  QDomNodeList frameList = itemElem.elementsByTagName( QStringLiteral( "ComposerFrame" ) );
1325  for ( int i = 0; i < frameList.size(); ++i )
1326  {
1327  QDomElement frameElem = frameList.at( i ).toElement();
1328  QgsLayoutFrame *newFrame = new QgsLayoutFrame( layoutItem->layout(), layoutItem );
1329  restoreGeneralComposeItemProperties( newFrame, frameElem );
1330  // Read frame XML
1331  double x = itemElem.attribute( QStringLiteral( "sectionX" ) ).toDouble();
1332  double y = itemElem.attribute( QStringLiteral( "sectionY" ) ).toDouble();
1333  double width = itemElem.attribute( QStringLiteral( "sectionWidth" ) ).toDouble();
1334  double height = itemElem.attribute( QStringLiteral( "sectionHeight" ) ).toDouble();
1335  newFrame->setContentSection( QRectF( x, y, width, height ) );
1336  newFrame->setHidePageIfEmpty( itemElem.attribute( QStringLiteral( "hidePageIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
1337  newFrame->setHideBackgroundIfEmpty( itemElem.attribute( QStringLiteral( "hideBackgroundIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
1338  layoutItem->addFrame( newFrame, false );
1339  }
1340 
1341  bool contentModeOK;
1342  layoutItem->setContentMode( static_cast< QgsLayoutItemHtml::ContentMode >( itemElem.attribute( QStringLiteral( "contentMode" ) ).toInt( &contentModeOK ) ) );
1343  if ( !contentModeOK )
1344  {
1345  layoutItem->setContentMode( QgsLayoutItemHtml::ContentMode::Url );
1346  }
1347  layoutItem->setEvaluateExpressions( itemElem.attribute( QStringLiteral( "evaluateExpressions" ), QStringLiteral( "true" ) ) == QLatin1String( "true" ) );
1348  layoutItem->setUseSmartBreaks( itemElem.attribute( QStringLiteral( "useSmartBreaks" ), QStringLiteral( "true" ) ) == QLatin1String( "true" ) );
1349  layoutItem->setMaxBreakDistance( itemElem.attribute( QStringLiteral( "maxBreakDistance" ), QStringLiteral( "10" ) ).toDouble() );
1350  layoutItem->setHtml( itemElem.attribute( QStringLiteral( "html" ) ) );
1351  layoutItem->setUserStylesheet( itemElem.attribute( QStringLiteral( "stylesheet" ) ) );
1352  layoutItem->setUserStylesheetEnabled( itemElem.attribute( QStringLiteral( "stylesheetEnabled" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) );
1353 
1354  //finally load the set url
1355  QString urlString = itemElem.attribute( QStringLiteral( "url" ) );
1356  if ( !urlString.isEmpty() )
1357  {
1358  layoutItem->setUrl( urlString );
1359  }
1360  layoutItem->loadHtml( true );
1361 
1362  return true;
1363 }
1364 
1365 bool QgsCompositionConverter::readTableXml( QgsLayoutItemAttributeTable *layoutItem, const QDomElement &itemElem, const QgsProject *project )
1366 {
1367 
1368  Q_UNUSED( project );
1369  readOldComposerObjectXml( layoutItem, itemElem );
1370 
1371  //first create the frames
1372  layoutItem->setResizeMode( static_cast< QgsLayoutMultiFrame::ResizeMode >( itemElem.attribute( QStringLiteral( "resizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
1373  QDomNodeList frameList = itemElem.elementsByTagName( QStringLiteral( "ComposerFrame" ) );
1374  for ( int i = 0; i < frameList.size(); ++i )
1375  {
1376  QDomElement frameElem = frameList.at( i ).toElement();
1377  QgsLayoutFrame *newFrame = new QgsLayoutFrame( layoutItem->layout(), layoutItem );
1378  restoreGeneralComposeItemProperties( newFrame, frameElem );
1379  // Read frame XML
1380  double x = itemElem.attribute( QStringLiteral( "sectionX" ) ).toDouble();
1381  double y = itemElem.attribute( QStringLiteral( "sectionY" ) ).toDouble();
1382  double width = itemElem.attribute( QStringLiteral( "sectionWidth" ) ).toDouble();
1383  double height = itemElem.attribute( QStringLiteral( "sectionHeight" ) ).toDouble();
1384  newFrame->setContentSection( QRectF( x, y, width, height ) );
1385  newFrame->setHidePageIfEmpty( itemElem.attribute( QStringLiteral( "hidePageIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
1386  newFrame->setHideBackgroundIfEmpty( itemElem.attribute( QStringLiteral( "hideBackgroundIfEmpty" ), QStringLiteral( "0" ) ).toInt() );
1387  layoutItem->addFrame( newFrame, false );
1388  }
1389 
1390  layoutItem->setEmptyTableBehavior( static_cast<QgsLayoutTable::EmptyTableMode>( itemElem.attribute( QStringLiteral( "emptyTableMode" ), QStringLiteral( "0" ) ).toInt() ) );
1391  layoutItem->setEmptyTableMessage( itemElem.attribute( QStringLiteral( "emptyTableMessage" ), QObject::tr( "No matching records" ) ) );
1392  layoutItem->setShowEmptyRows( itemElem.attribute( QStringLiteral( "showEmptyRows" ), QStringLiteral( "0" ) ).toInt() );
1393  if ( !QgsFontUtils::setFromXmlChildNode( layoutItem->mHeaderFont, itemElem, QStringLiteral( "headerFontProperties" ) ) )
1394  {
1395  layoutItem->mHeaderFont.fromString( itemElem.attribute( QStringLiteral( "headerFont" ), QLatin1String( "" ) ) );
1396  }
1397  layoutItem->setHeaderFontColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "headerFontColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
1398  layoutItem->setHeaderHAlignment( static_cast<QgsLayoutTable::HeaderHAlignment>( itemElem.attribute( QStringLiteral( "headerHAlignment" ), QStringLiteral( "0" ) ).toInt() ) ) ;
1399  layoutItem->setHeaderMode( static_cast<QgsLayoutTable::HeaderMode>( itemElem.attribute( QStringLiteral( "headerMode" ), QStringLiteral( "0" ) ).toInt() ) );
1400  if ( !QgsFontUtils::setFromXmlChildNode( layoutItem->mContentFont, itemElem, QStringLiteral( "contentFontProperties" ) ) )
1401  {
1402  layoutItem->mContentFont.fromString( itemElem.attribute( QStringLiteral( "contentFont" ), QLatin1String( "" ) ) );
1403  }
1404  layoutItem->setContentFontColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "contentFontColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
1405  layoutItem->setCellMargin( itemElem.attribute( QStringLiteral( "cellMargin" ), QStringLiteral( "1.0" ) ).toDouble() );
1406  layoutItem->setGridStrokeWidth( itemElem.attribute( QStringLiteral( "gridStrokeWidth" ), QStringLiteral( "0.5" ) ).toDouble() );
1407  layoutItem->setHorizontalGrid( itemElem.attribute( QStringLiteral( "horizontalGrid" ), QStringLiteral( "1" ) ).toInt() );
1408  layoutItem->setVerticalGrid( itemElem.attribute( QStringLiteral( "verticalGrid" ), QStringLiteral( "1" ) ).toInt() );
1409  layoutItem->setShowGrid( itemElem.attribute( QStringLiteral( "showGrid" ), QStringLiteral( "1" ) ).toInt() );
1410  layoutItem->setGridColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "gridColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
1411  layoutItem->setBackgroundColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "backgroundColor" ), QStringLiteral( "255,255,255,0" ) ) ) );
1412  layoutItem->setWrapBehavior( static_cast<QgsLayoutTable::WrapBehavior>( itemElem.attribute( QStringLiteral( "wrapBehavior" ), QStringLiteral( "0" ) ).toInt() ) );
1413 
1414  //restore column specifications
1415  layoutItem->mColumns.clear();
1416  QDomNodeList columnsList = itemElem.elementsByTagName( QStringLiteral( "displayColumns" ) );
1417  if ( !columnsList.isEmpty() )
1418  {
1419  QDomElement columnsElem = columnsList.at( 0 ).toElement();
1420  QDomNodeList columnEntryList = columnsElem.elementsByTagName( QStringLiteral( "column" ) );
1421  for ( int i = 0; i < columnEntryList.size(); ++i )
1422  {
1423  QDomElement columnElem = columnEntryList.at( i ).toElement();
1425  column->mHAlignment = static_cast< Qt::AlignmentFlag >( columnElem.attribute( QStringLiteral( "hAlignment" ), QString::number( Qt::AlignLeft ) ).toInt() );
1426  column->mVAlignment = static_cast< Qt::AlignmentFlag >( columnElem.attribute( QStringLiteral( "vAlignment" ), QString::number( Qt::AlignVCenter ) ).toInt() );
1427  column->mHeading = columnElem.attribute( QStringLiteral( "heading" ), QLatin1String( "" ) );
1428  column->mAttribute = columnElem.attribute( QStringLiteral( "attribute" ), QLatin1String( "" ) );
1429  column->mSortByRank = columnElem.attribute( QStringLiteral( "sortByRank" ), QStringLiteral( "0" ) ).toInt();
1430  column->mSortOrder = static_cast< Qt::SortOrder >( columnElem.attribute( QStringLiteral( "sortOrder" ), QString::number( Qt::AscendingOrder ) ).toInt() );
1431  column->mWidth = columnElem.attribute( QStringLiteral( "width" ), QStringLiteral( "0.0" ) ).toDouble();
1432 
1433  QDomNodeList bgColorList = columnElem.elementsByTagName( QStringLiteral( "backgroundColor" ) );
1434  if ( !bgColorList.isEmpty() )
1435  {
1436  QDomElement bgColorElem = bgColorList.at( 0 ).toElement();
1437  bool redOk, greenOk, blueOk, alphaOk;
1438  int bgRed, bgGreen, bgBlue, bgAlpha;
1439  bgRed = bgColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1440  bgGreen = bgColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1441  bgBlue = bgColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1442  bgAlpha = bgColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1443  if ( redOk && greenOk && blueOk && alphaOk )
1444  {
1445  column->mBackgroundColor = QColor( bgRed, bgGreen, bgBlue, bgAlpha );
1446  }
1447  }
1448  layoutItem->mColumns.append( column );
1449  }
1450  }
1451 
1452  //restore cell styles
1453  QDomNodeList stylesList = itemElem.elementsByTagName( QStringLiteral( "cellStyles" ) );
1454  if ( !stylesList.isEmpty() )
1455  {
1456  QDomElement stylesElem = stylesList.at( 0 ).toElement();
1457 
1458  QMap< QgsLayoutTable::CellStyleGroup, QString >::const_iterator it = layoutItem->mCellStyleNames.constBegin();
1459  for ( ; it != layoutItem->mCellStyleNames.constEnd(); ++it )
1460  {
1461  QString styleName = it.value();
1462  QDomNodeList styleList = stylesElem.elementsByTagName( styleName );
1463  if ( !styleList.isEmpty() )
1464  {
1465  QDomElement styleElem = styleList.at( 0 ).toElement();
1466  QgsLayoutTableStyle *style = layoutItem->mCellStyles.value( it.key() );
1467  if ( style )
1468  style->readXml( styleElem );
1469  }
1470  }
1471  }
1472 
1473  // look for stored layer name
1474  QString layerId = itemElem.attribute( QStringLiteral( "vectorLayer" ) );
1475  QString layerName = itemElem.attribute( QStringLiteral( "vectorLayerName" ) );
1476  QString layerSource = itemElem.attribute( QStringLiteral( "vectorLayerSource" ) );
1477  QString layerProvider = itemElem.attribute( QStringLiteral( "vectorLayerProvider" ) );
1478 
1479  QgsVectorLayerRef layerRef( layerId, layerName, layerSource, layerProvider );
1480  layoutItem->setVectorLayer( layerRef.resolveWeakly( project ) );
1481 
1482  return true;
1483 }
1484 
1485 
1486 template <class T, class T2>
1487 bool QgsCompositionConverter::readPolyXml( T *layoutItem, const QDomElement &itemElem, const QgsProject *project )
1488 {
1489  restoreGeneralComposeItemProperties( layoutItem, itemElem );
1490  QDomNodeList nodeList = itemElem.elementsByTagName( QStringLiteral( "node" ) );
1491  if ( !nodeList.isEmpty() )
1492  {
1493  QPolygonF polygon;
1494  for ( int i = 0; i < nodeList.length(); i++ )
1495  {
1496  QDomElement node = nodeList.at( i ).toElement();
1497  polygon.append( QPointF( node.attribute( QStringLiteral( "x" ) ).toDouble( ), node.attribute( QStringLiteral( "y" ) ).toDouble() ) );
1498  }
1499  layoutItem->setNodes( polygon );
1500  }
1501  if ( itemElem.elementsByTagName( QStringLiteral( "symbol" ) ).size() )
1502  {
1503  QDomElement symbolElement = itemElem.elementsByTagName( QStringLiteral( "symbol" ) ).at( 0 ).toElement();
1504  QgsReadWriteContext context;
1505  if ( project )
1506  context.setPathResolver( project->pathResolver( ) );
1507  T2 *styleSymbol = QgsSymbolLayerUtils::loadSymbol<T2>( symbolElement, context );
1508  if ( styleSymbol )
1509  layoutItem->setSymbol( styleSymbol );
1510  }
1511  // Disable frame for shapes
1512  layoutItem->setFrameEnabled( false );
1513  layoutItem->setBackgroundEnabled( false );
1514  return true;
1515 }
1516 
1517 
1518 bool QgsCompositionConverter::readXml( QgsLayoutItem *layoutItem, const QDomElement &itemElem )
1519 {
1520  if ( itemElem.isNull() )
1521  {
1522  return false;
1523  }
1524 
1525  readOldComposerObjectXml( layoutItem, itemElem );
1526 
1527  //uuid
1528  layoutItem->mUuid = itemElem.attribute( QStringLiteral( "uuid" ), QUuid::createUuid().toString() );
1529 
1530  // temporary for groups imported from templates
1531  layoutItem->mTemplateUuid = itemElem.attribute( QStringLiteral( "templateUuid" ) );
1532 
1533  //id
1534  QString id = itemElem.attribute( QStringLiteral( "id" ), QStringLiteral( "" ) );
1535  layoutItem->setId( id );
1536 
1537  //frame
1538  QString frame = itemElem.attribute( QStringLiteral( "frame" ) );
1539  layoutItem->setFrameEnabled( frame.compare( QStringLiteral( "true" ), Qt::CaseInsensitive ) == 0 ) ;
1540 
1541  //frame
1542  QString background = itemElem.attribute( QStringLiteral( "background" ) );
1543  layoutItem->setBackgroundEnabled( background.compare( QStringLiteral( "true" ), Qt::CaseInsensitive ) == 0 );
1544 
1545  //position lock for mouse moves/resizes
1546  QString positionLock = itemElem.attribute( QStringLiteral( "positionLock" ) );
1547  layoutItem->setLocked( positionLock.compare( QStringLiteral( "true" ), Qt::CaseInsensitive ) == 0 );
1548 
1549  //visibility
1550  layoutItem->setVisibility( itemElem.attribute( QStringLiteral( "visibility" ), QStringLiteral( "1" ) ) != QStringLiteral( "0" ) );
1551 
1552  layoutItem->mParentGroupUuid = itemElem.attribute( QStringLiteral( "groupUuid" ) );
1553  if ( !layoutItem->mParentGroupUuid.isEmpty() )
1554  {
1555  if ( QgsLayoutItemGroup *group = layoutItem->parentGroup() )
1556  {
1557  group->addItem( layoutItem );
1558  }
1559  }
1560  layoutItem->mTemplateUuid = itemElem.attribute( "templateUuid" );
1561 
1562 
1563  QRectF position = itemPosition( layoutItem, itemElem );
1564 
1565  // TODO: missing?
1566  // mLastValidViewScaleFactor = itemElem.attribute( QStringLiteral( "lastValidViewScaleFactor" ), QStringLiteral( "-1" ) ).toDouble();
1567 
1568  layoutItem->setZValue( itemElem.attribute( QStringLiteral( "zValue" ) ).toDouble() );
1569 
1570  //pen
1571  QDomNodeList frameColorList = itemElem.elementsByTagName( QStringLiteral( "FrameColor" ) );
1572  if ( !frameColorList.isEmpty() )
1573  {
1574  QDomElement frameColorElem = frameColorList.at( 0 ).toElement();
1575  bool redOk, greenOk, blueOk, alphaOk, widthOk;
1576  int penRed, penGreen, penBlue, penAlpha;
1577  double penWidth;
1578 
1579  penWidth = itemElem.attribute( QStringLiteral( "outlineWidth" ) ).toDouble( &widthOk );
1580  penRed = frameColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1581  penGreen = frameColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1582  penBlue = frameColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1583  penAlpha = frameColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1584  layoutItem->setFrameJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( itemElem.attribute( QStringLiteral( "frameJoinStyle" ), QStringLiteral( "miter" ) ) ) );
1585 
1586  if ( redOk && greenOk && blueOk && alphaOk && widthOk )
1587  {
1588  layoutItem->setFrameStrokeColor( QColor( penRed, penGreen, penBlue, penAlpha ) );
1589  layoutItem->setFrameStrokeWidth( QgsLayoutMeasurement( penWidth ) );
1590  QPen framePen( layoutItem->frameStrokeColor() );
1591  framePen.setWidthF( layoutItem->frameStrokeWidth( ).length() );
1592  framePen.setJoinStyle( layoutItem->frameJoinStyle( ) );
1593  layoutItem->setPen( framePen );
1594  //apply any data defined settings
1595  layoutItem->refreshFrame( false );
1596  }
1597  }
1598 
1599  //brush
1600  QDomNodeList bgColorList = itemElem.elementsByTagName( QStringLiteral( "BackgroundColor" ) );
1601  if ( !bgColorList.isEmpty() )
1602  {
1603  QDomElement bgColorElem = bgColorList.at( 0 ).toElement();
1604  bool redOk, greenOk, blueOk, alphaOk;
1605  int bgRed, bgGreen, bgBlue, bgAlpha;
1606  bgRed = bgColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1607  bgGreen = bgColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1608  bgBlue = bgColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1609  bgAlpha = bgColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1610  if ( redOk && greenOk && blueOk && alphaOk )
1611  {
1612  layoutItem->mBackgroundColor = QColor( bgRed, bgGreen, bgBlue, bgAlpha );
1613  layoutItem->setBrush( QBrush( layoutItem->mBackgroundColor, Qt::SolidPattern ) );
1614  }
1615  //apply any data defined settings
1616  layoutItem->refreshBackgroundColor( false );
1617  }
1618 
1619  //blend mode
1620  layoutItem->setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( itemElem.attribute( QStringLiteral( "blendMode" ), QStringLiteral( "0" ) ).toUInt() ) ) );
1621 
1622  //opacity
1623  if ( itemElem.hasAttribute( QStringLiteral( "opacity" ) ) )
1624  {
1625  layoutItem->setItemOpacity( itemElem.attribute( QStringLiteral( "opacity" ), QStringLiteral( "1" ) ).toDouble() );
1626  }
1627  else
1628  {
1629  layoutItem->setItemOpacity( 1.0 - itemElem.attribute( QStringLiteral( "transparency" ), QStringLiteral( "0" ) ).toInt() / 100.0 );
1630  }
1631 
1632  layoutItem->mExcludeFromExports = itemElem.attribute( QStringLiteral( "excludeFromExports" ), QStringLiteral( "0" ) ).toInt();
1633  layoutItem->mEvaluatedExcludeFromExports = layoutItem->mExcludeFromExports;
1634 
1635  // positioning
1636  layoutItem->attemptSetSceneRect( position );
1637  //rotation
1638  layoutItem->setItemRotation( itemElem.attribute( QStringLiteral( "itemRotation" ), QStringLiteral( "0" ) ).toDouble(), false );
1639 
1640  layoutItem->mBlockUndoCommands = false;
1641 
1642  return true;
1643 }
1644 
1645 
1646 
1647 bool QgsCompositionConverter::readOldComposerObjectXml( QgsLayoutObject *layoutItem,
1648  const QDomElement &itemElem )
1649 {
1650  if ( itemElem.isNull() )
1651  {
1652  return false;
1653  }
1654 
1655  //old (pre 3.0) data defined properties
1656  QgsCompositionConverter::readOldDataDefinedPropertyMap( itemElem, layoutItem->mDataDefinedProperties );
1657 
1658  QDomNode propsNode = itemElem.namedItem( QStringLiteral( "dataDefinedProperties" ) );
1659  if ( !propsNode.isNull() )
1660  {
1661  layoutItem->mDataDefinedProperties.readXml( propsNode.toElement(), sPropertyDefinitions );
1662  }
1664  {
1665  // upgrade transparency -> opacity
1667  exp = QStringLiteral( "100.0 - (%1)" ).arg( exp );
1670  }
1671 
1672  //custom properties
1673  layoutItem->mCustomProperties.readXml( itemElem );
1674 
1675  return true;
1676 }
1677 
1678 
1679 void QgsCompositionConverter::readOldDataDefinedPropertyMap( const QDomElement &itemElem, QgsPropertyCollection &dataDefinedProperties )
1680 {
1681  const QgsPropertiesDefinition defs = QgsCompositionConverter::propertyDefinitions();
1682  QgsPropertiesDefinition::const_iterator i = defs.constBegin();
1683  for ( ; i != defs.constEnd(); ++i )
1684  {
1685  QString elemName = i.value().name();
1686  QDomNodeList ddNodeList = itemElem.elementsByTagName( elemName );
1687  if ( !ddNodeList.isEmpty() )
1688  {
1689  QDomElement ddElem = ddNodeList.at( 0 ).toElement();
1690  QgsProperty prop = readOldDataDefinedProperty( static_cast< QgsCompositionConverter::DataDefinedProperty >( i.key() ), ddElem );
1691  if ( prop )
1692  dataDefinedProperties.setProperty( i.key(), prop );
1693  }
1694  }
1695 }
1696 
1697 QgsProperty QgsCompositionConverter::readOldDataDefinedProperty( const QgsCompositionConverter::DataDefinedProperty property, const QDomElement &ddElem )
1698 {
1700  {
1701  //invalid property
1702  return QgsProperty();
1703  }
1704 
1705  QString active = ddElem.attribute( QStringLiteral( "active" ) );
1706  bool isActive = false;
1707  if ( active.compare( QStringLiteral( "true" ), Qt::CaseInsensitive ) == 0 )
1708  {
1709  isActive = true;
1710  }
1711  QString field = ddElem.attribute( QStringLiteral( "field" ) );
1712  QString expr = ddElem.attribute( QStringLiteral( "expr" ) );
1713 
1714  QString useExpr = ddElem.attribute( QStringLiteral( "useExpr" ) );
1715  bool isExpression = false;
1716  if ( useExpr.compare( QStringLiteral( "true" ), Qt::CaseInsensitive ) == 0 )
1717  {
1718  isExpression = true;
1719  }
1720 
1721  if ( isExpression )
1722  return QgsProperty::fromExpression( expr, isActive );
1723  else
1724  return QgsProperty::fromField( field, isActive );
1725 }
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 setBlendMode(const QPainter::CompositionMode mode)
Sets the item&#39;s composition blending mode.
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.
void setHorizontalGrid(const bool horizontalGrid)
Sets whether the grid&#39;s horizontal lines should be drawn in the table.
A rectangle specified with double values.
Definition: qgsrectangle.h:39
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 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 setLocked(const bool locked)
Sets whether the item is locked, preventing mouse interactions with the item.
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.
QPen pen() const
Returns the pen used for drawing outlines in the scalebar.
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
Return XML content of the style.
void readXml(const QDomElement &styleElement)
Read style configuration (for project file reading)
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:1103
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:1114
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.
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.
virtual void setVisibility(const bool visible)
Sets whether the item is visible.
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).
Composer legend components style.
void setFilterFeatures(bool filtered)
Sets whether features should be filtered in the coverage layer.
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...
static QString svgSymbolNameToPath(QString name, const QgsPathResolver &pathResolver)
Get SVG symbol&#39;s path from its name.
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 setShowGrid(const bool showGrid)
Sets whether grid lines should be drawn in the table.
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.
void setShowEmptyRows(const bool showEmpty)
Sets whether empty rows should be drawn.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:479
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:251
void setStyle(const QString &name)
Sets the scale bar style by name.
void setUserStylesheetEnabled(const bool enabled)
Sets whether user stylesheets are enabled for the HTML content.
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
void setVerticalGrid(const bool verticalGrid)
Sets whether the grid&#39;s vertical lines should be drawn in the table.
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.
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.
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.
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
Return path resolver object with considering whether the project uses absolute or relative paths and ...
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:1556
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 setEmptyTableBehavior(const EmptyTableMode mode)
Sets the behavior mode for empty tables with no content rows.
void setOffsetY(const double offset)
Sets the offset for grid lines in the y-direction.
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 an Atlas, iterating over geometry features.
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.
void setOffsetX(const double offset)
Sets the offset for grid lines in the x-direction.
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:82
void setFrameStyle(const FrameStyle style)
Sets the grid frame style.
A layout table subclass that displays attributes from a vector layer.
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.
void setHidePageIfEmpty(const bool hidePageIfEmpty)
Sets whether the page should be hidden (ie, not included in layout exports) if this frame is empty...
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.
void setHideBackgroundIfEmpty(const bool hideBackgroundIfEmpty)
Sets whether the background and frame stroke should be hidden if this frame is empty.
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.
Double value (including negative values)
Definition: qgsproperty.h:57
void setWrapString(const QString &string)
Sets the legend text wrapping string.
void setContentMode(ContentMode mode)
Sets the source mode for item&#39;s HTML content.
void setCellMargin(const double margin)
Sets the margin distance in mm between cell borders and their contents.
void setVectorLayer(QgsVectorLayer *layer)
Sets the vector layer from which to display feature attributes.
void setGridStrokeWidth(const double width)
Sets the width in mm for grid lines in the table.
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.
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 setAnnotationDirection(const AnnotationDirection direction, const BorderSide side)
Sets the direction for drawing frame annotations for the specified map side.
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.
void setAnnotationPrecision(const int precision)
Sets the coordinate precision for grid annotations.
Unknown distance unit.
Definition: qgsunittypes.h:54
void setHeaderHAlignment(const HeaderHAlignment alignment)
Sets the horizontal alignment for table headers.
void setFrameJoinStyle(const Qt::PenJoinStyle style)
Sets the join style used when drawing the item&#39;s frame.
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 setAnnotationPosition(const AnnotationPosition position, const BorderSide side)
Sets the position for the grid annotations on a specified side of the map frame.
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 setHeaderMode(const HeaderMode mode)
Sets the display mode for headers in the table.
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...
void loadHtml(const bool useCache=false, const QgsExpressionContext *context=nullptr)
Reloads the html source from the url and redraws the item.
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 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.
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 setStyle(const GridStyle style)
Sets the grid style, which controls how the grid is drawn over the map&#39;s contents.
void setBoxSpace(double space)
Sets the legend box space.
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 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.
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:445
void setLabelBarSpace(double space)
Sets the spacing (in millimeters) between labels and the scalebar.