Add a page collection to layouts, and start porting composer page items

This commit is contained in:
Nyall Dawson 2017-07-18 16:45:09 +10:00
parent 3cf06db467
commit 9df4a67d6d
13 changed files with 439 additions and 0 deletions

View File

@ -382,8 +382,10 @@
%Include layout/qgslayout.sip
%Include layout/qgslayoutitem.sip
%Include layout/qgslayoutitemmap.sip
%Include layout/qgslayoutitempage.sip
%Include layout/qgslayoutitemregistry.sip
%Include layout/qgslayoutitemshape.sip
%Include layout/qgslayoutpagecollection.sip
%Include layout/qgslayoutobject.sip
%Include symbology-ng/qgscptcityarchive.sip
%Include symbology-ng/qgssvgcache.sip

View File

@ -183,6 +183,13 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator
void setReferenceMap( QgsLayoutItemMap *map );
QgsLayoutPageCollection *pageCollection();
%Docstring
Returns a pointer to the layout's page collection, which stores and manages
page items in the layout.
:rtype: QgsLayoutPageCollection
%End
signals:
void variablesChanged();

View File

@ -0,0 +1,42 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgslayoutitempage.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsLayoutItemPage : QgsLayoutItem
{
%Docstring
Item representing the paper in a layout.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutitempage.h"
%End
public:
explicit QgsLayoutItemPage( QgsLayout *layout /TransferThis/ );
%Docstring
Constructor for QgsLayoutItemPage, with the specified parent ``layout``.
%End
virtual int type() const;
virtual QString stringType() const;
protected:
virtual void draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle = 0 );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgslayoutitempage.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -0,0 +1,58 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgslayoutpagecollection.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsLayoutPageCollection : QObject
{
%Docstring
A manager for a collection of pages in a layout.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutpagecollection.h"
%End
public:
explicit QgsLayoutPageCollection( QgsLayout *layout /TransferThis/ );
%Docstring
Constructor for QgsLayoutItemPage, with the specified parent ``layout``.
%End
QgsLayout *layout() const;
%Docstring
Returns the layout this collection belongs to.
:rtype: QgsLayout
%End
void setPageStyleSymbol( QgsFillSymbol *symbol );
%Docstring
Sets the ``symbol`` to use for drawing pages in the collection.
Ownership is not transferred, and a copy of the symbol is created internally.
.. seealso:: pageStyleSymbol()
%End
const QgsFillSymbol *pageStyleSymbol() const;
%Docstring
Returns the symbol to use for drawing pages in the collection.
.. seealso:: setPageStyleSymbol()
:rtype: QgsFillSymbol
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgslayoutpagecollection.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -353,11 +353,13 @@ SET(QGIS_CORE_SRCS
layout/qgslayoutcontext.cpp
layout/qgslayoutitem.cpp
layout/qgslayoutitemmap.cpp
layout/qgslayoutitempage.cpp
layout/qgslayoutitemregistry.cpp
layout/qgslayoutitemshape.cpp
layout/qgslayoutmeasurement.cpp
layout/qgslayoutmeasurementconverter.cpp
layout/qgslayoutobject.cpp
layout/qgslayoutpagecollection.cpp
layout/qgslayoututils.cpp
layout/qgspagesizeregistry.cpp
layout/qgslayoutpoint.cpp
@ -680,8 +682,10 @@ SET(QGIS_CORE_MOC_HDRS
layout/qgslayout.h
layout/qgslayoutitem.h
layout/qgslayoutitemmap.h
layout/qgslayoutitempage.h
layout/qgslayoutitemregistry.h
layout/qgslayoutitemshape.h
layout/qgslayoutpagecollection.h
layout/qgslayoutobject.h
symbology-ng/qgscptcityarchive.h

View File

@ -15,10 +15,12 @@
***************************************************************************/
#include "qgslayout.h"
#include "qgslayoutpagecollection.h"
QgsLayout::QgsLayout( QgsProject *project )
: QGraphicsScene()
, mProject( project )
, mPageCollection( new QgsLayoutPageCollection( this ) )
{}
QgsProject *QgsLayout::project() const
@ -103,3 +105,8 @@ void QgsLayout::setReferenceMap( QgsLayoutItemMap *map )
{
Q_UNUSED( map );
}
QgsLayoutPageCollection *QgsLayout::pageCollection()
{
return mPageCollection.get();
}

View File

@ -20,6 +20,7 @@
#include <QGraphicsScene>
#include "qgslayoutcontext.h"
#include "qgsexpressioncontextgenerator.h"
#include "qgslayoutpagecollection.h"
class QgsLayoutItemMap;
@ -203,6 +204,12 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
//TODO
void setReferenceMap( QgsLayoutItemMap *map );
/**
* Returns a pointer to the layout's page collection, which stores and manages
* page items in the layout.
*/
QgsLayoutPageCollection *pageCollection();
signals:
/**
@ -221,6 +228,8 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
QgsUnitTypes::LayoutUnit mUnits = QgsUnitTypes::LayoutMillimeters;
QgsLayoutContext mContext;
std::unique_ptr< QgsLayoutPageCollection > mPageCollection;
};
#endif //QGSLAYOUT_H

View File

@ -0,0 +1,83 @@
/***************************************************************************
qgslayoutitempage.cpp
---------------------
begin : July 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgslayoutitempage.h"
#include "qgslayout.h"
#include "qgslayoututils.h"
#include <QPainter>
QgsLayoutItemPage::QgsLayoutItemPage( QgsLayout *layout )
: QgsLayoutItem( layout )
{
}
void QgsLayoutItemPage::draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle )
{
#if 0
Q_UNUSED( itemStyle );
Q_UNUSED( pWidget );
if ( !painter || !mComposition || !mComposition->pagesVisible() )
{
return;
}
//setup painter scaling to dots so that raster symbology is drawn to scale
double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
//setup render context
QgsRenderContext context = QgsComposerUtils::createRenderContextForComposition( mComposition, painter );
context.setForceVectorOutput( true );
QgsExpressionContext expressionContext = createExpressionContext();
context.setExpressionContext( expressionContext );
painter->save();
if ( mComposition->plotStyle() == QgsComposition::Preview )
{
//if in preview mode, draw page border and shadow so that it's
//still possible to tell where pages with a transparent style begin and end
painter->setRenderHint( QPainter::Antialiasing, false );
//shadow
painter->setBrush( QBrush( QColor( 150, 150, 150 ) ) );
painter->setPen( Qt::NoPen );
painter->drawRect( QRectF( 1, 1, rect().width() + 1, rect().height() + 1 ) );
//page area
painter->setBrush( QColor( 215, 215, 215 ) );
QPen pagePen = QPen( QColor( 100, 100, 100 ), 0 );
pagePen.setCosmetic( true );
painter->setPen( pagePen );
painter->drawRect( QRectF( 0, 0, rect().width(), rect().height() ) );
}
painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
painter->setRenderHint( QPainter::Antialiasing );
mComposition->pageStyleSymbol()->startRender( context );
calculatePageMargin();
QPolygonF pagePolygon = QPolygonF( QRectF( mPageMargin * dotsPerMM, mPageMargin * dotsPerMM,
( rect().width() - 2 * mPageMargin ) * dotsPerMM, ( rect().height() - 2 * mPageMargin ) * dotsPerMM ) );
QList<QPolygonF> rings; //empty list
mComposition->pageStyleSymbol()->renderPolygon( pagePolygon, &rings, nullptr, context );
mComposition->pageStyleSymbol()->stopRender( context );
painter->restore();
#endif
}

View File

@ -0,0 +1,49 @@
/***************************************************************************
qgslayoutitempage.h
--------------------
begin : July 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSLAYOUTITEMPAGE_H
#define QGSLAYOUTITEMPAGE_H
#include "qgis_core.h"
#include "qgslayoutitem.h"
#include "qgslayoutitemregistry.h"
/**
* \ingroup core
* \class QgsLayoutItemPage
* \brief Item representing the paper in a layout.
* \since QGIS 3.0
*/
class CORE_EXPORT QgsLayoutItemPage : public QgsLayoutItem
{
Q_OBJECT
public:
/**
* Constructor for QgsLayoutItemPage, with the specified parent \a layout.
*/
explicit QgsLayoutItemPage( QgsLayout *layout SIP_TRANSFERTHIS );
int type() const override { return QgsLayoutItemRegistry::LayoutPage; }
QString stringType() const override { return QStringLiteral( "ItemPaper" ); }
protected:
void draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle = nullptr ) override;
};
#endif //QGSLAYOUTITEMPAGE_H

View File

@ -0,0 +1,48 @@
/***************************************************************************
qgslayoutpagecollection.cpp
----------------------------
begin : July 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgslayoutpagecollection.h"
#include "qgslayout.h"
QgsLayoutPageCollection::QgsLayoutPageCollection( QgsLayout *layout )
: QObject( layout )
, mLayout( layout )
{
createDefaultPageStyleSymbol();
}
void QgsLayoutPageCollection::setPageStyleSymbol( QgsFillSymbol *symbol )
{
if ( !symbol )
return;
mPageStyleSymbol.reset( static_cast<QgsFillSymbol *>( symbol->clone() ) );
}
QgsLayout *QgsLayoutPageCollection::layout() const
{
return mLayout;
}
void QgsLayoutPageCollection::createDefaultPageStyleSymbol()
{
QgsStringMap properties;
properties.insert( QStringLiteral( "color" ), QStringLiteral( "white" ) );
properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "no" ) );
properties.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
mPageStyleSymbol.reset( QgsFillSymbol::createSimple( properties ) );
}

View File

@ -0,0 +1,75 @@
/***************************************************************************
qgslayoutpagecollection.h
--------------------------
begin : July 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSLAYOUTPAGECOLLECTION_H
#define QGSLAYOUTPAGECOLLECTION_H
#include "qgis_core.h"
#include "qgis_sip.h"
#include "qgssymbol.h"
#include <QObject>
#include <memory>
class QgsLayout;
/**
* \ingroup core
* \class QgsLayoutPageCollection
* \brief A manager for a collection of pages in a layout.
* \since QGIS 3.0
*/
class CORE_EXPORT QgsLayoutPageCollection : public QObject
{
Q_OBJECT
public:
/**
* Constructor for QgsLayoutItemPage, with the specified parent \a layout.
*/
explicit QgsLayoutPageCollection( QgsLayout *layout SIP_TRANSFERTHIS );
/**
* Returns the layout this collection belongs to.
*/
QgsLayout *layout() const;
/**
* Sets the \a symbol to use for drawing pages in the collection.
*
* Ownership is not transferred, and a copy of the symbol is created internally.
* \see pageStyleSymbol()
*/
void setPageStyleSymbol( QgsFillSymbol *symbol );
/**
* Returns the symbol to use for drawing pages in the collection.
* \see setPageStyleSymbol()
*/
const QgsFillSymbol *pageStyleSymbol() const { return mPageStyleSymbol.get(); }
private:
QgsLayout *mLayout = nullptr;
//! Symbol for drawing pages
std::unique_ptr< QgsFillSymbol > mPageStyleSymbol;
void createDefaultPageStyleSymbol();
};
#endif //QGSLAYOUTPAGECOLLECTION_H

View File

@ -75,6 +75,7 @@ ADD_PYTHON_TEST(PyQgsLayerMetadata test_qgslayermetadata.py)
ADD_PYTHON_TEST(PyQgsLayerTreeMapCanvasBridge test_qgslayertreemapcanvasbridge.py)
ADD_PYTHON_TEST(PyQgsLayerTree test_qgslayertree.py)
ADD_PYTHON_TEST(PyQgsLayoutManager test_qgslayoutmanager.py)
ADD_PYTHON_TEST(PyQgsLayoutPageCollection test_qgslayoutpagecollection.py)
ADD_PYTHON_TEST(PyQgsLayoutView test_qgslayoutview.py)
ADD_PYTHON_TEST(PyQgsLayoutItemPropertiesDialog test_qgslayoutitempropertiesdialog.py)
ADD_PYTHON_TEST(PyQgsLayoutUnitsComboBox test_qgslayoutunitscombobox.py)

View File

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsLayoutPageCollection
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Nyall Dawson'
__date__ = '18/07/2017'
__copyright__ = 'Copyright 2017, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import qgis # NOQA
from qgis.core import QgsUnitTypes, QgsLayout, QgsProject, QgsLayoutPageCollection, QgsSimpleFillSymbolLayer, QgsFillSymbol
from qgis.PyQt.QtCore import Qt
from qgis.testing import start_app, unittest
start_app()
class TestQgsLayoutPageCollection(unittest.TestCase):
def testLayout(self):
# test that layouts have a collection
p = QgsProject()
l = QgsLayout(p)
self.assertTrue(l.pageCollection())
self.assertEqual(l.pageCollection().layout(), l)
def testSymbol(self):
"""
Test setting a page symbol for the collection
"""
p = QgsProject()
l = QgsLayout(p)
collection = l.pageCollection()
self.assertTrue(collection.pageStyleSymbol())
fill = QgsSimpleFillSymbolLayer()
fill_symbol = QgsFillSymbol()
fill_symbol.changeSymbolLayer(0, fill)
fill.setColor(Qt.green)
fill.setStrokeColor(Qt.red)
fill.setStrokeWidth(6)
collection.setPageStyleSymbol(fill_symbol)
self.assertEqual(collection.pageStyleSymbol().symbolLayer(0).color().name(), '#00ff00')
self.assertEqual(collection.pageStyleSymbol().symbolLayer(0).strokeColor().name(), '#ff0000')
if __name__ == '__main__':
unittest.main()