Split subclasses of QgsLayerTreeNode into their own cpp/h files

This commit is contained in:
Martin Dobias 2014-05-17 22:29:00 +07:00
parent 56ee3f4040
commit 8a539e0874
9 changed files with 574 additions and 548 deletions

View File

@ -51,6 +51,8 @@ SET(QGIS_CORE_SRCS
diagram/qgstextdiagram.cpp
diagram/qgshistogramdiagram.cpp
layertree/qgslayertreegroup.cpp
layertree/qgslayertreelayer.cpp
layertree/qgslayertreenode.cpp
layertree/qgslayertreeregistrybridge.cpp
layertree/qgslayertreeutils.cpp
@ -380,6 +382,8 @@ SET(QGIS_CORE_MOC_HDRS
symbology-ng/qgssvgcache.h
symbology-ng/qgsstylev2.h
layertree/qgslayertreegroup.h
layertree/qgslayertreelayer.h
layertree/qgslayertreenode.h
layertree/qgslayertreeregistrybridge.h
)
@ -590,6 +594,9 @@ SET(QGIS_CORE_HDRS
symbology-ng/qgscptcityarchive.h
symbology-ng/qgsvectorfieldsymbollayer.h
layertree/qgslayertree.h
layertree/qgslayertreegroup.h
layertree/qgslayertreelayer.h
layertree/qgslayertreenode.h
layertree/qgslayertreeregistrybridge.h
layertree/qgslayertreeutils.h

View File

@ -2,6 +2,8 @@
#define QGSLAYERTREE_H
#include "qgslayertreenode.h"
#include "qgslayertreegroup.h"
#include "qgslayertreelayer.h"
namespace QgsLayerTree
{

View File

@ -0,0 +1,314 @@
#include "qgslayertreegroup.h"
#include "qgslayertree.h"
#include "qgslayertreeutils.h"
QgsLayerTreeGroup::QgsLayerTreeGroup(const QString& name, Qt::CheckState checked)
: QgsLayerTreeNode(NodeGroup)
, mName(name)
, mChecked(checked)
, mChangingChildVisibility(false)
{
}
QgsLayerTreeGroup::QgsLayerTreeGroup(const QgsLayerTreeGroup& other)
: QgsLayerTreeNode(other)
, mName(other.mName)
, mChecked(other.mChecked)
, mChangingChildVisibility(false)
{
}
QgsLayerTreeGroup* QgsLayerTreeGroup::addGroup(const QString &name)
{
QgsLayerTreeGroup* grp = new QgsLayerTreeGroup(name);
addChildNode( grp );
return grp;
}
QgsLayerTreeLayer*QgsLayerTreeGroup::insertLayer(int index, QgsMapLayer* layer)
{
QgsLayerTreeLayer* ll = new QgsLayerTreeLayer(layer);
insertChildNode( index, ll );
return ll;
}
QgsLayerTreeLayer* QgsLayerTreeGroup::addLayer(QgsMapLayer* layer)
{
QgsLayerTreeLayer* ll = new QgsLayerTreeLayer(layer);
addChildNode( ll );
return ll;
}
void QgsLayerTreeGroup::connectToChildNode(QgsLayerTreeNode* node)
{
if (QgsLayerTree::isLayer(node))
{
// TODO: this could be handled directly by LayerTreeLayer by listening to QgsMapLayerRegistry...
//QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer(node);
//connect(nodeLayer->layer(), SIGNAL(destroyed()), this, SLOT(layerDestroyed()));
}
connect(node, SIGNAL(visibilityChanged(Qt::CheckState)), this, SLOT(updateVisibilityFromChildren()));
// forward the signal towards the root
connect(node, SIGNAL(customPropertyChanged(QgsLayerTreeNode*,QString)), this, SIGNAL(customPropertyChanged(QgsLayerTreeNode*,QString)));
}
void QgsLayerTreeGroup::insertChildNode(int index, QgsLayerTreeNode* node)
{
QList<QgsLayerTreeNode*> nodes;
nodes << node;
insertChildNodes(index, nodes);
}
void QgsLayerTreeGroup::insertChildNodes(int index, QList<QgsLayerTreeNode*> nodes)
{
// low-level insert
insertChildren(index, nodes);
foreach (QgsLayerTreeNode* node, nodes)
connectToChildNode(node);
updateVisibilityFromChildren();
}
void QgsLayerTreeGroup::addChildNode(QgsLayerTreeNode* node)
{
insertChildNode(-1, node);
}
void QgsLayerTreeGroup::removeChildNode(QgsLayerTreeNode *node)
{
int i = mChildren.indexOf(node);
if (i >= 0)
removeChildAt(i);
}
void QgsLayerTreeGroup::removeLayer(QgsMapLayer* layer)
{
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isLayer(child))
{
QgsLayerTreeLayer* childLayer = QgsLayerTree::toLayer(child);
if (childLayer->layer() == layer)
{
removeChildAt(mChildren.indexOf(child));
break;
}
}
}
}
void QgsLayerTreeGroup::removeChildren(int from, int count)
{
removeChildrenRange(from, count);
updateVisibilityFromChildren();
}
void QgsLayerTreeGroup::removeAllChildren()
{
removeChildren(0, mChildren.count());
}
QgsLayerTreeLayer *QgsLayerTreeGroup::findLayer(const QString& layerId)
{
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isLayer(child))
{
QgsLayerTreeLayer* childLayer = QgsLayerTree::toLayer(child);
if (childLayer->layerId() == layerId)
return childLayer;
}
else if (QgsLayerTree::isGroup(child))
{
QgsLayerTreeLayer* res = QgsLayerTree::toGroup(child)->findLayer(layerId);
if (res)
return res;
}
}
return 0;
}
QList<QgsLayerTreeLayer*> QgsLayerTreeGroup::findLayers() const
{
QList<QgsLayerTreeLayer*> list;
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isLayer(child))
list << QgsLayerTree::toLayer(child);
else if (QgsLayerTree::isGroup(child))
list << QgsLayerTree::toGroup(child)->findLayers();
}
return list;
}
QgsLayerTreeGroup* QgsLayerTreeGroup::findGroup(const QString& name)
{
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isGroup(child))
{
QgsLayerTreeGroup* childGroup = QgsLayerTree::toGroup(child);
if (childGroup->name() == name)
return childGroup;
else
{
QgsLayerTreeGroup* grp = childGroup->findGroup(name);
if (grp)
return grp;
}
}
}
return 0;
}
QgsLayerTreeGroup* QgsLayerTreeGroup::readXML(QDomElement& element)
{
if (element.tagName() != "layer-tree-group")
return 0;
QString name = element.attribute("name");
bool isExpanded = (element.attribute("expanded", "1") == "1");
Qt::CheckState checked = QgsLayerTreeUtils::checkStateFromXml(element.attribute("checked"));
QgsLayerTreeGroup* groupNode = new QgsLayerTreeGroup(name, checked);
groupNode->setExpanded(isExpanded);
groupNode->readCommonXML(element);
groupNode->readChildrenFromXML(element);
return groupNode;
}
void QgsLayerTreeGroup::writeXML(QDomElement& parentElement)
{
QDomDocument doc = parentElement.ownerDocument();
QDomElement elem = doc.createElement("layer-tree-group");
elem.setAttribute("name", mName);
elem.setAttribute("expanded", mExpanded ? "1" : "0");
elem.setAttribute("checked", QgsLayerTreeUtils::checkStateToXml(mChecked));
writeCommonXML(elem);
foreach (QgsLayerTreeNode* node, mChildren)
node->writeXML(elem);
parentElement.appendChild(elem);
}
void QgsLayerTreeGroup::readChildrenFromXML(QDomElement& element)
{
QDomElement childElem = element.firstChildElement();
while (!childElem.isNull())
{
QgsLayerTreeNode* newNode = QgsLayerTreeNode::readXML(childElem);
if (newNode)
addChildNode(newNode);
childElem = childElem.nextSiblingElement();
}
}
QString QgsLayerTreeGroup::dump() const
{
QString header = QString( "GROUP: %1 visible=%2 expanded=%3\n" ).arg( name() ).arg( mChecked ).arg( mExpanded );
QStringList childrenDump;
foreach (QgsLayerTreeNode* node, mChildren)
childrenDump << node->dump().split( "\n" );
for (int i = 0; i < childrenDump.count(); ++i)
childrenDump[i].prepend( " " );
return header + childrenDump.join( "\n" );
}
QgsLayerTreeNode* QgsLayerTreeGroup::clone() const
{
return new QgsLayerTreeGroup(*this);
}
void QgsLayerTreeGroup::setVisible(Qt::CheckState state)
{
if (mChecked == state)
return;
mChecked = state;
emit visibilityChanged(state);
if (mChecked == Qt::Unchecked || mChecked == Qt::Checked)
{
mChangingChildVisibility = true; // guard against running again setVisible() triggered from children
// update children to have the correct visibility
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isGroup(child))
QgsLayerTree::toGroup(child)->setVisible(mChecked);
else if (QgsLayerTree::isLayer(child))
QgsLayerTree::toLayer(child)->setVisible(mChecked == Qt::Checked);
}
mChangingChildVisibility = false;
}
}
QStringList QgsLayerTreeGroup::childLayerIds() const
{
QStringList lst;
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isGroup(child))
lst << QgsLayerTree::toGroup(child)->childLayerIds();
else if (QgsLayerTree::isLayer(child))
lst << QgsLayerTree::toLayer(child)->layerId();
}
return lst;
}
void QgsLayerTreeGroup::layerDestroyed()
{
QgsMapLayer* layer = static_cast<QgsMapLayer*>(sender());
removeLayer(layer);
}
void QgsLayerTreeGroup::updateVisibilityFromChildren()
{
if (mChangingChildVisibility)
return;
if (mChildren.count() == 0)
return;
bool hasVisible = false, hasHidden = false;
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isLayer(child))
{
bool layerVisible = QgsLayerTree::toLayer(child)->isVisible();
if (layerVisible) hasVisible = true;
if (!layerVisible) hasHidden = true;
}
else if (QgsLayerTree::isGroup(child))
{
Qt::CheckState state = QgsLayerTree::toGroup(child)->isVisible();
if (state == Qt::Checked || state == Qt::PartiallyChecked) hasVisible = true;
if (state == Qt::Unchecked || state == Qt::PartiallyChecked) hasHidden = true;
}
}
Qt::CheckState newState;
if (hasVisible && !hasHidden)
newState = Qt::Checked;
else if (hasHidden && !hasVisible)
newState = Qt::Unchecked;
else
newState = Qt::PartiallyChecked;
setVisible(newState);
}

