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