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