View File

@ -0,0 +1,67 @@
#ifndef QGSLAYERTREEGROUP_H
#define QGSLAYERTREEGROUP_H
#include "qgslayertreenode.h"
class QgsLayerTreeLayer;
class QgsLayerTreeGroup : public QgsLayerTreeNode
{
Q_OBJECT
public:
QgsLayerTreeGroup(const QString& name = QString(), Qt::CheckState checked = Qt::Checked);
QgsLayerTreeGroup(const QgsLayerTreeGroup& other);
QString name() const { return mName; }
void setName(const QString& n) { mName = n; }
QgsLayerTreeGroup* addGroup(const QString& name);
QgsLayerTreeLayer* insertLayer(int index, QgsMapLayer* layer);
QgsLayerTreeLayer* addLayer(QgsMapLayer* layer);
void insertChildNodes(int index, QList<QgsLayerTreeNode*> nodes);
void insertChildNode(int index, QgsLayerTreeNode* node);
void addChildNode(QgsLayerTreeNode* node);
void removeChildNode(QgsLayerTreeNode* node);
void removeLayer(QgsMapLayer* layer);
void removeChildren(int from, int count);
void removeAllChildren();
QgsLayerTreeLayer* findLayer(const QString& layerId);
QList<QgsLayerTreeLayer*> findLayers() const;
QgsLayerTreeGroup* findGroup(const QString& name);
static QgsLayerTreeGroup* readXML(QDomElement& element);
virtual void writeXML(QDomElement& parentElement);
void readChildrenFromXML(QDomElement& element);
virtual QString dump() const;
virtual QgsLayerTreeNode* clone() const;
Qt::CheckState isVisible() const { return mChecked; }
void setVisible(Qt::CheckState state);
QStringList childLayerIds() const;
protected slots:
void layerDestroyed();
void updateVisibilityFromChildren();
protected:
void connectToChildNode(QgsLayerTreeNode* node);
protected:
QString mName;
Qt::CheckState mChecked;
bool mChangingChildVisibility;
};
#endif // QGSLAYERTREEGROUP_H

