Skip to content

Commit

Permalink
[composer] Attach compositions to QgsProject
Browse files Browse the repository at this point in the history
This adds a new QgsLayoutManager class which is used for
storage and serializing/deserializing of compositions.

A QgsLayoutManager is attached to QgsProject. This allows
core code to access the compositions attached to a project.
The intention is to move all handling of compositions from
app to core, making it easy for server to access project
compositions without resorting to fragile xml parsing.
  • Loading branch information
nyalldawson committed Mar 21, 2017
1 parent 63f7bee commit 3a1ac1a
Show file tree
Hide file tree
Showing 13 changed files with 554 additions and 20 deletions.
27 changes: 27 additions & 0 deletions python/core/composer/qgslayoutmanager.sip
@@ -0,0 +1,27 @@

class QgsLayoutManager : QObject
{
%TypeHeaderCode
#include <qgslayoutmanager.h>
%End
public:

explicit QgsLayoutManager( QgsProject* project = 0 );

~QgsLayoutManager();
bool addComposition( QgsComposition* composition /Transfer/ );
bool removeComposition( QgsComposition* composition );

void clear();
QList< QgsComposition* > compositions() const;
QgsComposition* compositionByName( const QString& name ) const;
bool readXml( const QDomElement& element, const QDomDocument& doc );
QDomElement writeXml( QDomDocument& doc ) const;

signals:
void compositionAdded( const QString& name );
void compositionRemoved( const QString& name );
void compositionAboutToBeRemoved( const QString& name );

};

1 change: 1 addition & 0 deletions python/core/core.sip
Expand Up @@ -225,6 +225,7 @@
%Include composer/qgscomposerutils.sip
%Include composer/qgscomposition.sip
%Include composer/qgsdoubleboxscalebarstyle.sip
%Include composer/qgslayoutmanager.sip
%Include composer/qgsnumericscalebarstyle.sip
%Include composer/qgspaperitem.sip
%Include composer/qgsscalebarstyle.sip
Expand Down
4 changes: 0 additions & 4 deletions src/app/composer/qgscomposer.h
Expand Up @@ -143,10 +143,6 @@ class QgsComposer: public QMainWindow, private Ui::QgsComposerBase
//! Is emitted every time the view zoom has changed
void zoomLevelChanged();

void composerAdded( QgsComposerView *v );
//!Composer deletes the old composerview when loading a template
void composerWillBeRemoved( QgsComposerView *v );

//! Is emitted when the atlas preview feature changes
void atlasPreviewFeatureChanged();

Expand Down
5 changes: 3 additions & 2 deletions src/app/composer/qgscomposermanager.cpp
Expand Up @@ -22,6 +22,7 @@
#include "qgscomposition.h"
#include "qgslogger.h"
#include "qgssettings.h"
#include "qgscomposerview.h"

#include <QDesktopServices>
#include <QDialog>
Expand All @@ -42,8 +43,8 @@ QgsComposerManager::QgsComposerManager( QWidget *parent, Qt::WindowFlags f ): QD
mComposerListWidget->setItemDelegate( new QgsComposerNameDelegate( mComposerListWidget ) );

connect( mButtonBox, SIGNAL( rejected() ), this, SLOT( close() ) );
connect( QgisApp::instance(), SIGNAL( composerAdded( QgsComposerView * ) ), this, SLOT( refreshComposers() ) );
connect( QgisApp::instance(), SIGNAL( composerRemoved( QgsComposerView * ) ), this, SLOT( refreshComposers() ) );
connect( QgisApp::instance(), &QgisApp::composerAdded, this, &QgsComposerManager::refreshComposers );
connect( QgisApp::instance(), &QgisApp::composerRemoved, this, &QgsComposerManager::refreshComposers );

connect( mComposerListWidget, SIGNAL( itemSelectionChanged() ), this, SLOT( toggleButtons() ) );

