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