View File

@ -0,0 +1,122 @@
#include "qgslayertreelayer.h"
#include "qgsmaplayerregistry.h"
QgsLayerTreeLayer::QgsLayerTreeLayer(QgsMapLayer *layer)
: QgsLayerTreeNode(NodeLayer), mLayerId(layer->id()), mLayer(layer), mVisible(true)
{
Q_ASSERT( QgsMapLayerRegistry::instance()->mapLayer(mLayerId) == layer );
}
QgsLayerTreeLayer::QgsLayerTreeLayer(QString layerId, QString name)
: QgsLayerTreeNode(NodeLayer)
, mLayerId(layerId)
, mLayerName(name)
, mLayer(0)
, mVisible(true)
{
attachToLayer();
}
QgsLayerTreeLayer::QgsLayerTreeLayer(const QgsLayerTreeLayer& other)
: QgsLayerTreeNode(other)
, mLayerId(other.mLayerId)
, mLayerName(other.mLayerName)
, mLayer(0)
, mVisible(other.mVisible)
{
attachToLayer();
}
void QgsLayerTreeLayer::attachToLayer()
{
// layer is not necessarily already loaded
QgsMapLayer* l = QgsMapLayerRegistry::instance()->mapLayer(mLayerId);
if (l)
{
mLayer = l;
mLayerName = l->name();
}
else
{
if (mLayerName.isEmpty())
mLayerName = "(?)";
// wait for the layer to be eventually loaded
connect(QgsMapLayerRegistry::instance(), SIGNAL(layersAdded(QList<QgsMapLayer*>)), this, SLOT(registryLayersAdded(QList<QgsMapLayer*>)));
}
}
void QgsLayerTreeLayer::setVisible(bool state)
{
if (mVisible == state)
return;
mVisible = state;
emit visibilityChanged(state ? Qt::Checked : Qt::Unchecked);
}
QgsLayerTreeLayer* QgsLayerTreeLayer::readXML(QDomElement& element)
{
if (element.tagName() != "layer-tree-layer")
return 0;
QString layerID = element.attribute("id");
QString layerName = element.attribute("name");
bool visible = element.attribute("visible").toInt();
bool isExpanded = (element.attribute("expanded", "1") == "1");
QgsLayerTreeLayer* nodeLayer = 0;
// TODO: maybe allow other sources of layers than just registry singleton?
QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer(layerID);
if (layer)
nodeLayer = new QgsLayerTreeLayer(layer);
else
nodeLayer = new QgsLayerTreeLayer(layerID, layerName);
nodeLayer->readCommonXML(element);
nodeLayer->setVisible(visible);
nodeLayer->setExpanded(isExpanded);
return nodeLayer;
}
void QgsLayerTreeLayer::writeXML(QDomElement& parentElement)
{
QDomDocument doc = parentElement.ownerDocument();
QDomElement elem = doc.createElement("layer-tree-layer");
elem.setAttribute("id", mLayerId);
elem.setAttribute("name", layerName());
elem.setAttribute("visible", mVisible ? "1" : "0");
elem.setAttribute("expanded", mExpanded ? "1" : "0");
writeCommonXML(elem);
parentElement.appendChild(elem);
}
QString QgsLayerTreeLayer::dump() const
{
return QString( "LAYER: %1 visible=%2 expanded=%3 id=%4\n" ).arg( layerName() ).arg( mVisible ).arg( mExpanded ).arg( layerId() );
}
QgsLayerTreeNode* QgsLayerTreeLayer::clone() const
{
return new QgsLayerTreeLayer(*this);
}
void QgsLayerTreeLayer::registryLayersAdded(QList<QgsMapLayer*> layers)
{
foreach (QgsMapLayer* l, layers)
{
if (l->id() == mLayerId)
{
mLayer = l;
disconnect(QgsMapLayerRegistry::instance(), SIGNAL(layersAdded(QList<QgsMapLayer*>)), this, SLOT(registryLayersAdded(QList<QgsMapLayer*>)));
emit layerLoaded();
break;
}
}
}

