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