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