LCOV - code coverage report
Current view: top level - core/layout - qgslayoutpagecollection.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 440 0.0 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                               qgslayoutpagecollection.cpp
       3                 :            :                              ----------------------------
       4                 :            :     begin                : July 2017
       5                 :            :     copyright            : (C) 2017 by Nyall Dawson
       6                 :            :     email                : nyall dot dawson at gmail dot com
       7                 :            :  ***************************************************************************/
       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 "qgslayoutpagecollection.h"
      18                 :            : #include "qgslayout.h"
      19                 :            : #include "qgsreadwritecontext.h"
      20                 :            : #include "qgsproject.h"
      21                 :            : #include "qgslayoutitemundocommand.h"
      22                 :            : #include "qgssymbollayerutils.h"
      23                 :            : #include "qgslayoutframe.h"
      24                 :            : #include "qgslayoutundostack.h"
      25                 :            : 
      26                 :          0 : QgsLayoutPageCollection::QgsLayoutPageCollection( QgsLayout *layout )
      27                 :          0 :   : QObject( layout )
      28                 :          0 :   , mLayout( layout )
      29                 :          0 :   , mGuideCollection( new QgsLayoutGuideCollection( layout, this ) )
      30                 :          0 : {
      31                 :          0 :   createDefaultPageStyleSymbol();
      32                 :          0 : }
      33                 :            : 
      34                 :          0 : QgsLayoutPageCollection::~QgsLayoutPageCollection()
      35                 :          0 : {
      36                 :          0 :   const auto constMPages = mPages;
      37                 :          0 :   for ( QgsLayoutItemPage *page : constMPages )
      38                 :            :   {
      39                 :          0 :     mLayout->removeItem( page );
      40                 :          0 :     page->deleteLater();
      41                 :            :   }
      42                 :          0 : }
      43                 :            : 
      44                 :          0 : void QgsLayoutPageCollection::setPageStyleSymbol( QgsFillSymbol *symbol )
      45                 :            : {
      46                 :          0 :   if ( !symbol )
      47                 :          0 :     return;
      48                 :            : 
      49                 :          0 :   mPageStyleSymbol.reset( static_cast<QgsFillSymbol *>( symbol->clone() ) );
      50                 :            : 
      51                 :          0 :   for ( QgsLayoutItemPage *page : std::as_const( mPages ) )
      52                 :            :   {
      53                 :          0 :     page->setPageStyleSymbol( symbol->clone() );
      54                 :          0 :     page->update();
      55                 :            :   }
      56                 :          0 : }
      57                 :            : 
      58                 :          0 : const QgsFillSymbol *QgsLayoutPageCollection::pageStyleSymbol() const
      59                 :            : {
      60                 :          0 :   return mPageStyleSymbol.get();
      61                 :            : }
      62                 :            : 
      63                 :          0 : void QgsLayoutPageCollection::beginPageSizeChange()
      64                 :            : {
      65                 :          0 :   mPreviousItemPositions.clear();
      66                 :          0 :   QList< QgsLayoutItem * > items;
      67                 :          0 :   mLayout->layoutItems( items );
      68                 :            : 
      69                 :          0 :   for ( QgsLayoutItem *item : std::as_const( items ) )
      70                 :            :   {
      71                 :          0 :     if ( item->type() == QgsLayoutItemRegistry::LayoutPage )
      72                 :          0 :       continue;
      73                 :            : 
      74                 :          0 :     mPreviousItemPositions.insert( item->uuid(), qMakePair( item->page(), item->pagePositionWithUnits() ) );
      75                 :            :   }
      76                 :          0 : }
      77                 :            : 
      78                 :          0 : void QgsLayoutPageCollection::endPageSizeChange()
      79                 :            : {
      80                 :          0 :   for ( auto it = mPreviousItemPositions.constBegin(); it != mPreviousItemPositions.constEnd(); ++it )
      81                 :            :   {
      82                 :          0 :     if ( QgsLayoutItem *item = mLayout->itemByUuid( it.key() ) )
      83                 :            :     {
      84                 :          0 :       if ( !mBlockUndoCommands )
      85                 :          0 :         item->beginCommand( QString() );
      86                 :          0 :       item->attemptMove( it.value().second, true, false, it.value().first );
      87                 :          0 :       if ( !mBlockUndoCommands )
      88                 :          0 :         item->endCommand();
      89                 :          0 :     }
      90                 :          0 :   }
      91                 :          0 :   mPreviousItemPositions.clear();
      92                 :          0 : }
      93                 :            : 
      94                 :          0 : void QgsLayoutPageCollection::reflow()
      95                 :            : {
      96                 :          0 :   double currentY = 0;
      97                 :          0 :   QgsLayoutPoint p( 0, 0, mLayout->units() );
      98                 :          0 :   const auto constMPages = mPages;
      99                 :          0 :   for ( QgsLayoutItemPage *page : constMPages )
     100                 :            :   {
     101                 :          0 :     page->attemptMove( p );
     102                 :          0 :     currentY += mLayout->convertToLayoutUnits( page->pageSize() ).height() + spaceBetweenPages();
     103                 :          0 :     p.setY( currentY );
     104                 :            :   }
     105                 :          0 :   mLayout->guides().update();
     106                 :          0 :   mLayout->updateBounds();
     107                 :          0 :   emit changed();
     108                 :          0 : }
     109                 :            : 
     110                 :          0 : double QgsLayoutPageCollection::maximumPageWidth() const
     111                 :            : {
     112                 :          0 :   double maxWidth = 0;
     113                 :          0 :   for ( QgsLayoutItemPage *page : mPages )
     114                 :            :   {
     115                 :          0 :     maxWidth = std::max( maxWidth, mLayout->convertToLayoutUnits( page->pageSize() ).width() );
     116                 :            :   }
     117                 :          0 :   return maxWidth;
     118                 :            : }
     119                 :            : 
     120                 :          0 : QSizeF QgsLayoutPageCollection::maximumPageSize() const
     121                 :            : {
     122                 :          0 :   double maxArea = 0;
     123                 :          0 :   QSizeF maxSize;
     124                 :          0 :   for ( QgsLayoutItemPage *page : mPages )
     125                 :            :   {
     126                 :          0 :     QSizeF pageSize = mLayout->convertToLayoutUnits( page->pageSize() );
     127                 :          0 :     double area = pageSize.width() * pageSize.height();
     128                 :          0 :     if ( area > maxArea )
     129                 :            :     {
     130                 :          0 :       maxArea = area;
     131                 :          0 :       maxSize = pageSize;
     132                 :          0 :     }
     133                 :            :   }
     134                 :          0 :   return maxSize;
     135                 :            : }
     136                 :            : 
     137                 :          0 : bool QgsLayoutPageCollection::hasUniformPageSizes() const
     138                 :            : {
     139                 :          0 :   QSizeF size;
     140                 :          0 :   for ( QgsLayoutItemPage *page : mPages )
     141                 :            :   {
     142                 :          0 :     QSizeF pageSize = mLayout->convertToLayoutUnits( page->pageSize() );
     143                 :          0 :     if ( !size.isValid() )
     144                 :          0 :       size = pageSize;
     145                 :            :     else
     146                 :            :     {
     147                 :          0 :       if ( !qgsDoubleNear( pageSize.width(), size.width(), 0.01 )
     148                 :          0 :            || !qgsDoubleNear( pageSize.height(), size.height(), 0.01 ) )
     149                 :          0 :         return false;
     150                 :            :     }
     151                 :            :   }
     152                 :          0 :   return true;
     153                 :          0 : }
     154                 :            : 
     155                 :          0 : int QgsLayoutPageCollection::pageNumberForPoint( QPointF point ) const
     156                 :            : {
     157                 :          0 :   int pageNumber = 0;
     158                 :          0 :   double startNextPageY = 0;
     159                 :          0 :   const auto constMPages = mPages;
     160                 :          0 :   for ( QgsLayoutItemPage *page : constMPages )
     161                 :            :   {
     162                 :          0 :     startNextPageY += page->rect().height() + spaceBetweenPages();
     163                 :          0 :     if ( startNextPageY > point.y() )
     164                 :          0 :       break;
     165                 :          0 :     pageNumber++;
     166                 :            :   }
     167                 :            : 
     168                 :          0 :   if ( pageNumber > mPages.count() - 1 )
     169                 :          0 :     pageNumber = mPages.count() - 1;
     170                 :          0 :   return pageNumber;
     171                 :          0 : }
     172                 :            : 
     173                 :          0 : int QgsLayoutPageCollection::predictPageNumberForPoint( QPointF point ) const
     174                 :            : {
     175                 :          0 :   if ( mPages.empty() )
     176                 :          0 :     return 0;
     177                 :            : 
     178                 :          0 :   int pageNumber = 0;
     179                 :          0 :   double startNextPageY = 0;
     180                 :          0 :   const auto constMPages = mPages;
     181                 :          0 :   for ( QgsLayoutItemPage *page : constMPages )
     182                 :            :   {
     183                 :          0 :     startNextPageY += page->rect().height() + spaceBetweenPages();
     184                 :          0 :     if ( startNextPageY >= point.y() )
     185                 :          0 :       break;
     186                 :          0 :     pageNumber++;
     187                 :            :   }
     188                 :            : 
     189                 :          0 :   if ( startNextPageY >= point.y() )
     190                 :            :   {
     191                 :            :     // found an existing page
     192                 :          0 :     return pageNumber;
     193                 :            :   }
     194                 :            : 
     195                 :          0 :   double lastPageHeight = mPages.last()->rect().height();
     196                 :          0 :   while ( startNextPageY < point.y() )
     197                 :            :   {
     198                 :          0 :     startNextPageY += lastPageHeight + spaceBetweenPages();
     199                 :          0 :     if ( startNextPageY >= point.y() )
     200                 :          0 :       break;
     201                 :          0 :     pageNumber++;
     202                 :            :   }
     203                 :            : 
     204                 :          0 :   return pageNumber;
     205                 :          0 : }
     206                 :            : 
     207                 :          0 : QgsLayoutItemPage *QgsLayoutPageCollection::pageAtPoint( QPointF point ) const
     208                 :            : {
     209                 :          0 :   const QList< QGraphicsItem * > items = mLayout->items( point );
     210                 :          0 :   for ( QGraphicsItem *item : items )
     211                 :            :   {
     212                 :          0 :     if ( item->type() == QgsLayoutItemRegistry::LayoutPage )
     213                 :            :     {
     214                 :          0 :       QgsLayoutItemPage *page = static_cast< QgsLayoutItemPage * >( item );
     215                 :          0 :       if ( page->mapToScene( page->rect() ).boundingRect().contains( point ) )
     216                 :          0 :         return page;
     217                 :          0 :     }
     218                 :            :   }
     219                 :          0 :   return nullptr;
     220                 :          0 : }
     221                 :            : 
     222                 :          0 : QPointF QgsLayoutPageCollection::pagePositionToLayoutPosition( int page, const QgsLayoutPoint &position ) const
     223                 :            : {
     224                 :          0 :   QPointF layoutUnitsPos = mLayout->convertToLayoutUnits( position );
     225                 :          0 :   if ( page > 0 && page < mPages.count() )
     226                 :            :   {
     227                 :          0 :     layoutUnitsPos.ry() += mPages.at( page )->pos().y();
     228                 :          0 :   }
     229                 :          0 :   return layoutUnitsPos;
     230                 :            : }
     231                 :            : 
     232                 :          0 : QgsLayoutPoint QgsLayoutPageCollection::pagePositionToAbsolute( int page, const QgsLayoutPoint &position ) const
     233                 :            : {
     234                 :          0 :   double vDelta = 0.0;
     235                 :          0 :   if ( page > 0 && page < mPages.count() )
     236                 :            :   {
     237                 :          0 :     vDelta = mLayout->convertFromLayoutUnits( mPages.at( page )->pos().y(), position.units() ).length();
     238                 :          0 :   }
     239                 :            : 
     240                 :          0 :   return QgsLayoutPoint( position.x(), position.y() + vDelta, position.units() );
     241                 :            : }
     242                 :            : 
     243                 :          0 : QPointF QgsLayoutPageCollection::positionOnPage( QPointF position ) const
     244                 :            : {
     245                 :          0 :   double startCurrentPageY = 0;
     246                 :          0 :   double startNextPageY = 0;
     247                 :          0 :   int pageNumber = 0;
     248                 :          0 :   const auto constMPages = mPages;
     249                 :          0 :   for ( QgsLayoutItemPage *page : constMPages )
     250                 :            :   {
     251                 :          0 :     startCurrentPageY = startNextPageY;
     252                 :          0 :     startNextPageY += page->rect().height() + spaceBetweenPages();
     253                 :          0 :     if ( startNextPageY > position.y() )
     254                 :          0 :       break;
     255                 :          0 :     pageNumber++;
     256                 :            :   }
     257                 :            : 
     258                 :            :   double y;
     259                 :          0 :   if ( pageNumber == mPages.size() )
     260                 :            :   {
     261                 :            :     //y coordinate is greater then the end of the last page, so return distance between
     262                 :            :     //top of last page and y coordinate
     263                 :          0 :     y = position.y() - ( startNextPageY - spaceBetweenPages() );
     264                 :          0 :   }
     265                 :            :   else
     266                 :            :   {
     267                 :            :     //y coordinate is less then the end of the last page
     268                 :          0 :     y = position.y() - startCurrentPageY;
     269                 :            :   }
     270                 :          0 :   return QPointF( position.x(), y );
     271                 :          0 : }
     272                 :            : 
     273                 :          0 : double QgsLayoutPageCollection::spaceBetweenPages() const
     274                 :            : {
     275                 :          0 :   return mLayout->convertToLayoutUnits( QgsLayoutMeasurement( 10 ) );
     276                 :            : }
     277                 :            : 
     278                 :          0 : double QgsLayoutPageCollection::pageShadowWidth() const
     279                 :            : {
     280                 :          0 :   return spaceBetweenPages() / 2;
     281                 :            : }
     282                 :            : 
     283                 :          0 : void QgsLayoutPageCollection::resizeToContents( const QgsMargins &margins, QgsUnitTypes::LayoutUnit marginUnits )
     284                 :            : {
     285                 :            :   //calculate current bounds
     286                 :          0 :   QRectF bounds = mLayout->layoutBounds( true, 0.0 );
     287                 :          0 :   if ( bounds.isEmpty() )
     288                 :          0 :     return;
     289                 :            : 
     290                 :          0 :   if ( !mBlockUndoCommands )
     291                 :          0 :     mLayout->undoStack()->beginCommand( this, tr( "Resize to Contents" ) );
     292                 :            : 
     293                 :          0 :   for ( int page = mPages.count() - 1; page > 0; page-- )
     294                 :            :   {
     295                 :          0 :     deletePage( page );
     296                 :          0 :   }
     297                 :            : 
     298                 :          0 :   if ( mPages.empty() )
     299                 :            :   {
     300                 :          0 :     std::unique_ptr< QgsLayoutItemPage > page = std::make_unique< QgsLayoutItemPage >( mLayout );
     301                 :          0 :     addPage( page.release() );
     302                 :          0 :   }
     303                 :            : 
     304                 :          0 :   QgsLayoutItemPage *page = mPages.at( 0 );
     305                 :            : 
     306                 :          0 :   double marginLeft = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.left(), marginUnits ) );
     307                 :          0 :   double marginTop = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.top(), marginUnits ) );
     308                 :          0 :   double marginBottom = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.bottom(), marginUnits ) );
     309                 :          0 :   double marginRight = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.right(), marginUnits ) );
     310                 :            : 
     311                 :          0 :   bounds.setWidth( bounds.width() + marginLeft + marginRight );
     312                 :          0 :   bounds.setHeight( bounds.height() + marginTop + marginBottom );
     313                 :            : 
     314                 :          0 :   QgsLayoutSize newPageSize = mLayout->convertFromLayoutUnits( bounds.size(), mLayout->units() );
     315                 :          0 :   page->setPageSize( newPageSize );
     316                 :            : 
     317                 :          0 :   reflow();
     318                 :            : 
     319                 :            :   //also move all items so that top-left of bounds is at marginLeft, marginTop
     320                 :          0 :   double diffX = marginLeft - bounds.left();
     321                 :          0 :   double diffY = marginTop - bounds.top();
     322                 :            : 
     323                 :          0 :   const QList<QGraphicsItem *> itemList = mLayout->items();
     324                 :          0 :   for ( QGraphicsItem *item : itemList )
     325                 :            :   {
     326                 :          0 :     if ( QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item ) )
     327                 :            :     {
     328                 :          0 :       QgsLayoutItemPage *pageItem = dynamic_cast<QgsLayoutItemPage *>( layoutItem );
     329                 :          0 :       if ( !pageItem )
     330                 :            :       {
     331                 :          0 :         layoutItem->beginCommand( tr( "Move Item" ) );
     332                 :          0 :         layoutItem->attemptMoveBy( diffX, diffY );
     333                 :          0 :         layoutItem->endCommand();
     334                 :          0 :       }
     335                 :          0 :     }
     336                 :            :   }
     337                 :            : 
     338                 :            :   //also move guides
     339                 :          0 :   mLayout->undoStack()->beginCommand( &mLayout->guides(), tr( "Move Guides" ) );
     340                 :          0 :   const QList< QgsLayoutGuide * > verticalGuides = mLayout->guides().guides( Qt::Vertical );
     341                 :          0 :   for ( QgsLayoutGuide *guide : verticalGuides )
     342                 :            :   {
     343                 :          0 :     guide->setLayoutPosition( guide->layoutPosition() + diffX );
     344                 :            :   }
     345                 :          0 :   const QList< QgsLayoutGuide * > horizontalGuides = mLayout->guides().guides( Qt::Horizontal );
     346                 :          0 :   for ( QgsLayoutGuide *guide : horizontalGuides )
     347                 :            :   {
     348                 :          0 :     guide->setLayoutPosition( guide->layoutPosition() + diffY );
     349                 :            :   }
     350                 :          0 :   mLayout->undoStack()->endCommand();
     351                 :            : 
     352                 :          0 :   if ( !mBlockUndoCommands )
     353                 :          0 :     mLayout->undoStack()->endCommand();
     354                 :          0 : }
     355                 :            : 
     356                 :          0 : bool QgsLayoutPageCollection::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const
     357                 :            : {
     358                 :          0 :   QDomElement element = document.createElement( QStringLiteral( "PageCollection" ) );
     359                 :            : 
     360                 :          0 :   QDomElement pageStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mPageStyleSymbol.get(), document, context );
     361                 :          0 :   element.appendChild( pageStyleElem );
     362                 :            : 
     363                 :          0 :   for ( const QgsLayoutItemPage *page : mPages )
     364                 :            :   {
     365                 :          0 :     page->writeXml( element, document, context );
     366                 :            :   }
     367                 :            : 
     368                 :          0 :   mGuideCollection->writeXml( element, document, context );
     369                 :            : 
     370                 :          0 :   parentElement.appendChild( element );
     371                 :            :   return true;
     372                 :          0 : }
     373                 :            : 
     374                 :          0 : bool QgsLayoutPageCollection::readXml( const QDomElement &e, const QDomDocument &document, const QgsReadWriteContext &context )
     375                 :            : {
     376                 :          0 :   QDomElement element = e;
     377                 :          0 :   if ( element.nodeName() != QLatin1String( "PageCollection" ) )
     378                 :            :   {
     379                 :          0 :     element = element.firstChildElement( QStringLiteral( "PageCollection" ) );
     380                 :          0 :   }
     381                 :            : 
     382                 :          0 :   if ( element.nodeName() != QLatin1String( "PageCollection" ) )
     383                 :            :   {
     384                 :          0 :     return false;
     385                 :            :   }
     386                 :            : 
     387                 :          0 :   mBlockUndoCommands = true;
     388                 :            : 
     389                 :          0 :   int i = 0;
     390                 :          0 :   for ( QgsLayoutItemPage *page : std::as_const( mPages ) )
     391                 :            :   {
     392                 :          0 :     emit pageAboutToBeRemoved( i );
     393                 :          0 :     mLayout->removeItem( page );
     394                 :          0 :     page->deleteLater();
     395                 :          0 :     ++i;
     396                 :            :   }
     397                 :          0 :   mPages.clear();
     398                 :            : 
     399                 :          0 :   QDomElement pageStyleSymbolElem = element.firstChildElement( QStringLiteral( "symbol" ) );
     400                 :          0 :   if ( !pageStyleSymbolElem.isNull() )
     401                 :            :   {
     402                 :          0 :     mPageStyleSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( pageStyleSymbolElem, context ) );
     403                 :          0 :   }
     404                 :            : 
     405                 :          0 :   QDomNodeList pageList = element.elementsByTagName( QStringLiteral( "LayoutItem" ) );
     406                 :          0 :   for ( int i = 0; i < pageList.size(); ++i )
     407                 :            :   {
     408                 :          0 :     QDomElement pageElement = pageList.at( i ).toElement();
     409                 :          0 :     std::unique_ptr< QgsLayoutItemPage > page( new QgsLayoutItemPage( mLayout ) );
     410                 :          0 :     if ( mPageStyleSymbol )
     411                 :          0 :       page->setPageStyleSymbol( mPageStyleSymbol->clone() );
     412                 :          0 :     page->readXml( pageElement, document, context );
     413                 :          0 :     page->finalizeRestoreFromXml();
     414                 :          0 :     mPages.append( page.get() );
     415                 :          0 :     mLayout->addItem( page.release() );
     416                 :          0 :   }
     417                 :            : 
     418                 :          0 :   reflow();
     419                 :            : 
     420                 :          0 :   mGuideCollection->readXml( element, document, context );
     421                 :            : 
     422                 :          0 :   mBlockUndoCommands = false;
     423                 :          0 :   return true;
     424                 :          0 : }
     425                 :          0 : 
     426                 :          0 : QgsLayoutGuideCollection &QgsLayoutPageCollection::guides()
     427                 :            : {
     428                 :          0 :   return *mGuideCollection;
     429                 :            : }
     430                 :            : 
     431                 :          0 : const QgsLayoutGuideCollection &QgsLayoutPageCollection::guides() const
     432                 :            : {
     433                 :          0 :   return *mGuideCollection;
     434                 :            : }
     435                 :            : 
     436                 :          0 : void QgsLayoutPageCollection::redraw()
     437                 :            : {
     438                 :          0 :   const auto constMPages = mPages;
     439                 :          0 :   for ( QgsLayoutItemPage *page : constMPages )
     440                 :            :   {
     441                 :          0 :     page->redraw();
     442                 :            :   }
     443                 :          0 : }
     444                 :            : 
     445                 :          0 : QgsLayout *QgsLayoutPageCollection::layout()
     446                 :            : {
     447                 :          0 :   return mLayout;
     448                 :            : }
     449                 :            : 
     450                 :          0 : QList<QgsLayoutItemPage *> QgsLayoutPageCollection::pages()
     451                 :            : {
     452                 :          0 :   return mPages;
     453                 :            : }
     454                 :            : 
     455                 :          0 : int QgsLayoutPageCollection::pageCount() const
     456                 :            : {
     457                 :          0 :   return mPages.count();
     458                 :            : }
     459                 :            : 
     460                 :          0 : QgsLayoutItemPage *QgsLayoutPageCollection::page( int pageNumber )
     461                 :            : {
     462                 :          0 :   return mPages.value( pageNumber );
     463                 :            : }
     464                 :            : 
     465                 :          0 : const QgsLayoutItemPage *QgsLayoutPageCollection::page( int pageNumber ) const
     466                 :            : {
     467                 :          0 :   return mPages.value( pageNumber );
     468                 :            : }
     469                 :            : 
     470                 :          0 : int QgsLayoutPageCollection::pageNumber( QgsLayoutItemPage *page ) const
     471                 :            : {
     472                 :          0 :   return mPages.indexOf( page );
     473                 :            : }
     474                 :            : 
     475                 :          0 : QList<QgsLayoutItemPage *> QgsLayoutPageCollection::visiblePages( const QRectF &region ) const
     476                 :            : {
     477                 :          0 :   QList<QgsLayoutItemPage *> pages;
     478                 :          0 :   const auto constMPages = mPages;
     479                 :          0 :   for ( QgsLayoutItemPage *page : constMPages )
     480                 :            :   {
     481                 :          0 :     if ( page->mapToScene( page->rect() ).boundingRect().intersects( region ) )
     482                 :          0 :       pages << page;
     483                 :            :   }
     484                 :          0 :   return pages;
     485                 :          0 : }
     486                 :            : 
     487                 :          0 : QList<int> QgsLayoutPageCollection::visiblePageNumbers( const QRectF &region ) const
     488                 :            : {
     489                 :          0 :   QList< int > pages;
     490                 :          0 :   int p = 0;
     491                 :          0 :   const auto constMPages = mPages;
     492                 :          0 :   for ( QgsLayoutItemPage *page : constMPages )
     493                 :            :   {
     494                 :          0 :     if ( page->mapToScene( page->rect() ).boundingRect().intersects( region ) )
     495                 :          0 :       pages << p;
     496                 :          0 :     p++;
     497                 :            :   }
     498                 :          0 :   return pages;
     499                 :          0 : }
     500                 :            : 
     501                 :          0 : bool QgsLayoutPageCollection::pageIsEmpty( int page ) const
     502                 :            : {
     503                 :            :   //get all items on page
     504                 :          0 :   const QList<QgsLayoutItem *> items = mLayout->pageCollection()->itemsOnPage( page );
     505                 :            : 
     506                 :            :   //loop through and check for non-paper items
     507                 :          0 :   for ( QgsLayoutItem *item : items )
     508                 :            :   {
     509                 :            :     //is item a paper item?
     510                 :          0 :     if ( item->type() != QgsLayoutItemRegistry::LayoutPage )
     511                 :            :     {
     512                 :            :       //item is not a paper item, so we have other items on the page
     513                 :          0 :       return false;
     514                 :            :     }
     515                 :            :   }
     516                 :            :   //no non-paper items
     517                 :          0 :   return true;
     518                 :          0 : }
     519                 :            : 
     520                 :          0 : QList<QgsLayoutItem *> QgsLayoutPageCollection::itemsOnPage( int page ) const
     521                 :            : {
     522                 :          0 :   QList<QgsLayoutItem *> itemList;
     523                 :          0 :   const QList<QGraphicsItem *> graphicsItemList = mLayout->items();
     524                 :          0 :   itemList.reserve( graphicsItemList.size() );
     525                 :          0 :   for ( QGraphicsItem *graphicsItem : graphicsItemList )
     526                 :            :   {
     527                 :          0 :     QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
     528                 :          0 :     if ( item && item->page() == page )
     529                 :            :     {
     530                 :          0 :       itemList.push_back( item );
     531                 :          0 :     }
     532                 :            :   }
     533                 :          0 :   return itemList;
     534                 :          0 : }
     535                 :            : 
     536                 :          0 : bool QgsLayoutPageCollection::shouldExportPage( int page ) const
     537                 :            : {
     538                 :          0 :   if ( page >= mPages.count() || page < 0 )
     539                 :            :   {
     540                 :            :     //page number out of range, of course we shouldn't export it - stop smoking crack!
     541                 :          0 :     return false;
     542                 :            :   }
     543                 :            : 
     544                 :          0 :   QgsLayoutItemPage *pageItem = mPages.at( page );
     545                 :          0 :   if ( !pageItem->shouldDrawItem() )
     546                 :          0 :     return false;
     547                 :            : 
     548                 :            :   //check all frame items on page
     549                 :          0 :   QList<QgsLayoutFrame *> frames;
     550                 :          0 :   itemsOnPage( frames, page );
     551                 :          0 :   for ( QgsLayoutFrame *frame : std::as_const( frames ) )
     552                 :            :   {
     553                 :          0 :     if ( frame->hidePageIfEmpty() && frame->isEmpty() )
     554                 :            :     {
     555                 :            :       //frame is set to hide page if empty, and frame is empty, so we don't want to export this page
     556                 :          0 :       return false;
     557                 :            :     }
     558                 :            :   }
     559                 :          0 :   return true;
     560                 :          0 : }
     561                 :            : 
     562                 :          0 : void QgsLayoutPageCollection::addPage( QgsLayoutItemPage *page )
     563                 :            : {
     564                 :          0 :   if ( !mBlockUndoCommands )
     565                 :          0 :     mLayout->undoStack()->beginCommand( this, tr( "Add Page" ) );
     566                 :          0 :   mPages.append( page );
     567                 :          0 :   mLayout->addItem( page );
     568                 :          0 :   reflow();
     569                 :          0 :   if ( !mBlockUndoCommands )
     570                 :          0 :     mLayout->undoStack()->endCommand();
     571                 :          0 : }
     572                 :            : 
     573                 :          0 : QgsLayoutItemPage *QgsLayoutPageCollection::extendByNewPage()
     574                 :            : {
     575                 :          0 :   if ( mPages.empty() )
     576                 :          0 :     return nullptr;
     577                 :            : 
     578                 :          0 :   QgsLayoutItemPage *lastPage = mPages.at( mPages.count() - 1 );
     579                 :          0 :   std::unique_ptr< QgsLayoutItemPage > newPage = std::make_unique< QgsLayoutItemPage >( mLayout );
     580                 :          0 :   newPage->attemptResize( lastPage->sizeWithUnits() );
     581                 :          0 :   addPage( newPage.release() );
     582                 :          0 :   return mPages.at( mPages.count() - 1 );
     583                 :          0 : }
     584                 :            : 
     585                 :          0 : void QgsLayoutPageCollection::insertPage( QgsLayoutItemPage *page, int beforePage )
     586                 :            : {
     587                 :          0 :   if ( !mBlockUndoCommands )
     588                 :            :   {
     589                 :          0 :     mLayout->undoStack()->beginMacro( tr( "Add Page" ) );
     590                 :          0 :     mLayout->undoStack()->beginCommand( this, tr( "Add Page" ) );
     591                 :          0 :   }
     592                 :            : 
     593                 :          0 :   if ( beforePage < 0 )
     594                 :          0 :     beforePage = 0;
     595                 :            : 
     596                 :          0 :   beginPageSizeChange();
     597                 :          0 :   if ( beforePage >= mPages.count() )
     598                 :            :   {
     599                 :          0 :     mPages.append( page );
     600                 :          0 :   }
     601                 :            :   else
     602                 :            :   {
     603                 :          0 :     mPages.insert( beforePage, page );
     604                 :            :   }
     605                 :          0 :   mLayout->addItem( page );
     606                 :          0 :   reflow();
     607                 :            : 
     608                 :            :   // bump up stored page numbers to account
     609                 :          0 :   for ( auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it ) // clazy:exclude=detaching-member
     610                 :            :   {
     611                 :          0 :     if ( it.value().first < beforePage )
     612                 :          0 :       continue;
     613                 :            : 
     614                 :          0 :     it.value().first = it.value().first + 1;
     615                 :          0 :   }
     616                 :            : 
     617                 :          0 :   endPageSizeChange();
     618                 :          0 :   if ( ! mBlockUndoCommands )
     619                 :            :   {
     620                 :          0 :     mLayout->undoStack()->endCommand();
     621                 :          0 :     mLayout->undoStack()->endMacro();
     622                 :          0 :   }
     623                 :          0 : }
     624                 :            : 
     625                 :          0 : void QgsLayoutPageCollection::deletePage( int pageNumber )
     626                 :            : {
     627                 :          0 :   if ( pageNumber < 0 || pageNumber >= mPages.count() )
     628                 :          0 :     return;
     629                 :            : 
     630                 :          0 :   if ( !mBlockUndoCommands )
     631                 :            :   {
     632                 :          0 :     mLayout->undoStack()->beginMacro( tr( "Remove Page" ) );
     633                 :          0 :     mLayout->undoStack()->beginCommand( this, tr( "Remove Page" ) );
     634                 :          0 :   }
     635                 :          0 :   emit pageAboutToBeRemoved( pageNumber );
     636                 :          0 :   beginPageSizeChange();
     637                 :          0 :   QgsLayoutItemPage *page = mPages.takeAt( pageNumber );
     638                 :          0 :   mLayout->removeItem( page );
     639                 :          0 :   page->deleteLater();
     640                 :          0 :   reflow();
     641                 :            : 
     642                 :            :   // bump stored page numbers to account
     643                 :          0 :   for ( auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it ) // clazy:exclude=detaching-member
     644                 :            :   {
     645                 :          0 :     if ( it.value().first <= pageNumber )
     646                 :          0 :       continue;
     647                 :            : 
     648                 :          0 :     it.value().first = it.value().first - 1;
     649                 :          0 :   }
     650                 :            : 
     651                 :          0 :   endPageSizeChange();
     652                 :          0 :   if ( ! mBlockUndoCommands )
     653                 :            :   {
     654                 :          0 :     mLayout->undoStack()->endCommand();
     655                 :          0 :     mLayout->undoStack()->endMacro();
     656                 :          0 :   }
     657                 :          0 : }
     658                 :            : 
     659                 :          0 : void QgsLayoutPageCollection::deletePage( QgsLayoutItemPage *page )
     660                 :            : {
     661                 :          0 :   if ( !mPages.contains( page ) )
     662                 :          0 :     return;
     663                 :            : 
     664                 :          0 :   if ( !mBlockUndoCommands )
     665                 :            :   {
     666                 :          0 :     mLayout->undoStack()->beginMacro( tr( "Remove Page" ) );
     667                 :          0 :     mLayout->undoStack()->beginCommand( this, tr( "Remove Page" ) );
     668                 :          0 :   }
     669                 :          0 :   int pageIndex = mPages.indexOf( page );
     670                 :          0 :   emit pageAboutToBeRemoved( pageIndex );
     671                 :          0 :   beginPageSizeChange();
     672                 :          0 :   mPages.removeAll( page );
     673                 :          0 :   page->deleteLater();
     674                 :            :   // remove immediately from scene -- otherwise immediately calculation of layout bounds (such as is done
     675                 :            :   // in reflow) will still consider the page, at least until it's actually deleted at the next event loop
     676                 :          0 :   mLayout->removeItem( page );
     677                 :          0 :   reflow();
     678                 :            : 
     679                 :            :   // bump stored page numbers to account
     680                 :          0 :   for ( auto it = mPreviousItemPositions.begin(); it != mPreviousItemPositions.end(); ++it ) // clazy:exclude=detaching-member
     681                 :            :   {
     682                 :          0 :     if ( it.value().first <= pageIndex )
     683                 :          0 :       continue;
     684                 :            : 
     685                 :          0 :     it.value().first = it.value().first - 1;
     686                 :          0 :   }
     687                 :            : 
     688                 :          0 :   endPageSizeChange();
     689                 :          0 :   if ( !mBlockUndoCommands )
     690                 :            :   {
     691                 :          0 :     mLayout->undoStack()->endCommand();
     692                 :          0 :     mLayout->undoStack()->endMacro();
     693                 :          0 :   }
     694                 :          0 : }
     695                 :            : 
     696                 :          0 : void QgsLayoutPageCollection::clear()
     697                 :            : {
     698                 :          0 :   if ( !mBlockUndoCommands )
     699                 :            :   {
     700                 :          0 :     mLayout->undoStack()->beginMacro( tr( "Remove Pages" ) );
     701                 :          0 :     mLayout->undoStack()->beginCommand( this, tr( "Remove Pages" ) );
     702                 :          0 :   }
     703                 :          0 :   for ( int i = mPages.count() - 1;  i >= 0; --i )
     704                 :            :   {
     705                 :          0 :     emit pageAboutToBeRemoved( i );
     706                 :          0 :     mPages.takeAt( i )->deleteLater();
     707                 :          0 :   }
     708                 :          0 :   reflow();
     709                 :          0 :   if ( !mBlockUndoCommands )
     710                 :            :   {
     711                 :          0 :     mLayout->undoStack()->endCommand();
     712                 :          0 :     mLayout->undoStack()->endMacro();
     713                 :          0 :   }
     714                 :          0 : }
     715                 :            : 
     716                 :          0 : QgsLayoutItemPage *QgsLayoutPageCollection::takePage( QgsLayoutItemPage *page )
     717                 :            : {
     718                 :          0 :   mPages.removeAll( page );
     719                 :          0 :   return page;
     720                 :            : }
     721                 :            : 
     722                 :          0 : void QgsLayoutPageCollection::createDefaultPageStyleSymbol()
     723                 :            : {
     724                 :          0 :   QVariantMap properties;
     725                 :          0 :   properties.insert( QStringLiteral( "color" ), QStringLiteral( "white" ) );
     726                 :          0 :   properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
     727                 :          0 :   properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "no" ) );
     728                 :          0 :   properties.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
     729                 :          0 :   mPageStyleSymbol.reset( QgsFillSymbol::createSimple( properties ) );
     730                 :          0 : }
     731                 :            : 

Generated by: LCOV version 1.14