Migrate QgsMapThemeCollection away from using layer IDs

This commit is contained in:
Martin Dobias 2016-12-10 23:23:18 +08:00
parent c143be7a73
commit 5fc10d6207
22 changed files with 465 additions and 425 deletions

View File

@ -46,6 +46,9 @@ class QgsLayerTreeGroup : QgsLayerTreeNode
//! Remove all child nodes. The nodes will be deleted.
void removeAllChildren();
//! Find layer node representing the map layer. Searches recursively the whole sub-tree.
//! @note added in 3.0
QgsLayerTreeLayer* findLayer( QgsMapLayer* layer ) const;
//! Find layer node representing the map layer specified by its ID. Searches recursively the whole sub-tree.
QgsLayerTreeLayer* findLayer( const QString& layerId );
//! Find all layer nodes. Searches recursively the whole sub-tree.

View File

@ -13,6 +13,33 @@ class QgsMapThemeCollection : QObject
%End
public:
/**
* \ingroup core
* Individual record of a visible layer in a map theme record.
* @note Added in QGIS 3.0
*/
class MapThemeLayerRecord
{
public:
//! Initialize layer record with a map layer - it will be stored as a weak pointer
MapThemeLayerRecord( QgsMapLayer* l = nullptr );
bool operator==( const QgsMapThemeCollection::MapThemeLayerRecord& other ) const;
bool operator!=( const QgsMapThemeCollection::MapThemeLayerRecord& other ) const;
//! Returns map layer or null if the layer does not exist anymore
QgsMapLayer* layer() const;
//! Whether current style is valid and should be applied
bool usingCurrentStyle;
//! Name of the current style of the layer
QString currentStyle;
//! Whether checkedLegendItems should be applied
bool usingLegendItems;
//! Rule keys of check legend items in layer tree model
QSet<QString> checkedLegendItems;
};
/** \ingroup core
* Individual map theme record of visible layers and styles.
*/
@ -23,42 +50,15 @@ class QgsMapThemeCollection : QObject
bool operator==( const QgsMapThemeCollection::MapThemeRecord& other ) const;
bool operator!=( const QgsMapThemeCollection::MapThemeRecord& other ) const;
/**
* Ordered list of visible layers
*/
QStringList visibleLayerIds() const;
//! Returns a list of records for all visible layer belonging to the theme.
QList<QgsMapThemeCollection::MapThemeLayerRecord> layerRecords() const;
/**
* Ordered list of visible layers
*/
void setVisibleLayerIds( const QStringList& visibleLayerIds );
/**
* Lists which legend symbols are checked for layers which support this and where
* not all symbols are checked.
* @note not available in Python bindings
*/
// QMap<QString, QSet<QString> > perLayerCheckedLegendSymbols() const;
/**
* Lists which legend symbols are checked for layers which support this and where
* not all symbols are checked.
* @note not available in Python bindings
*/
// void setPerLayerCheckedLegendSymbols(const QMap<QString, QSet<QString> >& perLayerCheckedLegendSymbols);
/**
* The currently used style name for layers with multiple styles.
* The map has layer ids as keys and style names as values.
*/
QMap<QString, QString> perLayerCurrentStyle() const;
/**
* The currently used style name for layers with multiple styles.
* The map has layer ids as keys and style names as values.
*/
void setPerLayerCurrentStyle(const QMap<QString, QString>& perLayerCurrentStyle);
//! Sets layer records for the theme.
void setLayerRecords( const QList<QgsMapThemeCollection::MapThemeLayerRecord>& records );
//! Return set with only records for valid layers
//! @note not available in python bindings
// QHash<QgsMapLayer*, QgsMapThemeCollection::MapThemeLayerRecord> validLayerRecords() const;
};
/**
@ -106,13 +106,18 @@ class QgsMapThemeCollection : QObject
*
* @note The order of the returned list is not guaranteed to reflect the order of layers
* in the canvas.
* @note Added in QGIS 3.0
*/
QStringList mapThemeVisibleLayers( const QString& name ) const;
QStringList mapThemeVisibleLayerIds( const QString& name ) const;
/**
* Apply check states of legend nodes of a given layer as defined in the map theme.
* Returns the list of layers that are visible for the specified map theme.
*
* @note The order of the returned list is not guaranteed to reflect the order of layers
* in the canvas.
* @note Added in QGIS 3.0
*/
void applyMapThemeCheckedLegendNodesToLayer( const QString& name, const QString& layerID );
QList<QgsMapLayer*> mapThemeVisibleLayers( const QString& name ) const;
/**
* Get layer style overrides (for QgsMapSettings) of the visible layers for given map theme.
@ -133,12 +138,18 @@ class QgsMapThemeCollection : QObject
void writeXml( QDomDocument& doc );
/**
* Static method for adding visible layers from a layer tree group to a map theme
* record.
* @param parent layer tree group parent
* @param rec map theme record to amend
* Static method to create theme from the current state of layer visibilities in layer tree,
* current style of layers and check state of legend items (from a layer tree model).
* @note added in QGIS 3.0
*/
static void addVisibleLayersToMapTheme( QgsLayerTreeGroup* parent, MapThemeRecord& rec );
static MapThemeRecord createThemeFromCurrentState( QgsLayerTreeGroup* root, QgsLayerTreeModel* model );
/**
* Apply theme given by its name and modify layer tree, current style of layers and checked
* legend items of passed layer tree model.
* @note added in QGIS 3.0
*/
void applyTheme( const QString& name, QgsLayerTreeGroup* root, QgsLayerTreeModel* model );
signals:

View File

