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