Expand Down
7 changes: 0 additions & 7 deletions src/app/qgisapp.cpp
Expand Up @@ -6988,11 +6988,7 @@ QgsComposer *QgisApp::createNewComposer( QString title )
mPrintComposersMenu->addAction( newComposerObject->windowAction() );
newComposerObject->open();
emit composerAdded( newComposerObject->view() );
connect( newComposerObject, &QgsComposer::composerAdded, this, &QgisApp::composerAdded );
connect( newComposerObject, &QgsComposer::composerWillBeRemoved, this, &QgisApp::composerWillBeRemoved );
connect( newComposerObject, &QgsComposer::atlasPreviewFeatureChanged, this, &QgisApp::refreshMapCanvas );
connect( mLayerTreeCanvasBridge, &QgsLayerTreeMapCanvasBridge::canvasLayersChanged, newComposerObject, &QgsComposer::onCanvasLayersChanged );

markDirty();
return newComposerObject;
}
Expand Down Expand Up @@ -7092,10 +7088,7 @@ bool QgisApp::loadComposersFromProject( const QDomDocument &doc )
composerView->updateRulers();
}
emit composerAdded( composer->view() );
connect( composer, &QgsComposer::composerAdded, this, &QgisApp::composerAdded );
connect( composer, &QgsComposer::composerWillBeRemoved, this, &QgisApp::composerWillBeRemoved );
connect( composer, &QgsComposer::atlasPreviewFeatureChanged, this, &QgisApp::refreshMapCanvas );
connect( mLayerTreeCanvasBridge, &QgsLayerTreeMapCanvasBridge::canvasLayersChanged, composer, &QgsComposer::onCanvasLayersChanged );