@ -197,7 +197,7 @@ void QgsComposerMapWidget::keepLayersVisibilityPresetSelected()
return;
QString presetName = action->text();
QList<QgsMapLayer*> lst = QgsMapThemes::instance()->orderedPresetVisibleLayers2( presetName );
QList<QgsMapLayer*> lst = QgsMapThemes::instance()->orderedPresetVisibleLayers( presetName );
if ( mComposerMap )
{
mKeepLayerListCheckBox->setChecked( true );

View File

@ -1199,9 +1199,9 @@ int main( int argc, char *argv[] )
QList< QPair<QgsVectorLayer *, int > > layers;
if ( !dxfPreset.isEmpty() )
{
Q_FOREACH ( const QString& layer, QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( dxfPreset ) )
Q_FOREACH ( QgsMapLayer* layer, QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( dxfPreset ) )
{
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( layer ) );
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
if ( !vl )
continue;
layers << qMakePair<QgsVectorLayer *, int>( vl, -1 );

View File

@ -346,7 +346,7 @@ void QgsVectorLayerAndAttributeModel::applyVisibilityPreset( const QString &name
}
else
{
visibleLayers = QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( name ).toSet();
visibleLayers = QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayerIds( name ).toSet();
}
if ( visibleLayers.isEmpty() )

View File

@ -54,66 +54,12 @@ QgsMapThemes::QgsMapThemes()
connect( mMenu, SIGNAL( aboutToShow() ), this, SLOT( menuAboutToShow() ) );
}
void QgsMapThemes::addPerLayerCheckedLegendSymbols( QgsMapThemeCollection::MapThemeRecord& rec )
{
QgsLayerTreeModel* model = QgisApp::instance()->layerTreeView()->layerTreeModel();
Q_FOREACH ( const QString& layerID, rec.visibleLayerIds() )
{
QgsLayerTreeLayer* nodeLayer = model->rootGroup()->findLayer( layerID );
if ( !nodeLayer )
continue;
bool hasCheckableItems = false;
bool someItemsUnchecked = false;
QSet<QString> checkedItems;
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer, true ) )
{
if ( legendNode->flags() & Qt::ItemIsUserCheckable )
{
hasCheckableItems = true;
if ( legendNode->data( Qt::CheckStateRole ).toInt() == Qt::Checked )
checkedItems << legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString();
else
someItemsUnchecked = true;
}
}
QMap<QString, QSet<QString> > checkedSymbols = rec.perLayerCheckedLegendSymbols();
if ( hasCheckableItems && someItemsUnchecked )
checkedSymbols.insert( nodeLayer->layerId(), checkedItems );
rec.setPerLayerCheckedLegendSymbols( checkedSymbols );
}
}
void QgsMapThemes::addPerLayerCurrentStyle( QgsMapThemeCollection::MapThemeRecord& rec )
{
QgsLayerTreeModel* model = QgisApp::instance()->layerTreeView()->layerTreeModel();
QMap<QString, QString> styles = rec.perLayerCurrentStyle();
Q_FOREACH ( const QString& layerID, rec.visibleLayerIds() )
{
QgsLayerTreeLayer* nodeLayer = model->rootGroup()->findLayer( layerID );
if ( !nodeLayer )
continue;
styles[layerID] = nodeLayer->layer()->styleManager()->currentStyle();
}
rec.setPerLayerCurrentStyle( styles );
}
QgsMapThemeCollection::MapThemeRecord QgsMapThemes::currentState()
{
QgsMapThemeCollection::MapThemeRecord rec;
QgsLayerTreeGroup* root = QgsProject::instance()->layerTreeRoot();
QgsMapThemeCollection::addVisibleLayersToMapTheme( root, rec );
addPerLayerCheckedLegendSymbols( rec );
addPerLayerCurrentStyle( rec );
return rec;
QgsLayerTreeModel* model = QgisApp::instance()->layerTreeView()->layerTreeModel();
return QgsMapThemeCollection::createThemeFromCurrentState( root, model );
}
QgsMapThemes* QgsMapThemes::instance()
@ -134,30 +80,21 @@ void QgsMapThemes::updatePreset( const QString& name )
QgsProject::instance()->mapThemeCollection()->update( name, currentState() );
}
QStringList QgsMapThemes::orderedPresetVisibleLayers( const QString& name ) const
QList<QgsMapLayer*> QgsMapThemes::orderedPresetVisibleLayers( const QString& name ) const
{
QStringList visibleIds = QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( name );
QStringList visibleIds = QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayerIds( name );
// also make sure to order the layers according to map canvas order
QgsLayerTreeMapCanvasBridge* bridge = QgisApp::instance()->layerTreeCanvasBridge();
QStringList order = bridge->hasCustomLayerOrder() ? bridge->customLayerOrder() : bridge->defaultLayerOrder();
QStringList order2;
QList<QgsMapLayer*> lst;
Q_FOREACH ( const QString& layerID, order )
{
if ( visibleIds.contains( layerID ) )
order2 << layerID;
}
return order2;
}
QList<QgsMapLayer*> QgsMapThemes::orderedPresetVisibleLayers2( const QString& name ) const
{
QList<QgsMapLayer*> lst;
Q_FOREACH ( const QString& layerId, orderedPresetVisibleLayers( name ) )
{
if ( QgsMapLayer* layer = QgsProject::instance()->mapLayer( layerId ) )
lst << layer;
{
if ( QgsMapLayer* layer = QgsProject::instance()->mapLayer( layerID ) )
lst << layer;
}
}
return lst;
}
@ -202,64 +139,15 @@ void QgsMapThemes::replaceTriggered()
addPreset( actionPreset->text() );
}
void QgsMapThemes::applyStateToLayerTreeGroup( QgsLayerTreeGroup* parent, const QgsMapThemeCollection::MapThemeRecord& rec )
{
Q_FOREACH ( QgsLayerTreeNode* node, parent->children() )
{
if ( QgsLayerTree::isGroup( node ) )
applyStateToLayerTreeGroup( QgsLayerTree::toGroup( node ), rec );
else if ( QgsLayerTree::isLayer( node ) )
{
QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
bool isVisible = rec.visibleLayerIds().contains( nodeLayer->layerId() );
nodeLayer->setVisible( isVisible ? Qt::Checked : Qt::Unchecked );
if ( isVisible )
{
if ( rec.perLayerCurrentStyle().contains( nodeLayer->layerId() ) )
{
// apply desired style first
nodeLayer->layer()->styleManager()->setCurrentStyle( rec.perLayerCurrentStyle().value( nodeLayer->layerId() ) );
}
QgsLayerTreeModel* model = QgisApp::instance()->layerTreeView()->layerTreeModel();
if ( rec.perLayerCheckedLegendSymbols().contains( nodeLayer->layerId() ) )
{
const QSet<QString>& checkedNodes = rec.perLayerCheckedLegendSymbols().value( nodeLayer->layerId() );
// some nodes are not checked
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer, true ) )
{
Qt::CheckState shouldHaveState = checkedNodes.contains( legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString() ) ? Qt::Checked : Qt::Unchecked;
if (( legendNode->flags() & Qt::ItemIsUserCheckable ) &&
legendNode->data( Qt::CheckStateRole ).toInt() != shouldHaveState )
legendNode->setData( shouldHaveState, Qt::CheckStateRole );
}
}
else
{
// all nodes should be checked
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer, true ) )
{
if (( legendNode->flags() & Qt::ItemIsUserCheckable ) &&
legendNode->data( Qt::CheckStateRole ).toInt() != Qt::Checked )
legendNode->setData( Qt::Checked, Qt::CheckStateRole );
}
}
}
}
}
}
void QgsMapThemes::applyState( const QString& presetName )
{
if ( !QgsProject::instance()->mapThemeCollection()->hasMapTheme( presetName ) )
return;
applyStateToLayerTreeGroup( QgsProject::instance()->layerTreeRoot(), QgsProject::instance()->mapThemeCollection()->mapThemeState( presetName ) );
// also make sure that the preset is up-to-date (not containing any non-existent legend items)
QgsProject::instance()->mapThemeCollection()->update( presetName, currentState() );
QgsLayerTreeGroup* root = QgsProject::instance()->layerTreeRoot();
QgsLayerTreeModel* model = QgisApp::instance()->layerTreeView()->layerTreeModel();
QgsProject::instance()->mapThemeCollection()->applyTheme( presetName, root, model );
}
void QgsMapThemes::removeCurrentPreset()

View File

@ -48,11 +48,7 @@ class APP_EXPORT QgsMapThemes : public QObject
//! Return list of layer IDs that should be visible for particular preset.
//! The order will match the layer order from the map canvas
QStringList orderedPresetVisibleLayers( const QString& name ) const;
//! Return list of layer IDs that should be visible for particular preset.
//! The order will match the layer order from the map canvas
QList<QgsMapLayer*> orderedPresetVisibleLayers2( const QString& name ) const;
QList<QgsMapLayer*> orderedPresetVisibleLayers( const QString& name ) const;
//! Convenience menu that lists available presets and actions for management
QMenu* menu();

View File