View File

@ -0,0 +1,61 @@
#ifndef QGSLAYERTREELAYER_H
#define QGSLAYERTREELAYER_H
#include "qgslayertreenode.h"
/**
* Layer Node
*
* It is expected that the layer is registered in QgsMapLayerRegistry.
*
* One layer is supposed to be present in one layer tree just once. It is possible that temporarily a layer
* temporarily exists in one tree more than once, e.g. while reordering items.
*
* Can exist also without a valid instance of a layer (just ID),
* so that referenced layer does not need to be loaded in order to use it in layer tree.
*/
class QgsLayerTreeLayer : public QgsLayerTreeNode
{
Q_OBJECT
public:
explicit QgsLayerTreeLayer(QgsMapLayer* layer);
QgsLayerTreeLayer(const QgsLayerTreeLayer& other);
explicit QgsLayerTreeLayer(QString layerId, QString name = QString());
QString layerId() const { return mLayerId; }
QgsMapLayer* layer() const { return mLayer; }
QString layerName() const { return mLayer ? mLayer->name() : mLayerName; }
void setLayerName(const QString& n) { if (mLayer) mLayer->setLayerName(n); else mLayerName = n; }
bool isVisible() const { return mVisible; }
void setVisible(bool state);
static QgsLayerTreeLayer* readXML(QDomElement& element);
virtual void writeXML(QDomElement& parentElement);
virtual QString dump() const;
virtual QgsLayerTreeNode* clone() const;
protected slots:
void registryLayersAdded(QList<QgsMapLayer*> layers);
signals:
//! emitted when a previously unavailable layer got loaded
void layerLoaded();
protected:
void attachToLayer();
QString mLayerId;
QString mLayerName; // only used if layer does not exist
QgsMapLayer* mLayer; // not owned! may be null
bool mVisible;
};
#endif // QGSLAYERTREELAYER_H