QgsDebugMsg( QString( "Loaded composer %1: %2ms" ).arg( title ).arg( t.elapsed() ) );
}
Expand Down
9 changes: 3 additions & 6 deletions src/app/qgisappinterface.cpp
Expand Up @@ -55,12 +55,9 @@ QgisAppInterface::QgisAppInterface( QgisApp *_qgis )
this, SIGNAL( currentLayerChanged( QgsMapLayer * ) ) );
connect( qgis, SIGNAL( currentThemeChanged( QString ) ),
this, SIGNAL( currentThemeChanged( QString ) ) );
connect( qgis, SIGNAL( composerAdded( QgsComposerView * ) ),
this, SIGNAL( composerAdded( QgsComposerView * ) ) );
connect( qgis, SIGNAL( composerWillBeRemoved( QgsComposerView * ) ),
this, SIGNAL( composerWillBeRemoved( QgsComposerView * ) ) );
connect( qgis, SIGNAL( composerRemoved( QgsComposerView * ) ),
this, SIGNAL( composerRemoved( QgsComposerView * ) ) );
connect( qgis, &QgisApp::composerAdded, this, &QgisAppInterface::composerAdded );
connect( qgis, &QgisApp::composerWillBeRemoved, this, &QgisAppInterface::composerWillBeRemoved );
connect( qgis, &QgisApp::composerRemoved, this, &QgisAppInterface::composerRemoved );
connect( qgis, SIGNAL( initializationCompleted() ),
this, SIGNAL( initializationCompleted() ) );
connect( qgis, SIGNAL( newProject() ),
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -297,6 +297,7 @@ SET(QGIS_CORE_SRCS
composer/qgscomposition.cpp
composer/qgsdoubleboxscalebarstyle.cpp
composer/qgsgroupungroupitemscommand.cpp
composer/qgslayoutmanager.cpp
composer/qgsnumericscalebarstyle.cpp
composer/qgspaperitem.cpp
composer/qgsscalebarstyle.cpp
Expand Down Expand Up @@ -585,6 +586,7 @@ SET(QGIS_CORE_MOC_HDRS
composer/qgscomposertexttable.h
composer/qgscomposition.h
composer/qgsgroupungroupitemscommand.h
composer/qgslayoutmanager.h
composer/qgspaperitem.h

processing/qgsprocessingfeedback.h
Expand Down
160 changes: 160 additions & 0 deletions src/core/composer/qgslayoutmanager.cpp
@@ -0,0 +1,160 @@
/***************************************************************************
qgslayoutmanager.cpp
--------------------
Date : January 2017
Copyright : (C) 2017 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 "qgslayoutmanager.h"
#include "qgsproject.h"

QgsLayoutManager::QgsLayoutManager( QgsProject *project )
: QObject( project )
, mProject( project )
{

}

QgsLayoutManager::~QgsLayoutManager()
{
clear();
}

bool QgsLayoutManager::addComposition( QgsComposition *composition )
{
if ( !composition )
return false;

// check for duplicate name
Q_FOREACH ( QgsComposition *c, mCompositions )
{
if ( c->name() == composition->name() )
return false;
}

mCompositions << composition;
emit compositionAdded( composition->name() );
mProject->setDirty( true );
return true;
}

bool QgsLayoutManager::removeComposition( QgsComposition *composition )
{
if ( !composition )
return false;

if ( !mCompositions.contains( composition ) )
return false;

QString name = composition->name();
emit compositionAboutToBeRemoved( name );
mCompositions.removeAll( composition );
delete composition;
emit compositionRemoved( name );
mProject->setDirty( true );
return true;
}

void QgsLayoutManager::clear()
{
Q_FOREACH ( QgsComposition *c, mCompositions )
{
removeComposition( c );
}
}

QList<QgsComposition *> QgsLayoutManager::compositions() const
{
return mCompositions;
}

QgsComposition *QgsLayoutManager::compositionByName( const QString &name ) const
{
Q_FOREACH ( QgsComposition *c, mCompositions )
{
if ( c->name() == name )
return c;
}
return nullptr;
}

bool QgsLayoutManager::readXml( const QDomElement &element, const QDomDocument &doc )
{
clear();

QDomElement layoutsElem = element;
if ( element.tagName() != QStringLiteral( "Layouts" ) )
{
layoutsElem = element.firstChildElement( QStringLiteral( "Layouts" ) );
}
if ( layoutsElem.isNull() )
return false;

//restore each composer
bool result = true;
QDomNodeList composerNodes = element.elementsByTagName( QStringLiteral( "Composer" ) );
for ( int i = 0; i < composerNodes.size(); ++i )
{
QgsComposition *c = createCompositionFromXml( composerNodes.at( i ).toElement(), doc );
if ( !c )
{
result = false;
continue;
}
result = result && addComposition( c );
}
return result;
}

QDomElement QgsLayoutManager::writeXml( QDomDocument &doc ) const
{
QDomElement layoutsElem = doc.createElement( QStringLiteral( "Layouts" ) );
Q_FOREACH ( QgsComposition *c, mCompositions )
{
QDomElement composerElem = doc.createElement( QStringLiteral( "Composer" ) );

layoutsElem.appendChild( composerElem );

c->writeXml( composerElem, doc );
c->atlasComposition().writeXml( composerElem, doc );
}
return layoutsElem;
}

QgsComposition *QgsLayoutManager::createCompositionFromXml( const QDomElement &element, const QDomDocument &doc ) const
{
QDomNodeList compositionNodeList = element.elementsByTagName( QStringLiteral( "Composition" ) );

if ( compositionNodeList.size() > 0 )
{
std::unique_ptr< QgsComposition > c( new QgsComposition( mProject ) );
QDomElement compositionElem = compositionNodeList.at( 0 ).toElement();
if ( !c->readXml( compositionElem, doc ) )
{
return nullptr;
}

// read atlas parameters - must be done before adding items
QDomElement atlasElem = element.firstChildElement( QStringLiteral( "Atlas" ) );
c->atlasComposition().readXml( atlasElem, doc );

//read and restore all the items
c->addItemsFromXml( element, doc );

//make sure z values are consistent
c->refreshZList();
return c.release();
}
else
{
return nullptr;
}
}

0 comments on commit 3a1ac1a

Please sign in to comment.