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