View File

@ -1,7 +1,5 @@
#include "qgslayertreenode.h"
#include "qgsmaplayerregistry.h"
#include "qgslayertree.h"
#include "qgslayertreeutils.h"
@ -120,437 +118,3 @@ void QgsLayerTreeNode::removeChildrenRange(int from, int count)
}
emit removedChildren(from, to);
}
// -----
QgsLayerTreeGroup::QgsLayerTreeGroup(const QString& name, Qt::CheckState checked)
: QgsLayerTreeNode(NodeGroup)
, mName(name)
, mChecked(checked)
, mChangingChildVisibility(false)
{
}
QgsLayerTreeGroup::QgsLayerTreeGroup(const QgsLayerTreeGroup& other)
: QgsLayerTreeNode(other)
, mName(other.mName)
, mChecked(other.mChecked)
, mChangingChildVisibility(false)
{
}
QgsLayerTreeGroup* QgsLayerTreeGroup::addGroup(const QString &name)
{
QgsLayerTreeGroup* grp = new QgsLayerTreeGroup(name);
addChildNode( grp );
return grp;
}
QgsLayerTreeLayer*QgsLayerTreeGroup::insertLayer(int index, QgsMapLayer* layer)
{
QgsLayerTreeLayer* ll = new QgsLayerTreeLayer(layer);
insertChildNode( index, ll );
return ll;
}
QgsLayerTreeLayer* QgsLayerTreeGroup::addLayer(QgsMapLayer* layer)
{
QgsLayerTreeLayer* ll = new QgsLayerTreeLayer(layer);
addChildNode( ll );
return ll;
}
void QgsLayerTreeGroup::connectToChildNode(QgsLayerTreeNode* node)
{
if (QgsLayerTree::isLayer(node))
{
// TODO: this could be handled directly by LayerTreeLayer by listening to QgsMapLayerRegistry...
//QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer(node);
//connect(nodeLayer->layer(), SIGNAL(destroyed()), this, SLOT(layerDestroyed()));
}
connect(node, SIGNAL(visibilityChanged(Qt::CheckState)), this, SLOT(updateVisibilityFromChildren()));
// forward the signal towards the root
connect(node, SIGNAL(customPropertyChanged(QgsLayerTreeNode*,QString)), this, SIGNAL(customPropertyChanged(QgsLayerTreeNode*,QString)));
}
void QgsLayerTreeGroup::insertChildNode(int index, QgsLayerTreeNode* node)
{
QList<QgsLayerTreeNode*> nodes;
nodes << node;
insertChildNodes(index, nodes);
}
void QgsLayerTreeGroup::insertChildNodes(int index, QList<QgsLayerTreeNode*> nodes)
{
// low-level insert
insertChildren(index, nodes);
foreach (QgsLayerTreeNode* node, nodes)
connectToChildNode(node);
updateVisibilityFromChildren();
}
void QgsLayerTreeGroup::addChildNode(QgsLayerTreeNode* node)
{
insertChildNode(-1, node);
}
void QgsLayerTreeGroup::removeChildNode(QgsLayerTreeNode *node)
{
int i = mChildren.indexOf(node);
if (i >= 0)
removeChildAt(i);
}
void QgsLayerTreeGroup::removeLayer(QgsMapLayer* layer)
{
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isLayer(child))
{
QgsLayerTreeLayer* childLayer = QgsLayerTree::toLayer(child);
if (childLayer->layer() == layer)
{
removeChildAt(mChildren.indexOf(child));
break;
}
}
}
}
void QgsLayerTreeGroup::removeChildren(int from, int count)
{
removeChildrenRange(from, count);
updateVisibilityFromChildren();
}
void QgsLayerTreeGroup::removeAllChildren()
{
removeChildren(0, mChildren.count());
}
QgsLayerTreeLayer *QgsLayerTreeGroup::findLayer(const QString& layerId)
{
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isLayer(child))
{
QgsLayerTreeLayer* childLayer = QgsLayerTree::toLayer(child);
if (childLayer->layerId() == layerId)
return childLayer;
}
else if (QgsLayerTree::isGroup(child))
{
QgsLayerTreeLayer* res = QgsLayerTree::toGroup(child)->findLayer(layerId);
if (res)
return res;
}
}
return 0;
}
QList<QgsLayerTreeLayer*> QgsLayerTreeGroup::findLayers() const
{
QList<QgsLayerTreeLayer*> list;
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isLayer(child))
list << QgsLayerTree::toLayer(child);
else if (QgsLayerTree::isGroup(child))
list << QgsLayerTree::toGroup(child)->findLayers();
}
return list;
}
QgsLayerTreeGroup* QgsLayerTreeGroup::findGroup(const QString& name)
{
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isGroup(child))
{
QgsLayerTreeGroup* childGroup = QgsLayerTree::toGroup(child);
if (childGroup->name() == name)
return childGroup;
else
{
QgsLayerTreeGroup* grp = childGroup->findGroup(name);
if (grp)
return grp;
}
}
}
return 0;
}
QgsLayerTreeGroup* QgsLayerTreeGroup::readXML(QDomElement& element)
{
if (element.tagName() != "layer-tree-group")
return 0;
QString name = element.attribute("name");
bool isExpanded = (element.attribute("expanded", "1") == "1");
Qt::CheckState checked = QgsLayerTreeUtils::checkStateFromXml(element.attribute("checked"));
QgsLayerTreeGroup* groupNode = new QgsLayerTreeGroup(name, checked);
groupNode->setExpanded(isExpanded);
groupNode->readCommonXML(element);
groupNode->readChildrenFromXML(element);
return groupNode;
}
void QgsLayerTreeGroup::writeXML(QDomElement& parentElement)
{
QDomDocument doc = parentElement.ownerDocument();
QDomElement elem = doc.createElement("layer-tree-group");
elem.setAttribute("name", mName);
elem.setAttribute("expanded", mExpanded ? "1" : "0");
elem.setAttribute("checked", QgsLayerTreeUtils::checkStateToXml(mChecked));
writeCommonXML(elem);
foreach (QgsLayerTreeNode* node, mChildren)
node->writeXML(elem);
parentElement.appendChild(elem);
}
void QgsLayerTreeGroup::readChildrenFromXML(QDomElement& element)
{
QDomElement childElem = element.firstChildElement();
while (!childElem.isNull())
{
QgsLayerTreeNode* newNode = QgsLayerTreeNode::readXML(childElem);
if (newNode)
addChildNode(newNode);
childElem = childElem.nextSiblingElement();
}
}
QString QgsLayerTreeGroup::dump() const
{
QString header = QString( "GROUP: %1 visible=%2 expanded=%3\n" ).arg( name() ).arg( mChecked ).arg( mExpanded );
QStringList childrenDump;
foreach (QgsLayerTreeNode* node, mChildren)
childrenDump << node->dump().split( "\n" );
for (int i = 0; i < childrenDump.count(); ++i)
childrenDump[i].prepend( " " );
return header + childrenDump.join( "\n" );
}
QgsLayerTreeNode* QgsLayerTreeGroup::clone() const
{
return new QgsLayerTreeGroup(*this);
}
void QgsLayerTreeGroup::setVisible(Qt::CheckState state)
{
if (mChecked == state)
return;
mChecked = state;
emit visibilityChanged(state);
if (mChecked == Qt::Unchecked || mChecked == Qt::Checked)
{
mChangingChildVisibility = true; // guard against running again setVisible() triggered from children
// update children to have the correct visibility
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isGroup(child))
QgsLayerTree::toGroup(child)->setVisible(mChecked);
else if (QgsLayerTree::isLayer(child))
QgsLayerTree::toLayer(child)->setVisible(mChecked == Qt::Checked);
}
mChangingChildVisibility = false;
}
}
QStringList QgsLayerTreeGroup::childLayerIds() const
{
QStringList lst;
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isGroup(child))
lst << QgsLayerTree::toGroup(child)->childLayerIds();
else if (QgsLayerTree::isLayer(child))
lst << QgsLayerTree::toLayer(child)->layerId();
}
return lst;
}
void QgsLayerTreeGroup::layerDestroyed()
{
QgsMapLayer* layer = static_cast<QgsMapLayer*>(sender());
removeLayer(layer);
}
void QgsLayerTreeGroup::updateVisibilityFromChildren()
{
if (mChangingChildVisibility)
return;
if (mChildren.count() == 0)
return;
bool hasVisible = false, hasHidden = false;
foreach (QgsLayerTreeNode* child, mChildren)
{
if (QgsLayerTree::isLayer(child))
{
bool layerVisible = QgsLayerTree::toLayer(child)->isVisible();
if (layerVisible) hasVisible = true;
if (!layerVisible) hasHidden = true;
}
else if (QgsLayerTree::isGroup(child))
{
Qt::CheckState state = QgsLayerTree::toGroup(child)->isVisible();
if (state == Qt::Checked || state == Qt::PartiallyChecked) hasVisible = true;
if (state == Qt::Unchecked || state == Qt::PartiallyChecked) hasHidden = true;
}
}
Qt::CheckState newState;
if (hasVisible && !hasHidden)
newState = Qt::Checked;
else if (hasHidden && !hasVisible)
newState = Qt::Unchecked;
else
newState = Qt::PartiallyChecked;
setVisible(newState);
}
// ----------
QgsLayerTreeLayer::QgsLayerTreeLayer(QgsMapLayer *layer)
: QgsLayerTreeNode(NodeLayer), mLayerId(layer->id()), mLayer(layer), mVisible(true)
{
Q_ASSERT( QgsMapLayerRegistry::instance()->mapLayer(mLayerId) == layer );
}
QgsLayerTreeLayer::QgsLayerTreeLayer(QString layerId, QString name)
: QgsLayerTreeNode(NodeLayer)
, mLayerId(layerId)
, mLayerName(name)
, mLayer(0)
, mVisible(true)
{
attachToLayer();
}
QgsLayerTreeLayer::QgsLayerTreeLayer(const QgsLayerTreeLayer& other)
: QgsLayerTreeNode(other)
, mLayerId(other.mLayerId)
, mLayerName(other.mLayerName)
, mLayer(0)
, mVisible(other.mVisible)
{
attachToLayer();
}
void QgsLayerTreeLayer::attachToLayer()
{
// layer is not necessarily already loaded
QgsMapLayer* l = QgsMapLayerRegistry::instance()->mapLayer(mLayerId);
if (l)
{
mLayer = l;
mLayerName = l->name();
}
else
{
if (mLayerName.isEmpty())
mLayerName = "(?)";
// wait for the layer to be eventually loaded
connect(QgsMapLayerRegistry::instance(), SIGNAL(layersAdded(QList<QgsMapLayer*>)), this, SLOT(registryLayersAdded(QList<QgsMapLayer*>)));
}
}
void QgsLayerTreeLayer::setVisible(bool state)
{
if (mVisible == state)
return;
mVisible = state;
emit visibilityChanged(state ? Qt::Checked : Qt::Unchecked);
}
QgsLayerTreeLayer* QgsLayerTreeLayer::readXML(QDomElement& element)
{
if (element.tagName() != "layer-tree-layer")
return 0;
QString layerID = element.attribute("id");
QString layerName = element.attribute("name");
bool visible = element.attribute("visible").toInt();
bool isExpanded = (element.attribute("expanded", "1") == "1");
QgsLayerTreeLayer* nodeLayer = 0;
// TODO: maybe allow other sources of layers than just registry singleton?
QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer(layerID);
if (layer)
nodeLayer = new QgsLayerTreeLayer(layer);
else
nodeLayer = new QgsLayerTreeLayer(layerID, layerName);
nodeLayer->readCommonXML(element);
nodeLayer->setVisible(visible);
nodeLayer->setExpanded(isExpanded);
return nodeLayer;
}
void QgsLayerTreeLayer::writeXML(QDomElement& parentElement)
{
QDomDocument doc = parentElement.ownerDocument();
QDomElement elem = doc.createElement("layer-tree-layer");
elem.setAttribute("id", mLayerId);
elem.setAttribute("name", layerName());
elem.setAttribute("visible", mVisible ? "1" : "0");
elem.setAttribute("expanded", mExpanded ? "1" : "0");
writeCommonXML(elem);
parentElement.appendChild(elem);
}
QString QgsLayerTreeLayer::dump() const
{
return QString( "LAYER: %1 visible=%2 expanded=%3 id=%4\n" ).arg( layerName() ).arg( mVisible ).arg( mExpanded ).arg( layerId() );
}
QgsLayerTreeNode* QgsLayerTreeLayer::clone() const
{
return new QgsLayerTreeLayer(*this);
}
void QgsLayerTreeLayer::registryLayersAdded(QList<QgsMapLayer*> layers)
{
foreach (QgsMapLayer* l, layers)
{
if (l->id() == mLayerId)
{
mLayer = l;
disconnect(QgsMapLayerRegistry::instance(), SIGNAL(layersAdded(QList<QgsMapLayer*>)), this, SLOT(registryLayersAdded(QList<QgsMapLayer*>)));
emit layerLoaded();
break;
}
}
}

