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