@ -628,16 +628,8 @@ void QgsAtlasComposition::readXml( const QDomElement& atlasElem, const QDomDocum
}
// look for stored layer name
mCoverageLayer = nullptr;
QMap<QString, QgsMapLayer*> layers = QgsProject::instance()->mapLayers();
for ( QMap<QString, QgsMapLayer*>::const_iterator it = layers.begin(); it != layers.end(); ++it )
{
if ( it.key() == atlasElem.attribute( QStringLiteral( "coverageLayer" ) ) )
{
mCoverageLayer = dynamic_cast<QgsVectorLayer*>( it.value() );
break;
}
}
QString coverageLayerId = atlasElem.attribute( QStringLiteral( "coverageLayer" ) );
mCoverageLayer = qobject_cast<QgsVectorLayer*>( QgsProject::instance()->mapLayer( coverageLayerId ) );
mPageNameExpression = atlasElem.attribute( QStringLiteral( "pageNameExpression" ), QString() );
mSingleFile = atlasElem.attribute( QStringLiteral( "singleFile" ), QStringLiteral( "false" ) ) == QLatin1String( "true" ) ? true : false;

View File

@ -22,6 +22,7 @@
#include "qgscomposerutils.h"
#include "qgslogger.h"
#include "qgsmaprenderercustompainterjob.h"
#include "qgsmaplayerlistutils.h"
#include "qgsmaplayerstylemanager.h"
#include "qgsmaptopixel.h"
#include "qgspainting.h"
@ -544,7 +545,7 @@ QList<QgsMapLayer*> QgsComposerMap::layersToRender( const QgsExpressionContext*
}
if ( QgsProject::instance()->mapThemeCollection()->hasMapTheme( presetName ) )
renderLayers = QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers2( presetName );
renderLayers = QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( presetName );
else // fallback to using map canvas layers
renderLayers = mComposition->mapSettings().layers();
}
@ -1559,9 +1560,7 @@ bool QgsComposerMap::readXml( const QDomElement& itemElem, const QDomDocument& d
void QgsComposerMap::storeCurrentLayerSet()
{
mLayers.clear();
Q_FOREACH ( QgsMapLayer* layer, mComposition->mapSettings().layers() )
mLayers << layer;
mLayers = _qgis_listRawToQPointer( mComposition->mapSettings().layers() );
if ( mKeepLayerStyles )
{
@ -1572,23 +1571,12 @@ void QgsComposerMap::storeCurrentLayerSet()
QList<QgsMapLayer*> QgsComposerMap::layers() const
{
QList<QgsMapLayer*> layers;
layers.reserve( mLayers.count() );
Q_FOREACH ( const QPointer<QgsMapLayer>& layerPtr, mLayers )
{
if ( layerPtr )
layers.append( layerPtr.data() );
}
return layers;
return _qgis_listQPointerToRaw( mLayers );
}
void QgsComposerMap::setLayers( const QList<QgsMapLayer*> layers )
{
mLayers.clear();
Q_FOREACH ( QgsMapLayer* layer, layers )
{
mLayers.append( layer );
}
mLayers = _qgis_listRawToQPointer( layers );
}

View File

@ -201,6 +201,11 @@ void QgsLayerTreeGroup::removeAllChildren()
removeChildren( 0, mChildren.count() );
}
QgsLayerTreeLayer *QgsLayerTreeGroup::findLayer( QgsMapLayer* layer ) const
{
return findLayer( layer->id() );
}
QgsLayerTreeLayer *QgsLayerTreeGroup::findLayer( const QString& layerId ) const
{
Q_FOREACH ( QgsLayerTreeNode* child, mChildren )

View File

@ -67,6 +67,9 @@ class CORE_EXPORT QgsLayerTreeGroup : public QgsLayerTreeNode
//! Remove all child nodes. The nodes will be deleted.
void removeAllChildren();
//! Find layer node representing the map layer. Searches recursively the whole sub-tree.
//! @note added in 3.0
QgsLayerTreeLayer* findLayer( QgsMapLayer* layer ) const;
//! Find layer node representing the map layer specified by its ID. Searches recursively the whole sub-tree.
QgsLayerTreeLayer* findLayer( const QString& layerId ) const;
//! Find all layer nodes. Searches recursively the whole sub-tree.

View File

@ -0,0 +1,56 @@
#ifndef QGSMAPLAYERLISTUTILS_H
#define QGSMAPLAYERLISTUTILS_H
//
// W A R N I N G
// -------------
//
// This file is not part of the QGIS API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
#include <QPointer>
#include "qgsmaplayer.h"
/// @cond PRIVATE
inline QList<QgsMapLayer*> _qgis_listQPointerToRaw( const QList< QPointer<QgsMapLayer> >& layers )
{
QList<QgsMapLayer*> lst;
lst.reserve( layers.count() );
Q_FOREACH ( const QPointer<QgsMapLayer>& layerPtr, layers )
{
if ( layerPtr )
lst.append( layerPtr.data() );
}
return lst;
}
inline QList< QPointer<QgsMapLayer> > _qgis_listRawToQPointer( const QList<QgsMapLayer*>& layers )
{
QList< QPointer<QgsMapLayer> > lst;
lst.reserve( layers.count() );
Q_FOREACH ( QgsMapLayer* layer, layers )
{
lst.append( layer );
}
return lst;
}
inline QStringList _qgis_listQPointerToIDs( const QList< QPointer<QgsMapLayer> >& layers )
{
QStringList lst;
lst.reserve( layers.count() );
Q_FOREACH ( const QPointer<QgsMapLayer>& layerPtr, layers )
{
if ( layerPtr )
lst << layerPtr->id();
}
return lst;
}
///@endcond
#endif // QGSMAPLAYERLISTUTILS_H

View File

@ -22,6 +22,7 @@
#include "qgsmessagelog.h"
#include "qgsmaplayer.h"
#include "qgsmaplayerlistutils.h"
#include "qgsproject.h"
#include "qgsxmlutils.h"
#include "qgscsexception.h"
@ -256,36 +257,18 @@ void QgsMapSettings::setOutputDpi( double dpi )
QStringList QgsMapSettings::layerIds() const
{
QStringList layerIds;
layerIds.reserve( mLayers.count() );
Q_FOREACH ( const QPointer<QgsMapLayer>& layerPtr, mLayers )
{
if ( layerPtr )
layerIds.append( layerPtr->id() );
}
return layerIds;
return _qgis_listQPointerToIDs( mLayers );
}
QList<QgsMapLayer*> QgsMapSettings::layers() const
{
QList<QgsMapLayer*> layers;
layers.reserve( mLayers.count() );
Q_FOREACH ( const QPointer<QgsMapLayer>& layerPtr, mLayers )
{
if ( layerPtr )
layers.append( layerPtr.data() );
}
return layers;
return _qgis_listQPointerToRaw( mLayers );
}
void QgsMapSettings::setLayers( const QList<QgsMapLayer*>& layers )
{
mLayers.clear();
Q_FOREACH ( QgsMapLayer* layer, layers )
{
mLayers.append( layer );
}
mLayers = _qgis_listRawToQPointer( layers );
}
QMap<QString, QString> QgsMapSettings::layerStyleOverrides() const

View File

@ -18,6 +18,7 @@
#include "qgslayertree.h"
#include "qgslayertreemodel.h"
#include "qgslayertreemodellegendnode.h"
#include "qgsmaplayerlistutils.h"
#include "qgsmaplayerstylemanager.h"
#include "qgsproject.h"
#include "qgsrenderer.h"
@ -32,21 +33,134 @@ QgsMapThemeCollection::QgsMapThemeCollection( QgsProject* project )
this, SLOT( registryLayersRemoved( QStringList ) ) );
}
void QgsMapThemeCollection::addVisibleLayersToMapTheme( QgsLayerTreeGroup* parent, QgsMapThemeCollection::MapThemeRecord& rec )
QgsMapThemeCollection::MapThemeLayerRecord QgsMapThemeCollection::createThemeLayerRecord( QgsLayerTreeLayer* nodeLayer, QgsLayerTreeModel* model )
{
MapThemeLayerRecord layerRec( nodeLayer->layer() );
layerRec.usingCurrentStyle = true;
layerRec.currentStyle = nodeLayer->layer()->styleManager()->currentStyle();
// get checked legend items
bool hasCheckableItems = false;
bool someItemsUnchecked = false;
QSet<QString> checkedItems;
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer, true ) )
{
if ( legendNode->flags() & Qt::ItemIsUserCheckable )
{
hasCheckableItems = true;
if ( legendNode->data( Qt::CheckStateRole ).toInt() == Qt::Checked )
checkedItems << legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString();
else
someItemsUnchecked = true;
}
}
if ( hasCheckableItems && someItemsUnchecked )
{
layerRec.usingLegendItems = true;
layerRec.checkedLegendItems = checkedItems;
}
return layerRec;
}
void QgsMapThemeCollection::createThemeFromCurrentState( QgsLayerTreeGroup* parent, QgsLayerTreeModel* model, QgsMapThemeCollection::MapThemeRecord& rec )
{
Q_FOREACH ( QgsLayerTreeNode* node, parent->children() )
{
if ( QgsLayerTree::isGroup( node ) )
addVisibleLayersToMapTheme( QgsLayerTree::toGroup( node ), rec );
createThemeFromCurrentState( QgsLayerTree::toGroup( node ), model, rec );
else if ( QgsLayerTree::isLayer( node ) )
{
QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
if ( nodeLayer->isVisible() )
rec.mVisibleLayerIds << nodeLayer->layerId();
rec.mLayerRecords << createThemeLayerRecord( nodeLayer, model );
}
}
}
QgsMapThemeCollection::MapThemeRecord QgsMapThemeCollection::createThemeFromCurrentState( QgsLayerTreeGroup* root, QgsLayerTreeModel* model )
{
QgsMapThemeCollection::MapThemeRecord rec;
createThemeFromCurrentState( root, model, rec );
return rec;
}
bool QgsMapThemeCollection::findRecordForLayer( QgsMapLayer* layer, const QgsMapThemeCollection::MapThemeRecord& rec, QgsMapThemeCollection::MapThemeLayerRecord& layerRec )
{
Q_FOREACH ( const QgsMapThemeCollection::MapThemeLayerRecord& lr, rec.mLayerRecords )
{
if ( lr.layer() == layer )
{
layerRec = lr;
return true;
}
}
return false;
}
void QgsMapThemeCollection::applyThemeToLayer( QgsLayerTreeLayer* nodeLayer, QgsLayerTreeModel* model, const QgsMapThemeCollection::MapThemeRecord& rec )
{
MapThemeLayerRecord layerRec;
bool isVisible = findRecordForLayer( nodeLayer->layer(), rec, layerRec );
nodeLayer->setVisible( isVisible ? Qt::Checked : Qt::Unchecked );
if ( !isVisible )
return;
if ( layerRec.usingCurrentStyle )
{
// apply desired style first
nodeLayer->layer()->styleManager()->setCurrentStyle( layerRec.currentStyle );
}
if ( layerRec.usingLegendItems )
{
// some nodes are not checked
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer, true ) )
{
QString ruleKey = legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString();
Qt::CheckState shouldHaveState = layerRec.checkedLegendItems.contains( ruleKey ) ? Qt::Checked : Qt::Unchecked;
if (( legendNode->flags() & Qt::ItemIsUserCheckable ) &&
legendNode->data( Qt::CheckStateRole ).toInt() != shouldHaveState )
legendNode->setData( shouldHaveState, Qt::CheckStateRole );
}
}
else
{
// all nodes should be checked
Q_FOREACH ( QgsLayerTreeModelLegendNode* legendNode, model->layerLegendNodes( nodeLayer, true ) )
{
if (( legendNode->flags() & Qt::ItemIsUserCheckable ) &&
legendNode->data( Qt::CheckStateRole ).toInt() != Qt::Checked )
legendNode->setData( Qt::Checked, Qt::CheckStateRole );
}
}
}
void QgsMapThemeCollection::applyThemeToGroup( QgsLayerTreeGroup* parent, QgsLayerTreeModel* model, const QgsMapThemeCollection::MapThemeRecord& rec )
{
Q_FOREACH ( QgsLayerTreeNode* node, parent->children() )
{
if ( QgsLayerTree::isGroup( node ) )
applyThemeToGroup( QgsLayerTree::toGroup( node ), model, rec );
else if ( QgsLayerTree::isLayer( node ) )
applyThemeToLayer( QgsLayerTree::toLayer( node ), model, rec );
}
}
void QgsMapThemeCollection::applyTheme( const QString& name, QgsLayerTreeGroup* root, QgsLayerTreeModel* model )
{
applyThemeToGroup( root, model, mapThemeState( name ) );
// also make sure that the preset is up-to-date (not containing any non-existent legend items)
update( name, createThemeFromCurrentState( root, model ) );
}
bool QgsMapThemeCollection::hasMapTheme( const QString& name ) const
{
return mMapThemes.contains( name );
@ -95,50 +209,48 @@ QStringList QgsMapThemeCollection::mapThemes() const
return mMapThemes.keys();
}
QStringList QgsMapThemeCollection::mapThemeVisibleLayers( const QString& name ) const
QStringList QgsMapThemeCollection::mapThemeVisibleLayerIds( const QString& name ) const
{
return mMapThemes.value( name ).mVisibleLayerIds;
}
QList<QgsMapLayer*> QgsMapThemeCollection::mapThemeVisibleLayers2( const QString& name ) const
{
QList<QgsMapLayer*> lst;
Q_FOREACH ( const QString& layerId, mMapThemes.value( name ).mVisibleLayerIds )
QStringList layerIds;
Q_FOREACH ( const MapThemeLayerRecord& layerRec, mMapThemes.value( name ).mLayerRecords )
{
if ( QgsMapLayer* layer = QgsProject::instance()->mapLayer( layerId ) )
lst << layer;
if ( layerRec.layer() )
layerIds << layerRec.layer()->id();
}
return lst;
return layerIds;
}
void QgsMapThemeCollection::applyMapThemeCheckedLegendNodesToLayer( const QString& name, const QString& layerID )
QList<QgsMapLayer*> QgsMapThemeCollection::mapThemeVisibleLayers( const QString& name ) const
{
if ( !mMapThemes.contains( name ) )
return;
QList<QgsMapLayer*> layers;
Q_FOREACH ( const MapThemeLayerRecord& layerRec, mMapThemes.value( name ).mLayerRecords )
{
if ( layerRec.layer() )
layers << layerRec.layer();
}
return layers;
}
QgsMapLayer* layer = mProject->mapLayer( layerID );
if ( !layer )
return;
const MapThemeRecord& rec = mMapThemes[name];
void QgsMapThemeCollection::applyMapThemeCheckedLegendNodesToLayer( const MapThemeLayerRecord& layerRec, QgsMapLayer* layer )
{
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( layer );
if ( !vlayer || !vlayer->renderer() )
return;
if ( !vlayer->renderer()->legendSymbolItemsCheckable() )
QgsFeatureRenderer* renderer = vlayer->renderer();
if ( !renderer->legendSymbolItemsCheckable() )
return; // no need to do anything
bool someNodesUnchecked = rec.mPerLayerCheckedLegendSymbols.contains( layerID );
bool someNodesUnchecked = layerRec.usingLegendItems;
Q_FOREACH ( const QgsLegendSymbolItem& item, vlayer->renderer()->legendSymbolItemsV2() )
{
bool checked = vlayer->renderer()->legendSymbolItemChecked( item.ruleKey() );
bool shouldBeChecked = someNodesUnchecked ? rec.mPerLayerCheckedLegendSymbols[layerID].contains( item.ruleKey() ) : true;
bool checked = renderer->legendSymbolItemChecked( item.ruleKey() );
bool shouldBeChecked = someNodesUnchecked ? layerRec.checkedLegendItems.contains( item.ruleKey() ) : true;
if ( checked != shouldBeChecked )
vlayer->renderer()->checkLegendSymbolItem( item.ruleKey(), shouldBeChecked );
renderer->checkLegendSymbolItem( item.ruleKey(), shouldBeChecked );
}
}
@ -149,29 +261,26 @@ QMap<QString, QString> QgsMapThemeCollection::mapThemeStyleOverrides( const QStr
if ( !mMapThemes.contains( presetName ) )
return styleOverrides;
QStringList lst = mapThemeVisibleLayers( presetName );
const QgsMapThemeCollection::MapThemeRecord& rec = mMapThemes[presetName];
Q_FOREACH ( const QString& layerID, lst )
Q_FOREACH ( const MapThemeLayerRecord& layerRec, mMapThemes.value( presetName ).mLayerRecords )
{
QgsMapLayer* layer = mProject->mapLayer( layerID );
if ( !layer )
if ( !layerRec.layer() )
continue;
// use either the stored style name or the current one if none has been stored
QString overrideStyleName = rec.mPerLayerCurrentStyle.value( layerID, layer->styleManager()->currentStyle() );
if ( layerRec.usingCurrentStyle )
{
QgsMapLayer* layer = layerRec.layer();
layer->styleManager()->setOverrideStyle( layerRec.currentStyle );
// store original style and temporarily apply a style
layer->styleManager()->setOverrideStyle( overrideStyleName );
// set the checked legend nodes
applyMapThemeCheckedLegendNodesToLayer( layerRec, layer );
// set the checked legend nodes
applyMapThemeCheckedLegendNodesToLayer( presetName, layerID );
// save to overrides
QgsMapLayerStyle layerStyle;
layerStyle.readFromLayer( layer );
styleOverrides[layer->id()] = layerStyle.xmlData();
// save to overrides
QgsMapLayerStyle layerStyle;
layerStyle.readFromLayer( layer );
styleOverrides[layerID] = layerStyle.xmlData();
layer->styleManager()->restoreOverrideStyle();
layer->styleManager()->restoreOverrideStyle();
}
}
return styleOverrides;
}
@ -180,20 +289,19 @@ void QgsMapThemeCollection::reconnectToLayersStyleManager()
{
// disconnect( 0, 0, this, SLOT( layerStyleRenamed( QString, QString ) ) );
QSet<QString> layerIDs;
MapThemeRecordMap::const_iterator it = mMapThemes.constBegin();
for ( ; it != mMapThemes.constEnd(); ++it )
QSet<QgsMapLayer*> layers;
Q_FOREACH ( const MapThemeRecord& rec, mMapThemes )
{
const MapThemeRecord& rec = it.value();
QMap<QString, QString>::const_iterator layerIt = rec.mPerLayerCurrentStyle.constBegin();
for ( ; layerIt != rec.mPerLayerCurrentStyle.constEnd(); ++layerIt )
layerIDs << layerIt.key();
Q_FOREACH ( const MapThemeLayerRecord& layerRec, rec.mLayerRecords )
{
if ( layerRec.layer() )
layers << layerRec.layer();
}
}
Q_FOREACH ( const QString& layerID, layerIDs )
Q_FOREACH ( QgsMapLayer* ml, layers )
{
if ( QgsMapLayer* ml = mProject->mapLayer( layerID ) )
connect( ml->styleManager(), SIGNAL( styleRenamed( QString, QString ) ), this, SLOT( layerStyleRenamed( QString, QString ) ) );
connect( ml->styleManager(), SIGNAL( styleRenamed( QString, QString ) ), this, SLOT( layerStyleRenamed( QString, QString ) ) );
}
}
@ -208,17 +316,22 @@ void QgsMapThemeCollection::readXml( const QDomDocument& doc )
QDomElement visPresetElem = visPresetsElem.firstChildElement( QStringLiteral( "visibility-preset" ) );
while ( !visPresetElem.isNull() )
{
QHash<QString, MapThemeLayerRecord> layerRecords; // key = layer ID
QString presetName = visPresetElem.attribute( QStringLiteral( "name" ) );
MapThemeRecord rec;
QDomElement visPresetLayerElem = visPresetElem.firstChildElement( QStringLiteral( "layer" ) );
while ( !visPresetLayerElem.isNull() )
{
QString layerID = visPresetLayerElem.attribute( QStringLiteral( "id" ) );
if ( mProject->mapLayer( layerID ) )
if ( QgsMapLayer* layer = mProject->mapLayer( layerID ) )
{
rec.mVisibleLayerIds << layerID; // only use valid layer IDs
layerRecords[layerID] = MapThemeLayerRecord( layer );
if ( visPresetLayerElem.hasAttribute( QStringLiteral( "style" ) ) )
rec.mPerLayerCurrentStyle[layerID] = visPresetLayerElem.attribute( QStringLiteral( "style" ) );
{
layerRecords[layerID].usingCurrentStyle = true;
layerRecords[layerID].currentStyle = visPresetLayerElem.attribute( QStringLiteral( "style" ) );
}
}
visPresetLayerElem = visPresetLayerElem.nextSiblingElement( QStringLiteral( "layer" ) );
}
@ -237,10 +350,15 @@ void QgsMapThemeCollection::readXml( const QDomDocument& doc )
QString layerID = checkedLegendNodesElem.attribute( QStringLiteral( "id" ) );
if ( mProject->mapLayer( layerID ) ) // only use valid IDs
rec.mPerLayerCheckedLegendSymbols.insert( layerID, checkedLegendNodes );
{
layerRecords[layerID].usingLegendItems = true;
layerRecords[layerID].checkedLegendItems = checkedLegendNodes;
}
checkedLegendNodesElem = checkedLegendNodesElem.nextSiblingElement( QStringLiteral( "checked-legend-nodes" ) );
}
MapThemeRecord rec;
rec.setLayerRecords( layerRecords.values() );
mMapThemes.insert( presetName, rec );
visPresetElem = visPresetElem.nextSiblingElement( QStringLiteral( "visibility-preset" ) );
@ -260,28 +378,29 @@ void QgsMapThemeCollection::writeXml( QDomDocument& doc )
const MapThemeRecord& rec = it.value();
QDomElement visPresetElem = doc.createElement( QStringLiteral( "visibility-preset" ) );
visPresetElem.setAttribute( QStringLiteral( "name" ), grpName );
Q_FOREACH ( const QString& layerID, rec.mVisibleLayerIds )
Q_FOREACH ( const MapThemeLayerRecord& layerRec, rec.mLayerRecords )
{
if ( !layerRec.layer() )
continue;
QString layerID = layerRec.layer()->id();
QDomElement layerElem = doc.createElement( QStringLiteral( "layer" ) );
layerElem.setAttribute( QStringLiteral( "id" ), layerID );
if ( rec.mPerLayerCurrentStyle.contains( layerID ) )
layerElem.setAttribute( QStringLiteral( "style" ), rec.mPerLayerCurrentStyle[layerID] );
if ( layerRec.usingCurrentStyle )
layerElem.setAttribute( QStringLiteral( "style" ), layerRec.currentStyle );
visPresetElem.appendChild( layerElem );
}
QMap<QString, QSet<QString> >::const_iterator layerIt = rec.mPerLayerCheckedLegendSymbols.constBegin();
for ( ; layerIt != rec.mPerLayerCheckedLegendSymbols.constEnd(); ++layerIt )
{
QString layerID = layerIt.key();
QDomElement checkedLegendNodesElem = doc.createElement( QStringLiteral( "checked-legend-nodes" ) );
checkedLegendNodesElem.setAttribute( QStringLiteral( "id" ), layerID );
Q_FOREACH ( const QString& checkedLegendNode, layerIt.value() )
if ( layerRec.usingLegendItems )
{
QDomElement checkedLegendNodeElem = doc.createElement( QStringLiteral( "checked-legend-node" ) );
checkedLegendNodeElem.setAttribute( QStringLiteral( "id" ), checkedLegendNode );
checkedLegendNodesElem.appendChild( checkedLegendNodeElem );
QDomElement checkedLegendNodesElem = doc.createElement( QStringLiteral( "checked-legend-nodes" ) );
checkedLegendNodesElem.setAttribute( QStringLiteral( "id" ), layerID );
Q_FOREACH ( const QString& checkedLegendNode, layerRec.checkedLegendItems )
{
QDomElement checkedLegendNodeElem = doc.createElement( QStringLiteral( "checked-legend-node" ) );
checkedLegendNodeElem.setAttribute( QStringLiteral( "id" ), checkedLegendNode );
checkedLegendNodesElem.appendChild( checkedLegendNodeElem );
}
visPresetElem.appendChild( checkedLegendNodesElem );
}
visPresetElem.appendChild( checkedLegendNodesElem );
}
visPresetsElem.appendChild( visPresetElem );
@ -292,15 +411,17 @@ void QgsMapThemeCollection::writeXml( QDomDocument& doc )
void QgsMapThemeCollection::registryLayersRemoved( const QStringList& layerIDs )
{
Q_FOREACH ( const QString& layerID, layerIDs )
// TODO: this should not be necessary - layers are stored as weak pointers
MapThemeRecordMap::iterator it = mMapThemes.begin();
for ( ; it != mMapThemes.end(); ++it )
{
MapThemeRecordMap::iterator it = mMapThemes.begin();
for ( ; it != mMapThemes.end(); ++it )
MapThemeRecord& rec = it.value();
for ( int i = 0; i < rec.mLayerRecords.count(); ++i )
{
MapThemeRecord& rec = it.value();
rec.mVisibleLayerIds.removeAll( layerID );
rec.mPerLayerCheckedLegendSymbols.remove( layerID );
rec.mPerLayerCurrentStyle.remove( layerID );
MapThemeLayerRecord& layerRec = rec.mLayerRecords[i];
if ( layerRec.layer() && layerIDs.contains( layerRec.layer()->id() ) )
rec.mLayerRecords.removeAt( i-- );
}
}
emit mapThemesChanged();
@ -312,49 +433,31 @@ void QgsMapThemeCollection::layerStyleRenamed( const QString& oldName, const QSt
if ( !styleMgr )
return;
QString layerID = styleMgr->layer()->id();
MapThemeRecordMap::iterator it = mMapThemes.begin();
for ( ; it != mMapThemes.end(); ++it )
{
MapThemeRecord& rec = it.value();
if ( rec.mPerLayerCurrentStyle.contains( layerID ) )
for ( int i = 0; i < rec.mLayerRecords.count(); ++i )
{
QString styleName = rec.mPerLayerCurrentStyle[layerID];
if ( styleName == oldName )
rec.mPerLayerCurrentStyle[layerID] = newName;
MapThemeLayerRecord& layerRec = rec.mLayerRecords[i];
if ( layerRec.layer() == styleMgr->layer() )
{
if ( layerRec.currentStyle == oldName )
layerRec.currentStyle = newName;
}
}
}
emit mapThemesChanged();
}
QStringList QgsMapThemeCollection::MapThemeRecord::visibleLayerIds() const
{
return mVisibleLayerIds;
}
void QgsMapThemeCollection::MapThemeRecord::setVisibleLayerIds( const QStringList& visibleLayerIds )
QHash<QgsMapLayer*, QgsMapThemeCollection::MapThemeLayerRecord> QgsMapThemeCollection::MapThemeRecord::validLayerRecords() const
{
mVisibleLayerIds = visibleLayerIds;
}
QMap<QString, QSet<QString> > QgsMapThemeCollection::MapThemeRecord::perLayerCheckedLegendSymbols() const
{
return mPerLayerCheckedLegendSymbols;
}
void QgsMapThemeCollection::MapThemeRecord::setPerLayerCheckedLegendSymbols( const QMap<QString, QSet<QString> >& perLayerCheckedLegendSymbols )
{
mPerLayerCheckedLegendSymbols = perLayerCheckedLegendSymbols;
}
QMap<QString, QString> QgsMapThemeCollection::MapThemeRecord::perLayerCurrentStyle() const
{
return mPerLayerCurrentStyle;
}
void QgsMapThemeCollection::MapThemeRecord::setPerLayerCurrentStyle( const QMap<QString, QString>& perLayerCurrentStyle )
{
mPerLayerCurrentStyle = perLayerCurrentStyle;
QHash<QgsMapLayer*, MapThemeLayerRecord> validSet;
Q_FOREACH ( const MapThemeLayerRecord& layerRec, mLayerRecords )
{
if ( layerRec.layer() )
validSet.insert( layerRec.layer(), layerRec );
}
return validSet;
}

View File

@ -18,13 +18,17 @@
#include <QMap>
#include <QObject>
#include <QPointer>
#include <QSet>
#include <QStringList>
#include "qgsmaplayer.h"
class QDomDocument;
class QgsLayerTreeModel;
class QgsLayerTreeNode;
class QgsLayerTreeGroup;
class QgsMapLayer;
class QgsLayerTreeLayer;
class QgsProject;
/**
@ -43,6 +47,44 @@ class CORE_EXPORT QgsMapThemeCollection : public QObject
public:
/**
* \ingroup core
* Individual record of a visible layer in a map theme record.
* @note Added in QGIS 3.0
*/
class MapThemeLayerRecord
{
public:
//! Initialize layer record with a map layer - it will be stored as a weak pointer
MapThemeLayerRecord( QgsMapLayer* l = nullptr ): usingCurrentStyle( false ), usingLegendItems( false ), mLayer( l ) {}
bool operator==( const MapThemeLayerRecord& other ) const
{
return mLayer == other.mLayer &&
usingCurrentStyle == other.usingCurrentStyle && currentStyle == other.currentStyle &&
usingLegendItems == other.usingLegendItems && checkedLegendItems == other.checkedLegendItems;
}
bool operator!=( const MapThemeLayerRecord& other ) const
{
return !( *this == other );
}
//! Returns map layer or null if the layer does not exist anymore
QgsMapLayer* layer() const { return mLayer; }
//! Whether current style is valid and should be applied
bool usingCurrentStyle;
//! Name of the current style of the layer
QString currentStyle;
//! Whether checkedLegendItems should be applied
bool usingLegendItems;
//! Rule keys of check legend items in layer tree model
QSet<QString> checkedLegendItems;
private:
//! Weak pointer to the layer
QPointer<QgsMapLayer> mLayer;
};
/**
* \ingroup core
* Individual map theme record of visible layers and styles.
@ -55,61 +97,26 @@ class CORE_EXPORT QgsMapThemeCollection : public QObject
bool operator==( const MapThemeRecord& other ) const
{
return mVisibleLayerIds.toSet() == other.mVisibleLayerIds.toSet()
&& mPerLayerCheckedLegendSymbols == other.mPerLayerCheckedLegendSymbols
&& mPerLayerCurrentStyle == other.mPerLayerCurrentStyle;
return validLayerRecords() == other.validLayerRecords();
}
bool operator!=( const MapThemeRecord& other ) const
{
return !( *this == other );
}
/**
* Ordered list of visible layers
* @note Added in QGIS 3.0
*/
QStringList visibleLayerIds() const;
//! Returns a list of records for all visible layer belonging to the theme.
QList<MapThemeLayerRecord> layerRecords() const { return mLayerRecords; }
/**
* Ordered list of visible layers
* @note Added in QGIS 3.0
*/
void setVisibleLayerIds( const QStringList& visibleLayerIds );
//! Sets layer records for the theme.
void setLayerRecords( const QList<MapThemeLayerRecord>& records ) { mLayerRecords = records; }
/**
* Lists which legend symbols are checked for layers which support this and where
* not all symbols are checked.
* @note not available in Python bindings
* @note Added in QGIS 3.0
*/
QMap<QString, QSet<QString> > perLayerCheckedLegendSymbols() const;
/**
* Lists which legend symbols are checked for layers which support this and where
* not all symbols are checked.
* @note not available in Python bindings
* @note Added in QGIS 3.0
*/
void setPerLayerCheckedLegendSymbols( const QMap<QString, QSet<QString> >& perLayerCheckedLegendSymbols );
/**
* The currently used style name for layers with multiple styles.
* The map has layer ids as keys and style names as values.
* @note Added in QGIS 3.0
*/
QMap<QString, QString> perLayerCurrentStyle() const;
/**
* The currently used style name for layers with multiple styles.
* The map has layer ids as keys and style names as values.
* @note Added in QGIS 3.0
*/
void setPerLayerCurrentStyle( const QMap<QString, QString>& perLayerCurrentStyle );
//! Return set with only records for valid layers
//! @note not available in python bindings
QHash<QgsMapLayer*, MapThemeLayerRecord> validLayerRecords() const;
private:
QStringList mVisibleLayerIds;
QMap<QString, QSet<QString> > mPerLayerCheckedLegendSymbols;
QMap<QString, QString> mPerLayerCurrentStyle;
//! Layer-specific records for the theme. Only visible layers are listed.
QList<MapThemeLayerRecord> mLayerRecords;
friend class QgsMapThemeCollection;
};
@ -167,7 +174,7 @@ class CORE_EXPORT QgsMapThemeCollection : public QObject
* in the canvas.
* @note Added in QGIS 3.0
*/
QStringList mapThemeVisibleLayers( const QString& name ) const;
QStringList mapThemeVisibleLayerIds( const QString& name ) const;
/**
* Returns the list of layers that are visible for the specified map theme.
@ -176,13 +183,7 @@ class CORE_EXPORT QgsMapThemeCollection : public QObject
* in the canvas.
* @note Added in QGIS 3.0
*/
QList<QgsMapLayer*> mapThemeVisibleLayers2( const QString& name ) const;
/**
* Apply check states of legend nodes of a given layer as defined in the map theme.
* @note Added in QGIS 3.0
*/
void applyMapThemeCheckedLegendNodesToLayer( const QString& name, const QString& layerID );
QList<QgsMapLayer*> mapThemeVisibleLayers( const QString& name ) const;
/**
* Get layer style overrides (for QgsMapSettings) of the visible layers for given map theme.
@ -204,12 +205,18 @@ class CORE_EXPORT QgsMapThemeCollection : public QObject
void writeXml( QDomDocument& doc );
/**
* Static method for adding visible layers from a layer tree group to a map theme
* record.
* @param parent layer tree group parent
* @param rec map theme record to amend
* Static method to create theme from the current state of layer visibilities in layer tree,
* current style of layers and check state of legend items (from a layer tree model).
* @note added in QGIS 3.0
*/
static void addVisibleLayersToMapTheme( QgsLayerTreeGroup* parent, MapThemeRecord& rec );
static MapThemeRecord createThemeFromCurrentState( QgsLayerTreeGroup* root, QgsLayerTreeModel* model );
/**
* Apply theme given by its name and modify layer tree, current style of layers and checked
* legend items of passed layer tree model.
* @note added in QGIS 3.0
*/
void applyTheme( const QString& name, QgsLayerTreeGroup* root, QgsLayerTreeModel* model );
signals:
@ -231,11 +238,22 @@ class CORE_EXPORT QgsMapThemeCollection : public QObject
private:
/**
* Apply check states of legend nodes of a given layer as defined in the map theme.
*/
void applyMapThemeCheckedLegendNodesToLayer( const MapThemeLayerRecord& layerRec, QgsMapLayer* layer );
/**
* Reconnects all map theme layers to handle style renames
*/
void reconnectToLayersStyleManager();
static bool findRecordForLayer( QgsMapLayer* layer, const MapThemeRecord& rec, MapThemeLayerRecord& layerRec );
static MapThemeLayerRecord createThemeLayerRecord( QgsLayerTreeLayer* nodeLayer, QgsLayerTreeModel* model );
static void createThemeFromCurrentState( QgsLayerTreeGroup* parent, QgsLayerTreeModel* model, MapThemeRecord& rec );
static void applyThemeToLayer( QgsLayerTreeLayer* nodeLayer, QgsLayerTreeModel* model, const MapThemeRecord& rec );
static void applyThemeToGroup( QgsLayerTreeGroup* parent, QgsLayerTreeModel* model, const MapThemeRecord& rec );
typedef QMap<QString, MapThemeRecord> MapThemeRecordMap;
MapThemeRecordMap mMapThemes;
//! project used to retrieve layers from layer IDs