View File

@ -85,117 +85,6 @@ protected:
QgsObjectCustomProperties mProperties;
};
/**
* Layer Node
*
* It is expected that the layer is registered in QgsMapLayerRegistry.
*
* One layer is supposed to be present in one layer tree just once. It is possible that temporarily a layer
* temporarily exists in one tree more than once, e.g. while reordering items.
*
* Can exist also without a valid instance of a layer (just ID),
* so that referenced layer does not need to be loaded in order to use it in layer tree.
*/
class QgsLayerTreeLayer : public QgsLayerTreeNode
{
Q_OBJECT
public:
explicit QgsLayerTreeLayer(QgsMapLayer* layer);
QgsLayerTreeLayer(const QgsLayerTreeLayer& other);
explicit QgsLayerTreeLayer(QString layerId, QString name = QString());
QString layerId() const { return mLayerId; }
QgsMapLayer* layer() const { return mLayer; }
QString layerName() const { return mLayer ? mLayer->name() : mLayerName; }
void setLayerName(const QString& n) { if (mLayer) mLayer->setLayerName(n); else mLayerName = n; }
bool isVisible() const { return mVisible; }
void setVisible(bool state);
static QgsLayerTreeLayer* readXML(QDomElement& element);
virtual void writeXML(QDomElement& parentElement);
virtual QString dump() const;
virtual QgsLayerTreeNode* clone() const;
protected slots:
void registryLayersAdded(QList<QgsMapLayer*> layers);
signals:
//! emitted when a previously unavailable layer got loaded
void layerLoaded();
protected:
void attachToLayer();
QString mLayerId;
QString mLayerName; // only used if layer does not exist
QgsMapLayer* mLayer; // not owned! may be null
bool mVisible;
};
class QgsLayerTreeGroup : public QgsLayerTreeNode
{
Q_OBJECT
public:
QgsLayerTreeGroup(const QString& name = QString(), Qt::CheckState checked = Qt::Checked);
QgsLayerTreeGroup(const QgsLayerTreeGroup& other);
QString name() const { return mName; }
void setName(const QString& n) { mName = n; }
QgsLayerTreeGroup* addGroup(const QString& name);
QgsLayerTreeLayer* insertLayer(int index, QgsMapLayer* layer);
QgsLayerTreeLayer* addLayer(QgsMapLayer* layer);
void insertChildNodes(int index, QList<QgsLayerTreeNode*> nodes);
void insertChildNode(int index, QgsLayerTreeNode* node);
void addChildNode(QgsLayerTreeNode* node);
void removeChildNode(QgsLayerTreeNode* node);
void removeLayer(QgsMapLayer* layer);
void removeChildren(int from, int count);
void removeAllChildren();
QgsLayerTreeLayer* findLayer(const QString& layerId);
QList<QgsLayerTreeLayer*> findLayers() const;
QgsLayerTreeGroup* findGroup(const QString& name);
static QgsLayerTreeGroup* readXML(QDomElement& element);
virtual void writeXML(QDomElement& parentElement);
void readChildrenFromXML(QDomElement& element);
virtual QString dump() const;
virtual QgsLayerTreeNode* clone() const;
Qt::CheckState isVisible() const { return mChecked; }
void setVisible(Qt::CheckState state);
QStringList childLayerIds() const;
protected slots:
void layerDestroyed();
void updateVisibilityFromChildren();
protected:
void connectToChildNode(QgsLayerTreeNode* node);
protected:
QString mName;
Qt::CheckState mChecked;
bool mChangingChildVisibility;
};

View File

@ -1,6 +1,6 @@
#include "qgslayertreeutils.h"
#include "qgslayertreenode.h"
#include "qgslayertree.h"
#include "qgsvectorlayer.h"