| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| #include "qgsapplayertreeviewmenuprovider.h" | ||
|
|
||
|
|
||
| #include "qgisapp.h" | ||
| #include "qgsapplication.h" | ||
| #include "qgsclipboard.h" | ||
| #include "qgslayertree.h" | ||
| #include "qgslayertreemodel.h" | ||
| #include "qgslayertreeviewdefaultactions.h" | ||
| #include "qgsproject.h" | ||
| #include "qgsrasterlayer.h" | ||
| #include "qgsvectordataprovider.h" | ||
| #include "qgsvectorlayer.h" | ||
|
|
||
|
|
||
| QgsAppLayerTreeViewMenuProvider::QgsAppLayerTreeViewMenuProvider( QgsLayerTreeView* view, QgsMapCanvas* canvas ) | ||
| : mView( view ) | ||
| , mCanvas( canvas ) | ||
| { | ||
| } | ||
|
|
||
|
|
||
| QMenu* QgsAppLayerTreeViewMenuProvider::createContextMenu() | ||
| { | ||
| QMenu* menu = new QMenu; | ||
|
|
||
| QgsLayerTreeViewDefaultActions* actions = mView->defaultActions(); | ||
|
|
||
| QModelIndex idx = mView->currentIndex(); | ||
| if ( !idx.isValid() ) | ||
| { | ||
| // global menu | ||
| menu->addAction( actions->actionAddGroup( menu ) ); | ||
|
|
||
| // TODO: expand all, collapse all | ||
| // TODO: update drawing order | ||
| } | ||
| else if ( QgsLayerTreeNode* node = mView->layerTreeModel()->index2node( idx ) ) | ||
| { | ||
| // layer or group selected | ||
| if ( QgsLayerTree::isGroup( node ) ) | ||
| { | ||
| menu->addAction( actions->actionZoomToGroup( mCanvas, menu ) ); | ||
| menu->addAction( actions->actionRemoveGroupOrLayer( menu ) ); | ||
|
|
||
| menu->addAction( QgsApplication::getThemeIcon( "/mActionSetCRS.png" ), | ||
| tr( "&Set Group CRS" ), QgisApp::instance(), SLOT( legendGroupSetCRS() ) ); | ||
|
|
||
| menu->addAction( actions->actionRenameGroupOrLayer( menu ) ); | ||
|
|
||
| if ( mView->selectedNodes( true ).count() >= 2 ) | ||
| menu->addAction( actions->actionGroupSelected( menu ) ); | ||
|
|
||
| menu->addAction( actions->actionAddGroup( menu ) ); | ||
| } | ||
| else if ( QgsLayerTree::isLayer( node ) ) | ||
| { | ||
| QgsMapLayer* layer = QgsLayerTree::toLayer( node )->layer(); | ||
|
|
||
| menu->addAction( actions->actionZoomToLayer( mCanvas, menu ) ); | ||
| menu->addAction( actions->actionShowInOverview( menu ) ); | ||
|
|
||
| if ( layer && layer->type() == QgsMapLayer::RasterLayer ) | ||
| { | ||
| menu->addAction( tr( "&Zoom to Best Scale (100%)" ), QgisApp::instance(), SLOT( legendLayerZoomNative() ) ); | ||
|
|
||
| QgsRasterLayer* rasterLayer = qobject_cast<QgsRasterLayer *>( layer ); | ||
| if ( rasterLayer && rasterLayer->rasterType() != QgsRasterLayer::Palette ) | ||
| menu->addAction( tr( "&Stretch Using Current Extent" ), QgisApp::instance(), SLOT( legendLayerStretchUsingCurrentExtent() ) ); | ||
| } | ||
|
|
||
| menu->addAction( actions->actionRemoveGroupOrLayer( menu ) ); | ||
|
|
||
| // duplicate layer | ||
| QAction* duplicateLayersAction = menu->addAction( QgsApplication::getThemeIcon( "/mActionDuplicateLayer.svg" ), tr( "&Duplicate" ), QgisApp::instance(), SLOT( duplicateLayers() ) ); | ||
|
|
||
| // set layer scale visibility | ||
| menu->addAction( tr( "&Set Layer Scale Visibility" ), QgisApp::instance(), SLOT( setLayerScaleVisibility() ) ); | ||
|
|
||
| // set layer crs | ||
| menu->addAction( QgsApplication::getThemeIcon( "/mActionSetCRS.png" ), tr( "&Set Layer CRS" ), QgisApp::instance(), SLOT( setLayerCRS() ) ); | ||
|
|
||
| // assign layer crs to project | ||
| menu->addAction( QgsApplication::getThemeIcon( "/mActionSetProjectCRS.png" ), tr( "Set &Project CRS from Layer" ), QgisApp::instance(), SLOT( setProjectCRSFromLayer() ) ); | ||
|
|
||
| menu->addSeparator(); | ||
|
|
||
| if ( layer && layer->type() == QgsMapLayer::VectorLayer ) | ||
| { | ||
| QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( layer ); | ||
|
|
||
| QAction *toggleEditingAction = QgisApp::instance()->actionToggleEditing(); | ||
| QAction *saveLayerEditsAction = QgisApp::instance()->actionSaveActiveLayerEdits(); | ||
| QAction *allEditsAction = QgisApp::instance()->actionAllEdits(); | ||
|
|
||
| // attribute table | ||
| menu->addAction( QgsApplication::getThemeIcon( "/mActionOpenTable.png" ), tr( "&Open Attribute Table" ), | ||
| QgisApp::instance(), SLOT( attributeTable() ) ); | ||
|
|
||
| // allow editing | ||
| int cap = vlayer->dataProvider()->capabilities(); | ||
| if ( cap & QgsVectorDataProvider::EditingCapabilities ) | ||
| { | ||
| if ( toggleEditingAction ) | ||
| { | ||
| menu->addAction( toggleEditingAction ); | ||
| toggleEditingAction->setChecked( vlayer->isEditable() ); | ||
| } | ||
| if ( saveLayerEditsAction && vlayer->isModified() ) | ||
| { | ||
| menu->addAction( saveLayerEditsAction ); | ||
| } | ||
| } | ||
|
|
||
| if ( allEditsAction->isEnabled() ) | ||
| menu->addAction( allEditsAction ); | ||
|
|
||
| // disable duplication of memory layers | ||
| if ( vlayer->storageType() == "Memory storage" && mView->selectedLayerNodes().count() == 1 ) | ||
| duplicateLayersAction->setEnabled( false ); | ||
|
|
||
| // save as vector file | ||
| menu->addAction( tr( "Save As..." ), QgisApp::instance(), SLOT( saveAsFile() ) ); | ||
| menu->addAction( tr( "Save As Layer Definition File..." ), QgisApp::instance(), SLOT( saveAsLayerDefinition() ) ); | ||
|
|
||
| if ( !vlayer->isEditable() && vlayer->dataProvider()->supportsSubsetString() && vlayer->vectorJoins().isEmpty() ) | ||
| menu->addAction( tr( "&Filter..." ), QgisApp::instance(), SLOT( layerSubsetString() ) ); | ||
|
|
||
| menu->addAction( actions->actionShowFeatureCount( menu ) ); | ||
|
|
||
| menu->addSeparator(); | ||
| } | ||
| else if ( layer && layer->type() == QgsMapLayer::RasterLayer ) | ||
| { | ||
| menu->addAction( tr( "Save As..." ), QgisApp::instance(), SLOT( saveAsRasterFile() ) ); | ||
| menu->addAction( tr( "Save As Layer Definition File..." ), QgisApp::instance(), SLOT( saveAsLayerDefinition() ) ); | ||
| } | ||
| else if ( layer && layer->type() == QgsMapLayer::PluginLayer && mView->selectedLayerNodes().count() == 1 ) | ||
| { | ||
| // disable duplication of plugin layers | ||
| duplicateLayersAction->setEnabled( false ); | ||
| } | ||
|
|
||
| // TODO: custom actions | ||
|
|
||
| if ( layer && QgsProject::instance()->layerIsEmbedded( layer->id() ).isEmpty() ) | ||
| menu->addAction( tr( "&Properties" ), QgisApp::instance(), SLOT( layerProperties() ) ); | ||
|
|
||
| if ( node->parent() != mView->layerTreeModel()->rootGroup() ) | ||
| menu->addAction( actions->actionMakeTopLevel( menu ) ); | ||
|
|
||
| menu->addAction( actions->actionRenameGroupOrLayer( menu ) ); | ||
|
|
||
| if ( mView->selectedNodes( true ).count() >= 2 ) | ||
| menu->addAction( actions->actionGroupSelected( menu ) ); | ||
|
|
||
| if ( mView->selectedLayerNodes().count() == 1 ) | ||
| { | ||
| QgisApp* app = QgisApp::instance(); | ||
| menu->addAction( tr( "Copy Style" ), app, SLOT( copyStyle() ) ); | ||
| if ( app->clipboard()->hasFormat( QGSCLIPBOARD_STYLE_MIME ) ) | ||
| { | ||
| menu->addAction( tr( "Paste Style" ), app, SLOT( pasteStyle() ) ); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| } | ||
| else | ||
| { | ||
| // symbology item? | ||
| } | ||
|
|
||
| return menu; | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| #ifndef QGSAPPLAYERTREEVIEWMENUPROVIDER_H | ||
| #define QGSAPPLAYERTREEVIEWMENUPROVIDER_H | ||
|
|
||
| #include <QObject> | ||
|
|
||
| #include "qgslayertreeview.h" | ||
|
|
||
| class QgsMapCanvas; | ||
|
|
||
|
|
||
| class QgsAppLayerTreeViewMenuProvider : public QObject, public QgsLayerTreeViewMenuProvider | ||
| { | ||
| public: | ||
| QgsAppLayerTreeViewMenuProvider(QgsLayerTreeView* view, QgsMapCanvas* canvas); | ||
|
|
||
| QMenu* createContextMenu(); | ||
|
|
||
| protected: | ||
| QgsLayerTreeView* mView; | ||
| QgsMapCanvas* mCanvas; | ||
| }; | ||
|
|
||
|
|
||
| #endif // QGSAPPLAYERTREEVIEWMENUPROVIDER_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| /*************************************************************************** | ||
| qgslayertree.h | ||
| -------------------------------------- | ||
| Date : May 2014 | ||
| Copyright : (C) 2014 by Martin Dobias | ||
| Email : wonder dot sk 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 QGSLAYERTREE_H | ||
| #define QGSLAYERTREE_H | ||
|
|
||
| #include "qgslayertreenode.h" | ||
| #include "qgslayertreegroup.h" | ||
| #include "qgslayertreelayer.h" | ||
|
|
||
| /** | ||
| * Namespace with helper functions for layer tree operations. | ||
| * | ||
| * Only generally useful routines should be here. Miscellaneous utility functions for work | ||
| * with the layer tree are in QgsLayerTreeUtils class. | ||
| * | ||
| * @note added in 2.4 | ||
| */ | ||
| namespace QgsLayerTree | ||
| { | ||
| //! Check whether the node is a valid group node | ||
| inline bool isGroup( QgsLayerTreeNode* node ) | ||
| { | ||
| return node && node->nodeType() == QgsLayerTreeNode::NodeGroup; | ||
| } | ||
|
|
||
| //! Check whether the node is a valid layer node | ||
| inline bool isLayer( QgsLayerTreeNode* node ) | ||
| { | ||
| return node && node->nodeType() == QgsLayerTreeNode::NodeLayer; | ||
| } | ||
|
|
||
| //! Cast node to a group. No type checking is done - use isGroup() to find out whether this operation is legal. | ||
| inline QgsLayerTreeGroup* toGroup( QgsLayerTreeNode* node ) | ||
| { | ||
| return static_cast<QgsLayerTreeGroup*>( node ); | ||
| } | ||
|
|
||
| //! Cast node to a layer. No type checking is done - use isLayer() to find out whether this operation is legal. | ||
| inline QgsLayerTreeLayer* toLayer( QgsLayerTreeNode* node ) | ||
| { | ||
| return static_cast<QgsLayerTreeLayer*>( node ); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| #endif // QGSLAYERTREE_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,324 @@ | ||
| /*************************************************************************** | ||
| qgslayertreegroup.cpp | ||
| -------------------------------------- | ||
| Date : May 2014 | ||
| Copyright : (C) 2014 by Martin Dobias | ||
| Email : wonder dot sk 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 "qgslayertreegroup.h" | ||
|
|
||
| #include "qgslayertree.h" | ||
| #include "qgslayertreeutils.h" | ||
|
|
||
| #include <QDomElement> | ||
| #include <QStringList> | ||
|
|
||
|
|
||
| QgsLayerTreeGroup::QgsLayerTreeGroup( const QString& name, Qt::CheckState checked ) | ||
| : QgsLayerTreeNode( NodeGroup ) | ||
| , mName( name ) | ||
| , mChecked( checked ) | ||
| , mChangingChildVisibility( false ) | ||
| { | ||
| connect( this, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) ); | ||
| } | ||
|
|
||
| QgsLayerTreeGroup::QgsLayerTreeGroup( const QgsLayerTreeGroup& other ) | ||
| : QgsLayerTreeNode( other ) | ||
| , mName( other.mName ) | ||
| , mChecked( other.mChecked ) | ||
| , mChangingChildVisibility( false ) | ||
| { | ||
| connect( this, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) ); | ||
| } | ||
|
|
||
|
|
||
| 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::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 ); | ||
|
|
||
| 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( this, 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 ); | ||
| } | ||
|
|
||
| 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::nodeVisibilityChanged( QgsLayerTreeNode* node ) | ||
| { | ||
| if ( mChildren.indexOf( node ) != -1 ) | ||
| updateVisibilityFromChildren(); | ||
| } | ||
|
|
||
| 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() == Qt::Checked; | ||
| 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 ); | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| /*************************************************************************** | ||
| qgslayertreegroup.h | ||
| -------------------------------------- | ||
| Date : May 2014 | ||
| Copyright : (C) 2014 by Martin Dobias | ||
| Email : wonder dot sk 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 QGSLAYERTREEGROUP_H | ||
| #define QGSLAYERTREEGROUP_H | ||
|
|
||
| #include "qgslayertreenode.h" | ||
|
|
||
| class QgsMapLayer; | ||
| class QgsLayerTreeLayer; | ||
|
|
||
| /** | ||
| * Layer tree group node serves as a container for layers and further groups. | ||
| * | ||
| * @note added in 2.4 | ||
| */ | ||
| 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 nodeVisibilityChanged( QgsLayerTreeNode* node ); | ||
|
|
||
| protected: | ||
| void updateVisibilityFromChildren(); | ||
|
|
||
| protected: | ||
| QString mName; | ||
| Qt::CheckState mChecked; | ||
|
|
||
| bool mChangingChildVisibility; | ||
| }; | ||
|
|
||
|
|
||
| #endif // QGSLAYERTREEGROUP_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| /*************************************************************************** | ||
| qgslayertreelayer.cpp | ||
| -------------------------------------- | ||
| Date : May 2014 | ||
| Copyright : (C) 2014 by Martin Dobias | ||
| Email : wonder dot sk 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 "qgslayertreelayer.h" | ||
|
|
||
| #include "qgslayertreeutils.h" | ||
| #include "qgsmaplayer.h" | ||
| #include "qgsmaplayerregistry.h" | ||
|
|
||
|
|
||
| QgsLayerTreeLayer::QgsLayerTreeLayer( QgsMapLayer *layer ) | ||
| : QgsLayerTreeNode( NodeLayer ) | ||
| , mLayerId( layer->id() ) | ||
| , mLayer( layer ) | ||
| , mVisible( Qt::Checked ) | ||
| { | ||
| Q_ASSERT( QgsMapLayerRegistry::instance()->mapLayer( mLayerId ) == layer ); | ||
| } | ||
|
|
||
| QgsLayerTreeLayer::QgsLayerTreeLayer( QString layerId, QString name ) | ||
| : QgsLayerTreeNode( NodeLayer ) | ||
| , mLayerId( layerId ) | ||
| , mLayerName( name ) | ||
| , mLayer( 0 ) | ||
| , mVisible( Qt::Checked ) | ||
| { | ||
| 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*> ) ) ); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| QString QgsLayerTreeLayer::layerName() const | ||
| { | ||
| return mLayer ? mLayer->name() : mLayerName; | ||
| } | ||
|
|
||
| void QgsLayerTreeLayer::setLayerName( const QString& n ) | ||
| { | ||
| if ( mLayer ) | ||
| mLayer->setLayerName( n ); | ||
| else | ||
| mLayerName = n; | ||
| } | ||
|
|
||
| void QgsLayerTreeLayer::setVisible( Qt::CheckState state ) | ||
| { | ||
| if ( mVisible == state ) | ||
| return; | ||
|
|
||
| mVisible = state; | ||
| emit visibilityChanged( this, state ); | ||
| } | ||
|
|
||
| QgsLayerTreeLayer* QgsLayerTreeLayer::readXML( QDomElement& element ) | ||
| { | ||
| if ( element.tagName() != "layer-tree-layer" ) | ||
| return 0; | ||
|
|
||
| QString layerID = element.attribute( "id" ); | ||
| QString layerName = element.attribute( "name" ); | ||
| Qt::CheckState checked = QgsLayerTreeUtils::checkStateFromXml( element.attribute( "checked" ) ); | ||
| bool isExpanded = ( element.attribute( "expanded", "1" ) == "1" ); | ||
|
|
||
| QgsLayerTreeLayer* nodeLayer = 0; | ||
|
|
||
| QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerID ); | ||
|
|
||
| if ( layer ) | ||
| nodeLayer = new QgsLayerTreeLayer( layer ); | ||
| else | ||
| nodeLayer = new QgsLayerTreeLayer( layerID, layerName ); | ||
|
|
||
| nodeLayer->readCommonXML( element ); | ||
|
|
||
| nodeLayer->setVisible( checked ); | ||
| 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( "checked", QgsLayerTreeUtils::checkStateToXml( mVisible ) ); | ||
| 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; | ||
| } | ||
| } | ||
| } |