View File

@ -90,10 +90,6 @@ void TestQgs25DRenderer::initTestCase()
QgsExpressionContextUtils::setLayerVariable( mpPolysLayer, QStringLiteral( "qgis_25d_height" ), 8 );
QgsExpressionContextUtils::setLayerVariable( mpPolysLayer, QStringLiteral( "qgis_25d_angle" ), 45 );
// Register the layer with the registry
QgsProject::instance()->addMapLayers(
QList<QgsMapLayer *>() << mpPolysLayer );
mMapSettings.setLayers( QList<QgsMapLayer*>() << mpPolysLayer );
mReport += QLatin1String( "<h1>25D Renderer Tests</h1>\n" );
@ -109,6 +105,8 @@ void TestQgs25DRenderer::cleanupTestCase()
myFile.close();
}
delete mpPolysLayer;
QgsApplication::exitQgis();
}

View File

@ -111,8 +111,6 @@ void TestQgsAtlasComposition::initTestCase()
simplifyMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification );
mVectorLayer->setSimplifyMethod( simplifyMethod );
QgsProject::instance()->addMapLayers( QList<QgsMapLayer*>() << mVectorLayer );
mReport = QStringLiteral( "<h1>Composer Atlas Tests</h1>\n" );
}
@ -125,6 +123,7 @@ TestQgsAtlasComposition::~TestQgsAtlasComposition()
void TestQgsAtlasComposition::cleanupTestCase()
{
delete mComposition;
delete mVectorLayer;
QgsApplication::exitQgis();
QString myReportFile = QDir::tempPath() + "/qgistest.html";

View File

@ -97,8 +97,6 @@ void TestQgsBlendModes::initTestCase()
QFileInfo myPointFileInfo( myPointsFileName );
mpPointsLayer = new QgsVectorLayer( myPointFileInfo.filePath(),
myPointFileInfo.completeBaseName(), QStringLiteral( "ogr" ) );
QgsProject::instance()->addMapLayers(
QList<QgsMapLayer *>() << mpPointsLayer );
//create a poly layer that will be used in tests
QString myPolysFileName = mTestDataDir + "polys.shp";
@ -110,8 +108,6 @@ void TestQgsBlendModes::initTestCase()
simplifyMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification );
mpPolysLayer->setSimplifyMethod( simplifyMethod );
QgsProject::instance()->addMapLayers(
QList<QgsMapLayer *>() << mpPolysLayer );
//create a line layer that will be used in tests
QString myLinesFileName = mTestDataDir + "lines.shp";
@ -119,8 +115,6 @@ void TestQgsBlendModes::initTestCase()
mpLinesLayer = new QgsVectorLayer( myLineFileInfo.filePath(),
myLineFileInfo.completeBaseName(), QStringLiteral( "ogr" ) );
mpLinesLayer->setSimplifyMethod( simplifyMethod );
QgsProject::instance()->addMapLayers(
QList<QgsMapLayer *>() << mpLinesLayer );
//create two raster layers
QFileInfo rasterFileInfo( mTestDataDir + "rgb256x256.png" );
@ -131,10 +125,6 @@ void TestQgsBlendModes::initTestCase()
QgsMultiBandColorRenderer* rasterRenderer = new QgsMultiBandColorRenderer( mRasterLayer1->dataProvider(), 1, 2, 3 );
mRasterLayer1->setRenderer( rasterRenderer );
mRasterLayer2->setRenderer(( QgsRasterRenderer* ) rasterRenderer->clone() );
QgsProject::instance()->addMapLayers(
QList<QgsMapLayer *>() << mRasterLayer1 );
QgsProject::instance()->addMapLayers(
QList<QgsMapLayer *>() << mRasterLayer2 );
// points extent was not always reliable
mExtent = QgsRectangle( -118.8888888888887720, 22.8002070393376783, -83.3333333333331581, 46.8719806763287536 );
@ -150,6 +140,12 @@ void TestQgsBlendModes::cleanupTestCase()
myFile.close();
}
delete mpPointsLayer;
delete mpPolysLayer;
delete mpLinesLayer;
delete mRasterLayer1;
delete mRasterLayer2;
QgsApplication::exitQgis();
}

