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