LCOV - code coverage report
Current view: top level - core/layout - qgscompositionconverter.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 1 1120 0.1 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           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 : }

Generated by: LCOV version 1.14