View File

@ -97,10 +97,6 @@ void TestQgsCentroidFillSymbol::initTestCase()
simplifyMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification );
mpPolysLayer->setSimplifyMethod( simplifyMethod );
// Register the layer with the registry
QgsProject::instance()->addMapLayers(
QList<QgsMapLayer *>() << mpPolysLayer );
//setup gradient fill
mCentroidFill = new QgsCentroidFillSymbolLayer();
mFillSymbol = new QgsFillSymbol();
@ -127,6 +123,8 @@ void TestQgsCentroidFillSymbol::cleanupTestCase()
myFile.close();
}
delete mpPolysLayer;
QgsApplication::exitQgis();
}

View File

@ -78,8 +78,6 @@ void TestQgsComposerDD::initTestCase()
simplifyMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification );
mVectorLayer->setSimplifyMethod( simplifyMethod );
QgsProject::instance()->addMapLayers( QList<QgsMapLayer*>() << mVectorLayer );
//create composition with composer map
mMapSettings->setLayers( QList<QgsMapLayer*>() << mVectorLayer );
mMapSettings->setCrsTransformEnabled( true );
@ -117,6 +115,7 @@ void TestQgsComposerDD::cleanupTestCase()
{
delete mComposition;
delete mMapSettings;
delete mVectorLayer;
QString myReportFile = QDir::tempPath() + "/qgistest.html";
QFile myFile( myReportFile );

View File

@ -76,7 +76,6 @@ void TestQgsComposerLabel::initTestCase()
mVectorLayer = new QgsVectorLayer( vectorFileInfo.filePath(),
vectorFileInfo.completeBaseName(),
QStringLiteral( "ogr" ) );
QgsProject::instance()->addMapLayers( QList<QgsMapLayer*>() << mVectorLayer );
//create composition with composer map
mMapSettings->setLayers( QList<QgsMapLayer*>() << mVectorLayer );
@ -104,6 +103,7 @@ void TestQgsComposerLabel::cleanupTestCase()
delete mComposition;
delete mMapSettings;
delete mVectorLayer;
QgsApplication::exitQgis();
}

View File

@ -78,22 +78,18 @@ void TestQgsComposerMap::initTestCase()
rasterFileInfo.completeBaseName() );
QgsMultiBandColorRenderer* rasterRenderer = new QgsMultiBandColorRenderer( mRasterLayer->dataProvider(), 2, 3, 4 );
mRasterLayer->setRenderer( rasterRenderer );
QgsProject::instance()->addMapLayers( QList<QgsMapLayer*>() << mRasterLayer );
QFileInfo pointFileInfo( QStringLiteral( TEST_DATA_DIR ) + "/points.shp" );
mPointsLayer = new QgsVectorLayer( pointFileInfo.filePath(),
pointFileInfo.completeBaseName(), QStringLiteral( "ogr" ) );
QgsProject::instance()->addMapLayers( QList<QgsMapLayer *>() << mPointsLayer );
QFileInfo polyFileInfo( QStringLiteral( TEST_DATA_DIR ) + "/polys.shp" );
mPolysLayer = new QgsVectorLayer( polyFileInfo.filePath(),
polyFileInfo.completeBaseName(), QStringLiteral( "ogr" ) );
QgsProject::instance()->addMapLayers( QList<QgsMapLayer *>() << mPolysLayer );
QFileInfo lineFileInfo( QStringLiteral( TEST_DATA_DIR ) + "/lines.shp" );
mLinesLayer = new QgsVectorLayer( lineFileInfo.filePath(),
lineFileInfo.completeBaseName(), QStringLiteral( "ogr" ) );
QgsProject::instance()->addMapLayers( QList<QgsMapLayer *>() << mLinesLayer );
}
void TestQgsComposerMap::cleanupTestCase()
@ -107,6 +103,11 @@ void TestQgsComposerMap::cleanupTestCase()
myFile.close();
}
delete mRasterLayer;
delete mPointsLayer;
delete mPolysLayer;
delete mLinesLayer;
QgsApplication::exitQgis();
}
@ -349,7 +350,10 @@ void TestQgsComposerMap::dataDefinedStyles()
mComposition->addComposerMap( mComposerMap );
QgsMapThemeCollection::MapThemeRecord rec;
rec.setVisibleLayerIds( QStringList() << mPointsLayer->id() << mLinesLayer->id() );
rec.setLayerRecords( QList<QgsMapThemeCollection::MapThemeLayerRecord>()
<< QgsMapThemeCollection::MapThemeLayerRecord( mPointsLayer )
<< QgsMapThemeCollection::MapThemeLayerRecord( mLinesLayer )
);
QgsProject::instance()->mapThemeCollection()->insert( QStringLiteral( "test preset" ), rec );