2014-05-21 15:28:23 +07:00
|
|
|
/***************************************************************************
|
|
|
|
qgslayertreemodel.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. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
2014-05-05 16:58:10 +02:00
|
|
|
#include "qgslayertreemodel.h"
|
|
|
|
|
2014-05-17 22:14:36 +07:00
|
|
|
#include "qgslayertree.h"
|
2014-05-05 16:58:10 +02:00
|
|
|
|
|
|
|
#include <QMimeData>
|
|
|
|
#include <QTextStream>
|
|
|
|
|
|
|
|
#include "qgsdataitem.h"
|
2014-05-15 14:52:18 +07:00
|
|
|
#include "qgspluginlayer.h"
|
|
|
|
#include "qgsrasterlayer.h"
|
2014-05-05 16:58:10 +02:00
|
|
|
#include "qgsrendererv2.h"
|
2014-05-15 14:52:18 +07:00
|
|
|
#include "qgssymbollayerv2utils.h"
|
2014-05-05 16:58:10 +02:00
|
|
|
#include "qgsvectorlayer.h"
|
|
|
|
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeModel::QgsLayerTreeModel( QgsLayerTreeGroup* rootNode, QObject *parent )
|
|
|
|
: QAbstractItemModel( parent )
|
|
|
|
, mRootNode( rootNode )
|
|
|
|
, mFlags( ShowSymbology )
|
2014-06-17 14:56:13 +07:00
|
|
|
, mAutoCollapseSymNodesCount( -1 )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
Q_ASSERT( mRootNode );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
connect( mRootNode, SIGNAL( willAddChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeWillAddChildren( QgsLayerTreeNode*, int, int ) ) );
|
|
|
|
connect( mRootNode, SIGNAL( addedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeAddedChildren( QgsLayerTreeNode*, int, int ) ) );
|
|
|
|
connect( mRootNode, SIGNAL( willRemoveChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeWillRemoveChildren( QgsLayerTreeNode*, int, int ) ) );
|
|
|
|
connect( mRootNode, SIGNAL( removedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeRemovedChildren() ) );
|
|
|
|
connect( mRootNode, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode* ) ) );
|
2014-06-13 18:04:08 +07:00
|
|
|
|
|
|
|
mFontLayer.setBold( true );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QgsLayerTreeModel::~QgsLayerTreeModel()
|
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
foreach ( QList<QgsLayerTreeModelSymbologyNode*> nodeL, mSymbologyNodes )
|
|
|
|
qDeleteAll( nodeL );
|
2014-05-05 16:58:10 +02:00
|
|
|
mSymbologyNodes.clear();
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeNode* QgsLayerTreeModel::index2node( const QModelIndex& index ) const
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !index.isValid() )
|
2014-05-05 16:58:10 +02:00
|
|
|
return mRootNode;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QObject* obj = reinterpret_cast<QObject*>( index.internalPointer() );
|
|
|
|
return qobject_cast<QgsLayerTreeNode*>( obj );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeModelSymbologyNode* QgsLayerTreeModel::index2symnode( const QModelIndex& index )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
return qobject_cast<QgsLayerTreeModelSymbologyNode*>( reinterpret_cast<QObject*>( index.internalPointer() ) );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
int QgsLayerTreeModel::rowCount( const QModelIndex &parent ) const
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( index2symnode( parent ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
|
|
|
return 0; // they are leaves
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeNode* n = index2node( parent );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( parent.isValid() && parent.column() != 0 )
|
2014-05-05 16:58:10 +02:00
|
|
|
return 0;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( QgsLayerTree::isLayer( n ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeLayer* nL = QgsLayerTree::toLayer( n );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
|
|
|
return mSymbologyNodes[nL].count();
|
|
|
|
}
|
|
|
|
|
|
|
|
return n->children().count();
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
int QgsLayerTreeModel::columnCount( const QModelIndex &parent ) const
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
Q_UNUSED( parent );
|
2014-05-05 16:58:10 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QModelIndex QgsLayerTreeModel::index( int row, int column, const QModelIndex &parent ) const
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( column != 0 || row < 0 || row >= rowCount( parent ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
return QModelIndex();
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeNode* n = index2node( parent );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !n )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeModelSymbologyNode* sym = index2symnode( parent );
|
|
|
|
Q_ASSERT( sym );
|
2014-05-05 16:58:10 +02:00
|
|
|
return QModelIndex(); // have no children
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !n || column != 0 || row >= rowCount( parent ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
return QModelIndex();
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( testFlag( ShowSymbology ) && QgsLayerTree::isLayer( n ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeLayer* nL = QgsLayerTree::toLayer( n );
|
|
|
|
Q_ASSERT( mSymbologyNodes.contains( nL ) );
|
|
|
|
return createIndex( row, column, static_cast<QObject*>( mSymbologyNodes[nL].at( row ) ) );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
return createIndex( row, column, static_cast<QObject*>( n->children().at( row ) ) );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QModelIndex QgsLayerTreeModel::parent( const QModelIndex &child ) const
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !child.isValid() )
|
2014-05-05 16:58:10 +02:00
|
|
|
return QModelIndex();
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeNode* n = index2node( child );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
|
|
|
QgsLayerTreeNode* parentNode = 0;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !n )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeModelSymbologyNode* sym = index2symnode( child );
|
|
|
|
Q_ASSERT( sym );
|
2014-05-05 16:58:10 +02:00
|
|
|
parentNode = sym->parent();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
parentNode = n->parent(); // must not be null
|
2014-05-21 15:28:23 +07:00
|
|
|
Q_ASSERT( parentNode );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
|
|
|
QgsLayerTreeNode* grandParentNode = parentNode->parent();
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !grandParentNode )
|
2014-05-05 16:58:10 +02:00
|
|
|
return QModelIndex(); // root node -> invalid index
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
int row = grandParentNode->children().indexOf( parentNode );
|
|
|
|
Q_ASSERT( row >= 0 );
|
|
|
|
return createIndex( row, 0, static_cast<QObject*>( parentNode ) );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QVariant QgsLayerTreeModel::data( const QModelIndex &index, int role ) const
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !index.isValid() )
|
2014-05-05 16:58:10 +02:00
|
|
|
return QVariant();
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( QgsLayerTreeModelSymbologyNode* sym = index2symnode( index ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( role == Qt::DisplayRole )
|
2014-05-05 16:58:10 +02:00
|
|
|
return sym->name();
|
2014-05-21 15:28:23 +07:00
|
|
|
else if ( role == Qt::DecorationRole )
|
2014-05-05 16:58:10 +02:00
|
|
|
return sym->icon();
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeNode* node = index2node( index );
|
|
|
|
if ( role == Qt::DisplayRole || role == Qt::EditRole )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( QgsLayerTree::isGroup( node ) )
|
|
|
|
return QgsLayerTree::toGroup( node )->name();
|
|
|
|
else if ( QgsLayerTree::isLayer( node ) )
|
2014-05-15 14:52:18 +07:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
|
2014-05-15 14:52:18 +07:00
|
|
|
QString name = nodeLayer->layerName();
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( nodeLayer->customProperty( "showFeatureCount", 0 ).toInt() && role == Qt::DisplayRole )
|
2014-05-15 14:52:18 +07:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( nodeLayer->layer() );
|
|
|
|
if ( vlayer && vlayer->pendingFeatureCount() >= 0 )
|
2014-05-15 14:52:18 +07:00
|
|
|
name += QString( " [%1]" ).arg( vlayer->pendingFeatureCount() );
|
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
else if ( role == Qt::DecorationRole && index.column() == 0 )
|
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( QgsLayerTree::isGroup( node ) )
|
2014-05-23 18:50:31 +07:00
|
|
|
return iconGroup();
|
2014-05-21 15:28:23 +07:00
|
|
|
else if ( QgsLayerTree::isLayer( node ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsMapLayer* layer = QgsLayerTree::toLayer( node )->layer();
|
|
|
|
if ( !layer )
|
2014-05-05 16:58:10 +02:00
|
|
|
return QVariant();
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( layer->type() == QgsMapLayer::RasterLayer )
|
2014-06-09 10:59:43 +07:00
|
|
|
{
|
|
|
|
if ( testFlag( ShowRasterPreviewIcon ) )
|
|
|
|
{
|
|
|
|
QgsRasterLayer* rlayer = qobject_cast<QgsRasterLayer *>( layer );
|
|
|
|
return QIcon( rlayer->previewAsPixmap( QSize( 32, 32 ) ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return QgsLayerItem::iconRaster();
|
|
|
|
}
|
2014-05-21 15:28:23 +07:00
|
|
|
else if ( layer->type() == QgsMapLayer::VectorLayer )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsVectorLayer* vlayer = static_cast<QgsVectorLayer*>( layer );
|
2014-05-22 17:55:30 +07:00
|
|
|
if ( vlayer->isEditable() )
|
|
|
|
{
|
|
|
|
if ( vlayer->isModified() )
|
|
|
|
return QIcon( QgsApplication::getThemePixmap( "/mIconEditableEdits.png" ) );
|
|
|
|
else
|
|
|
|
return QIcon( QgsApplication::getThemePixmap( "/mIconEditable.png" ) );
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( vlayer->geometryType() == QGis::Point )
|
2014-05-05 16:58:10 +02:00
|
|
|
return QgsLayerItem::iconPoint();
|
2014-05-21 15:28:23 +07:00
|
|
|
else if ( vlayer->geometryType() == QGis::Line )
|
2014-05-05 16:58:10 +02:00
|
|
|
return QgsLayerItem::iconLine();
|
2014-05-21 15:28:23 +07:00
|
|
|
else if ( vlayer->geometryType() == QGis::Polygon )
|
2014-05-05 16:58:10 +02:00
|
|
|
return QgsLayerItem::iconPolygon();
|
2014-05-21 15:28:23 +07:00
|
|
|
else if ( vlayer->geometryType() == QGis::NoGeometry )
|
2014-05-05 16:58:10 +02:00
|
|
|
return QgsLayerItem::iconTable();
|
|
|
|
}
|
|
|
|
return QgsLayerItem::iconDefault();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( role == Qt::CheckStateRole )
|
|
|
|
{
|
2014-05-23 00:14:39 +07:00
|
|
|
if ( !testFlag( AllowNodeChangeVisibility ) )
|
2014-05-10 22:18:47 +07:00
|
|
|
return QVariant();
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( QgsLayerTree::isLayer( node ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
|
2014-05-23 00:24:23 +07:00
|
|
|
if ( nodeLayer->layer() && nodeLayer->layer()->type() == QgsMapLayer::VectorLayer )
|
|
|
|
{
|
|
|
|
if ( qobject_cast<QgsVectorLayer*>( nodeLayer->layer() )->geometryType() == QGis::NoGeometry )
|
|
|
|
return QVariant(); // do not show checkbox for non-spatial tables
|
|
|
|
}
|
2014-05-17 22:54:03 +07:00
|
|
|
return nodeLayer->isVisible();
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
2014-05-21 15:28:23 +07:00
|
|
|
else if ( QgsLayerTree::isGroup( node ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeGroup* nodeGroup = QgsLayerTree::toGroup( node );
|
2014-05-05 16:58:10 +02:00
|
|
|
return nodeGroup->isVisible();
|
|
|
|
}
|
|
|
|
}
|
2014-05-11 17:42:27 +07:00
|
|
|
else if ( role == Qt::FontRole )
|
|
|
|
{
|
2014-06-13 18:04:08 +07:00
|
|
|
QFont f( QgsLayerTree::isLayer( node ) ? mFontLayer : ( QgsLayerTree::isGroup( node ) ? mFontGroup : QFont() ) );
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( node->customProperty( "embedded" ).toInt() )
|
|
|
|
f.setItalic( true );
|
2014-05-25 23:17:42 +07:00
|
|
|
if ( index == mCurrentIndex )
|
2014-05-22 18:52:31 +07:00
|
|
|
f.setUnderline( true );
|
2014-05-11 17:42:27 +07:00
|
|
|
return f;
|
|
|
|
}
|
2014-05-22 18:20:47 +07:00
|
|
|
else if ( role == Qt::ToolTipRole )
|
|
|
|
{
|
|
|
|
if ( QgsLayerTree::isLayer( node ) )
|
|
|
|
{
|
|
|
|
if ( QgsMapLayer* layer = QgsLayerTree::toLayer( node )->layer() )
|
|
|
|
return layer->publicSource();
|
|
|
|
}
|
|
|
|
}
|
2014-05-05 16:58:10 +02:00
|
|
|
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
Qt::ItemFlags QgsLayerTreeModel::flags( const QModelIndex& index ) const
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !index.isValid() )
|
2014-05-23 00:14:39 +07:00
|
|
|
{
|
|
|
|
Qt::ItemFlags rootFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
|
|
|
if ( testFlag( AllowNodeReorder ) )
|
|
|
|
rootFlags |= Qt::ItemIsDropEnabled;
|
|
|
|
return rootFlags;
|
|
|
|
}
|
2014-05-05 16:58:10 +02:00
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( index2symnode( index ) )
|
2014-05-23 00:14:39 +07:00
|
|
|
return Qt::ItemIsEnabled; // | Qt::ItemIsSelectable;
|
2014-05-05 16:58:10 +02:00
|
|
|
|
2014-05-23 00:14:39 +07:00
|
|
|
Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
2014-05-27 11:07:11 +07:00
|
|
|
|
2014-05-23 00:14:39 +07:00
|
|
|
if ( testFlag( AllowNodeRename ) )
|
|
|
|
f |= Qt::ItemIsEditable;
|
2014-05-27 11:07:11 +07:00
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeNode* node = index2node( index );
|
2014-05-27 11:07:11 +07:00
|
|
|
bool isEmbedded = node->customProperty( "embedded" ).toInt();
|
|
|
|
|
|
|
|
if ( testFlag( AllowNodeReorder ) )
|
|
|
|
{
|
|
|
|
// only root embedded nodes can be reordered
|
|
|
|
if ( !isEmbedded || ( isEmbedded && node->parent() && !node->parent()->customProperty( "embedded" ).toInt() ) )
|
|
|
|
f |= Qt::ItemIsDragEnabled;
|
|
|
|
}
|
|
|
|
|
2014-05-23 00:14:39 +07:00
|
|
|
if ( testFlag( AllowNodeChangeVisibility ) && ( QgsLayerTree::isLayer( node ) || QgsLayerTree::isGroup( node ) ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
f |= Qt::ItemIsUserCheckable;
|
2014-05-27 11:07:11 +07:00
|
|
|
|
|
|
|
if ( testFlag( AllowNodeReorder ) && QgsLayerTree::isGroup( node ) && !isEmbedded )
|
2014-05-23 00:14:39 +07:00
|
|
|
f |= Qt::ItemIsDropEnabled;
|
2014-05-27 11:07:11 +07:00
|
|
|
|
2014-05-05 16:58:10 +02:00
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
bool QgsLayerTreeModel::setData( const QModelIndex& index, const QVariant& value, int role )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeNode* node = index2node( index );
|
|
|
|
if ( !node )
|
|
|
|
return QgsLayerTreeModel::setData( index, value, role );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( role == Qt::CheckStateRole )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-23 00:14:39 +07:00
|
|
|
if ( !testFlag( AllowNodeChangeVisibility ) )
|
2014-05-10 22:18:47 +07:00
|
|
|
return false;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( QgsLayerTree::isLayer( node ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeLayer* layer = QgsLayerTree::toLayer( node );
|
|
|
|
layer->setVisible(( Qt::CheckState )value.toInt() );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
2014-05-21 15:28:23 +07:00
|
|
|
else if ( QgsLayerTree::isGroup( node ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeGroup* group = QgsLayerTree::toGroup( node );
|
|
|
|
group->setVisible(( Qt::CheckState )value.toInt() );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2014-05-21 15:28:23 +07:00
|
|
|
else if ( role == Qt::EditRole )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-23 00:14:39 +07:00
|
|
|
if ( !testFlag( AllowNodeRename ) )
|
|
|
|
return false;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( QgsLayerTree::isLayer( node ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeLayer* layer = QgsLayerTree::toLayer( node );
|
|
|
|
layer->setLayerName( value.toString() );
|
|
|
|
emit dataChanged( index, index );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
2014-05-21 15:28:23 +07:00
|
|
|
else if ( QgsLayerTree::isGroup( node ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTree::toGroup( node )->setName( value.toString() );
|
|
|
|
emit dataChanged( index, index );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
return QAbstractItemModel::setData( index, value, role );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QModelIndex QgsLayerTreeModel::node2index( QgsLayerTreeNode* node ) const
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !node->parent() )
|
2014-05-05 16:58:10 +02:00
|
|
|
return QModelIndex(); // this is the only root item -> invalid index
|
2014-05-21 15:28:23 +07:00
|
|
|
QModelIndex parentIndex = node2index( node->parent() );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
int row = node->parent()->children().indexOf( node );
|
|
|
|
Q_ASSERT( row >= 0 );
|
|
|
|
return index( row, 0, parentIndex );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
static bool _isChildOfNode( QgsLayerTreeNode* child, QgsLayerTreeNode* node )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !child->parent() )
|
2014-05-05 16:58:10 +02:00
|
|
|
return false;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( child->parent() == node )
|
2014-05-05 16:58:10 +02:00
|
|
|
return true;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
return _isChildOfNode( child->parent(), node );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
static bool _isChildOfNodes( QgsLayerTreeNode* child, QList<QgsLayerTreeNode*> nodes )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
foreach ( QgsLayerTreeNode* n, nodes )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( _isChildOfNode( child, n ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QList<QgsLayerTreeNode*> QgsLayerTreeModel::indexes2nodes( const QModelIndexList& list, bool skipInternal ) const
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
|
|
|
QList<QgsLayerTreeNode*> nodes;
|
2014-05-21 15:28:23 +07:00
|
|
|
foreach ( QModelIndex index, list )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeNode* node = index2node( index );
|
|
|
|
if ( !node )
|
2014-05-05 16:58:10 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
nodes << node;
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !skipInternal )
|
2014-05-05 16:58:10 +02:00
|
|
|
return nodes;
|
|
|
|
|
|
|
|
// remove any children of nodes if both parent node and children are selected
|
|
|
|
QList<QgsLayerTreeNode*> nodesFinal;
|
2014-05-21 15:28:23 +07:00
|
|
|
foreach ( QgsLayerTreeNode* node, nodes )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !_isChildOfNodes( node, nodes ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
nodesFinal << node;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodesFinal;
|
|
|
|
}
|
|
|
|
|
2014-05-27 20:49:47 +07:00
|
|
|
bool QgsLayerTreeModel::isIndexSymbologyNode( const QModelIndex& index ) const
|
|
|
|
{
|
|
|
|
return index2symnode( index ) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
QgsLayerTreeLayer* QgsLayerTreeModel::layerNodeForSymbologyNode( const QModelIndex& index ) const
|
|
|
|
{
|
|
|
|
QgsLayerTreeModelSymbologyNode* symNode = index2symnode( index );
|
|
|
|
return symNode ? symNode->parent() : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
QgsLayerTreeGroup*QgsLayerTreeModel::rootGroup()
|
|
|
|
{
|
|
|
|
return mRootNode;
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
void QgsLayerTreeModel::refreshLayerSymbology( QgsLayerTreeLayer* nodeLayer )
|
2014-05-15 14:52:18 +07:00
|
|
|
{
|
|
|
|
// update title
|
2014-05-21 15:28:23 +07:00
|
|
|
QModelIndex idx = node2index( nodeLayer );
|
|
|
|
emit dataChanged( idx, idx );
|
2014-05-15 14:52:18 +07:00
|
|
|
|
|
|
|
// update children
|
2014-06-17 14:56:13 +07:00
|
|
|
int oldNodeCount = rowCount( idx );
|
|
|
|
beginRemoveRows( idx, 0, oldNodeCount - 1 );
|
2014-05-21 15:28:23 +07:00
|
|
|
removeSymbologyFromLayer( nodeLayer );
|
2014-05-15 14:52:18 +07:00
|
|
|
endRemoveRows();
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
addSymbologyToLayer( nodeLayer );
|
2014-06-17 14:56:13 +07:00
|
|
|
int newNodeCount = rowCount( idx );
|
|
|
|
|
|
|
|
// automatic collapse of symbology nodes - useful if a layer has many symbology nodes
|
|
|
|
if ( mAutoCollapseSymNodesCount != -1 && oldNodeCount != newNodeCount && newNodeCount >= mAutoCollapseSymNodesCount )
|
|
|
|
nodeLayer->setExpanded( false );
|
2014-05-15 14:52:18 +07:00
|
|
|
}
|
|
|
|
|
2014-05-27 20:49:47 +07:00
|
|
|
QModelIndex QgsLayerTreeModel::currentIndex() const
|
|
|
|
{
|
|
|
|
return mCurrentIndex;
|
|
|
|
}
|
|
|
|
|
2014-05-25 23:17:42 +07:00
|
|
|
void QgsLayerTreeModel::setCurrentIndex( const QModelIndex& currentIndex )
|
2014-05-22 18:52:31 +07:00
|
|
|
{
|
2014-05-25 23:17:42 +07:00
|
|
|
QModelIndex oldIndex = mCurrentIndex;
|
|
|
|
mCurrentIndex = currentIndex;
|
2014-05-22 18:52:31 +07:00
|
|
|
|
2014-05-25 23:17:42 +07:00
|
|
|
if ( oldIndex.isValid() )
|
|
|
|
emit dataChanged( oldIndex, oldIndex );
|
|
|
|
if ( currentIndex.isValid() )
|
|
|
|
emit dataChanged( currentIndex, currentIndex );
|
2014-05-22 18:52:31 +07:00
|
|
|
}
|
|
|
|
|
2014-06-13 18:04:08 +07:00
|
|
|
|
|
|
|
void QgsLayerTreeModel::setLayerTreeNodeFont( int nodeType, const QFont& font )
|
|
|
|
{
|
|
|
|
if ( nodeType == QgsLayerTreeNode::NodeGroup )
|
|
|
|
{
|
|
|
|
if ( mFontGroup != font )
|
|
|
|
{
|
|
|
|
mFontGroup = font;
|
|
|
|
recursivelyEmitDataChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( nodeType == QgsLayerTreeNode::NodeLayer )
|
|
|
|
{
|
|
|
|
if ( mFontLayer != font )
|
|
|
|
{
|
|
|
|
mFontLayer = font;
|
|
|
|
recursivelyEmitDataChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2014-06-18 23:59:46 +02:00
|
|
|
{
|
2014-06-13 18:04:08 +07:00
|
|
|
QgsDebugMsg( "invalid node type" );
|
2014-06-18 23:59:46 +02:00
|
|
|
}
|
2014-06-13 18:04:08 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QFont QgsLayerTreeModel::layerTreeNodeFont( int nodeType ) const
|
|
|
|
{
|
|
|
|
if ( nodeType == QgsLayerTreeNode::NodeGroup )
|
|
|
|
return mFontGroup;
|
|
|
|
else if ( nodeType == QgsLayerTreeNode::NodeLayer )
|
|
|
|
return mFontLayer;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QgsDebugMsg( "invalid node type" );
|
|
|
|
return QFont();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
void QgsLayerTreeModel::nodeWillAddChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
Q_ASSERT( node );
|
|
|
|
beginInsertRows( node2index( node ), indexFrom, indexTo );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
2014-05-22 17:55:30 +07:00
|
|
|
static QList<QgsLayerTreeLayer*> _layerNodesInSubtree( QgsLayerTreeNode* node, int indexFrom, int indexTo )
|
|
|
|
{
|
|
|
|
QList<QgsLayerTreeNode*> children = node->children();
|
|
|
|
QList<QgsLayerTreeLayer*> newLayerNodes;
|
|
|
|
for ( int i = indexFrom; i <= indexTo; ++i )
|
|
|
|
{
|
|
|
|
QgsLayerTreeNode* child = children.at( i );
|
|
|
|
if ( QgsLayerTree::isLayer( child ) )
|
|
|
|
newLayerNodes << QgsLayerTree::toLayer( child );
|
|
|
|
else if ( QgsLayerTree::isGroup( child ) )
|
|
|
|
newLayerNodes << QgsLayerTree::toGroup( child )->findLayers();
|
|
|
|
}
|
|
|
|
return newLayerNodes;
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
void QgsLayerTreeModel::nodeAddedChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
Q_ASSERT( node );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
|
|
|
endInsertRows();
|
|
|
|
|
2014-05-22 17:55:30 +07:00
|
|
|
foreach ( QgsLayerTreeLayer* newLayerNode, _layerNodesInSubtree( node, indexFrom, indexTo ) )
|
|
|
|
connectToLayer( newLayerNode );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
void QgsLayerTreeModel::nodeWillRemoveChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
Q_ASSERT( node );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
beginRemoveRows( node2index( node ), indexFrom, indexTo );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
2014-05-22 17:55:30 +07:00
|
|
|
// disconnect from layers and remove their symbology
|
|
|
|
foreach ( QgsLayerTreeLayer* nodeLayer, _layerNodesInSubtree( node, indexFrom, indexTo ) )
|
|
|
|
disconnectFromLayer( nodeLayer );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QgsLayerTreeModel::nodeRemovedChildren()
|
|
|
|
{
|
|
|
|
endRemoveRows();
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
void QgsLayerTreeModel::nodeVisibilityChanged( QgsLayerTreeNode* node )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
Q_ASSERT( node );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QModelIndex index = node2index( node );
|
|
|
|
emit dataChanged( index, index );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
2014-05-15 14:52:18 +07:00
|
|
|
void QgsLayerTreeModel::nodeLayerLoaded()
|
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeLayer* nodeLayer = qobject_cast<QgsLayerTreeLayer*>( sender() );
|
|
|
|
if ( !nodeLayer )
|
2014-05-15 14:52:18 +07:00
|
|
|
return;
|
|
|
|
|
2014-05-22 17:55:30 +07:00
|
|
|
// deffered connection to the layer
|
|
|
|
connectToLayer( nodeLayer );
|
2014-05-15 14:52:18 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
void QgsLayerTreeModel::layerRendererChanged()
|
|
|
|
{
|
2014-06-05 11:24:32 +07:00
|
|
|
if ( !testFlag( ShowSymbology ) )
|
|
|
|
return;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsMapLayer* layer = qobject_cast<QgsMapLayer*>( sender() );
|
|
|
|
if ( !layer )
|
2014-05-15 14:52:18 +07:00
|
|
|
return;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeLayer* nodeLayer = mRootNode->findLayer( layer->id() );
|
|
|
|
if ( !nodeLayer )
|
2014-05-15 14:52:18 +07:00
|
|
|
return;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
refreshLayerSymbology( nodeLayer );
|
2014-05-15 14:52:18 +07:00
|
|
|
}
|
|
|
|
|
2014-05-22 17:55:30 +07:00
|
|
|
void QgsLayerTreeModel::layerNeedsUpdate()
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-22 17:55:30 +07:00
|
|
|
QgsMapLayer* layer = qobject_cast<QgsMapLayer*>( sender() );
|
|
|
|
if ( !layer )
|
|
|
|
return;
|
|
|
|
|
|
|
|
QgsLayerTreeLayer* nodeLayer = mRootNode->findLayer( layer->id() );
|
|
|
|
if ( !nodeLayer )
|
|
|
|
return;
|
2014-05-05 16:58:10 +02:00
|
|
|
|
2014-05-22 17:55:30 +07:00
|
|
|
QModelIndex index = node2index( nodeLayer );
|
|
|
|
emit dataChanged( index, index );
|
2014-06-13 16:40:00 +07:00
|
|
|
|
|
|
|
if ( nodeLayer->customProperty( "showFeatureCount" ).toInt() )
|
|
|
|
refreshLayerSymbology( nodeLayer );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
void QgsLayerTreeModel::removeSymbologyFromLayer( QgsLayerTreeLayer* nodeLayer )
|
2014-05-15 14:52:18 +07:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( mSymbologyNodes.contains( nodeLayer ) )
|
2014-05-15 14:52:18 +07:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
qDeleteAll( mSymbologyNodes[nodeLayer] );
|
|
|
|
mSymbologyNodes.remove( nodeLayer );
|
2014-05-15 14:52:18 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
void QgsLayerTreeModel::addSymbologyToLayer( QgsLayerTreeLayer* nodeL )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !nodeL->layer() )
|
2014-05-15 14:52:18 +07:00
|
|
|
return;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( nodeL->layer()->type() == QgsMapLayer::VectorLayer )
|
2014-05-15 14:52:18 +07:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
addSymbologyToVectorLayer( nodeL );
|
2014-05-15 14:52:18 +07:00
|
|
|
}
|
2014-05-21 15:28:23 +07:00
|
|
|
else if ( nodeL->layer()->type() == QgsMapLayer::RasterLayer )
|
2014-05-15 14:52:18 +07:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
addSymbologyToRasterLayer( nodeL );
|
2014-05-15 14:52:18 +07:00
|
|
|
}
|
2014-05-21 15:28:23 +07:00
|
|
|
else if ( nodeL->layer()->type() == QgsMapLayer::PluginLayer )
|
2014-05-15 14:52:18 +07:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
addSymbologyToPluginLayer( nodeL );
|
2014-05-15 14:52:18 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
void QgsLayerTreeModel::addSymbologyToVectorLayer( QgsLayerTreeLayer* nodeL )
|
2014-05-15 14:52:18 +07:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsVectorLayer* vlayer = static_cast<QgsVectorLayer*>( nodeL->layer() );
|
2014-05-15 14:52:18 +07:00
|
|
|
QgsFeatureRendererV2* r = vlayer->rendererV2();
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !r )
|
2014-05-15 14:52:18 +07:00
|
|
|
return;
|
2014-05-05 16:58:10 +02:00
|
|
|
|
|
|
|
QList<QgsLayerTreeModelSymbologyNode*>& lst = mSymbologyNodes[nodeL];
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
bool showFeatureCount = nodeL->customProperty( "showFeatureCount", 0 ).toBool();
|
|
|
|
if ( showFeatureCount )
|
2014-05-15 14:52:18 +07:00
|
|
|
{
|
|
|
|
vlayer->countSymbolFeatures();
|
|
|
|
}
|
|
|
|
QSize iconSize( 16, 16 );
|
|
|
|
QgsLegendSymbolList items = r->legendSymbolItems();
|
|
|
|
|
2014-06-18 20:26:38 +07:00
|
|
|
if ( items.count() == 0 )
|
|
|
|
return;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
beginInsertRows( node2index( nodeL ), 0, items.count() - 1 );
|
2014-05-15 14:52:18 +07:00
|
|
|
|
|
|
|
typedef QPair<QString, QgsSymbolV2*> XY;
|
|
|
|
foreach ( XY item, items )
|
|
|
|
{
|
|
|
|
QString label = item.first;
|
2014-05-22 19:52:30 +07:00
|
|
|
QIcon icon;
|
|
|
|
if ( item.second )
|
|
|
|
icon = QgsSymbolLayerV2Utils::symbolPreviewPixmap( item.second, iconSize );
|
|
|
|
if ( showFeatureCount && item.second )
|
2014-05-21 15:28:23 +07:00
|
|
|
label += QString( " [%1]" ).arg( vlayer->featureCount( item.second ) );
|
2014-05-22 19:52:30 +07:00
|
|
|
lst << new QgsLayerTreeModelSymbologyNode( nodeL, label, icon );
|
2014-05-15 14:52:18 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
endInsertRows();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
void QgsLayerTreeModel::addSymbologyToRasterLayer( QgsLayerTreeLayer* nodeL )
|
2014-05-15 14:52:18 +07:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsRasterLayer* rlayer = static_cast<QgsRasterLayer*>( nodeL->layer() );
|
2014-05-15 14:52:18 +07:00
|
|
|
|
|
|
|
QgsLegendColorList rasterItemList = rlayer->legendSymbologyItems();
|
|
|
|
|
|
|
|
QList<QgsLayerTreeModelSymbologyNode*>& lst = mSymbologyNodes[nodeL];
|
|
|
|
|
2014-05-21 19:30:29 +07:00
|
|
|
// temporary solution for WMS. Ideally should be done with a delegate.
|
|
|
|
if ( rlayer->providerType() == "wms" )
|
|
|
|
{
|
|
|
|
QImage img = rlayer->dataProvider()->getLegendGraphic( 1000 ); // dummy scale - should not be required!
|
|
|
|
if ( !img.isNull() )
|
|
|
|
lst << new QgsLayerTreeModelSymbologyNode( nodeL, tr( "Double-click to view legend" ) );
|
|
|
|
}
|
2014-05-15 14:52:18 +07:00
|
|
|
|
2014-06-18 20:26:38 +07:00
|
|
|
if ( rasterItemList.count() == 0 )
|
|
|
|
return;
|
|
|
|
|
2014-05-15 14:52:18 +07:00
|
|
|
// Paletted raster may have many colors, for example UInt16 may have 65536 colors
|
|
|
|
// and it is very slow, so we limit max count
|
2014-05-21 15:28:23 +07:00
|
|
|
QSize iconSize( 16, 16 );
|
2014-05-15 14:52:18 +07:00
|
|
|
int count = 0;
|
|
|
|
int max_count = 1000;
|
2014-05-21 15:28:23 +07:00
|
|
|
int total_count = qMin( max_count + 1, rasterItemList.count() );
|
2014-05-15 14:52:18 +07:00
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
beginInsertRows( node2index( nodeL ), 0, total_count - 1 );
|
2014-05-15 14:52:18 +07:00
|
|
|
|
|
|
|
for ( QgsLegendColorList::const_iterator itemIt = rasterItemList.constBegin();
|
|
|
|
itemIt != rasterItemList.constEnd(); ++itemIt, ++count )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-15 14:52:18 +07:00
|
|
|
QPixmap pix( iconSize );
|
|
|
|
pix.fill( itemIt->second );
|
2014-05-21 15:28:23 +07:00
|
|
|
lst << new QgsLayerTreeModelSymbologyNode( nodeL, itemIt->first, QIcon( pix ) );
|
2014-05-15 14:52:18 +07:00
|
|
|
|
|
|
|
if ( count == max_count )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-15 14:52:18 +07:00
|
|
|
pix.fill( Qt::transparent );
|
|
|
|
QString label = tr( "following %1 items\nnot displayed" ).arg( rasterItemList.size() - max_count );
|
2014-05-21 15:28:23 +07:00
|
|
|
lst << new QgsLayerTreeModelSymbologyNode( nodeL, label, QIcon( pix ) );
|
2014-05-15 14:52:18 +07:00
|
|
|
break;
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
}
|
2014-05-15 14:52:18 +07:00
|
|
|
|
|
|
|
endInsertRows();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
void QgsLayerTreeModel::addSymbologyToPluginLayer( QgsLayerTreeLayer* nodeL )
|
2014-05-15 14:52:18 +07:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsPluginLayer* player = static_cast<QgsPluginLayer*>( nodeL->layer() );
|
2014-05-15 14:52:18 +07:00
|
|
|
|
|
|
|
QList<QgsLayerTreeModelSymbologyNode*>& lst = mSymbologyNodes[nodeL];
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QSize iconSize( 16, 16 );
|
|
|
|
QgsLegendSymbologyList symbologyList = player->legendSymbologyItems( iconSize );
|
2014-05-15 14:52:18 +07:00
|
|
|
|
2014-06-18 20:26:38 +07:00
|
|
|
if ( symbologyList.count() == 0 )
|
|
|
|
return;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
beginInsertRows( node2index( nodeL ), 0, symbologyList.count() - 1 );
|
2014-05-15 14:52:18 +07:00
|
|
|
|
|
|
|
typedef QPair<QString, QPixmap> XY;
|
2014-05-21 15:28:23 +07:00
|
|
|
foreach ( XY item, symbologyList )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
lst << new QgsLayerTreeModelSymbologyNode( nodeL, item.first, QIcon( item.second ) );
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
2014-05-15 14:52:18 +07:00
|
|
|
|
|
|
|
endInsertRows();
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-22 17:55:30 +07:00
|
|
|
void QgsLayerTreeModel::connectToLayer( QgsLayerTreeLayer* nodeLayer )
|
|
|
|
{
|
|
|
|
if ( !nodeLayer->layer() )
|
|
|
|
{
|
|
|
|
// in order to connect to layer, we need to have it loaded.
|
|
|
|
// keep an eye on the layer ID: once loaded, we will use it
|
|
|
|
connect( nodeLayer, SIGNAL( layerLoaded() ), this, SLOT( nodeLayerLoaded() ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( testFlag( ShowSymbology ) )
|
|
|
|
{
|
|
|
|
addSymbologyToLayer( nodeLayer );
|
2014-06-17 14:56:13 +07:00
|
|
|
|
|
|
|
// automatic collapse of symbology nodes - useful if a layer has many symbology nodes
|
|
|
|
if ( !mRootNode->customProperty( "loading" ).toBool() )
|
|
|
|
{
|
|
|
|
if ( mAutoCollapseSymNodesCount != -1 && rowCount( node2index( nodeLayer ) ) >= mAutoCollapseSymNodesCount )
|
|
|
|
nodeLayer->setExpanded( false );
|
|
|
|
}
|
2014-05-22 17:55:30 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
QgsMapLayer* layer = nodeLayer->layer();
|
2014-06-05 11:24:32 +07:00
|
|
|
connect( layer, SIGNAL( rendererChanged() ), this, SLOT( layerRendererChanged() ), Qt::UniqueConnection );
|
|
|
|
|
2014-05-22 17:55:30 +07:00
|
|
|
if ( layer->type() == QgsMapLayer::VectorLayer )
|
|
|
|
{
|
|
|
|
// using unique connection because there may be temporarily more nodes for a layer than just one
|
|
|
|
// which would create multiple connections, however disconnect() would disconnect all multiple connections
|
|
|
|
// even if we wanted to disconnect just one connection in each call.
|
|
|
|
connect( layer, SIGNAL( editingStarted() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
|
|
|
|
connect( layer, SIGNAL( editingStopped() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
|
|
|
|
connect( layer, SIGNAL( layerModified() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
|
2014-06-13 18:49:54 +07:00
|
|
|
connect( layer, SIGNAL( layerNameChanged() ), this, SLOT( layerNeedsUpdate() ), Qt::UniqueConnection );
|
2014-05-22 17:55:30 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// try to find out if the layer ID is present in the tree multiple times
|
|
|
|
static int _numLayerCount( QgsLayerTreeGroup* group, const QString& layerId )
|
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
foreach ( QgsLayerTreeNode* child, group->children() )
|
|
|
|
{
|
|
|
|
if ( QgsLayerTree::isLayer( child ) )
|
|
|
|
{
|
|
|
|
if ( QgsLayerTree::toLayer( child )->layerId() == layerId )
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
else if ( QgsLayerTree::isGroup( child ) )
|
|
|
|
{
|
|
|
|
count += _numLayerCount( QgsLayerTree::toGroup( child ), layerId );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QgsLayerTreeModel::disconnectFromLayer( QgsLayerTreeLayer* nodeLayer )
|
|
|
|
{
|
|
|
|
if ( !nodeLayer->layer() )
|
|
|
|
return; // we were never connected
|
|
|
|
|
|
|
|
if ( testFlag( ShowSymbology ) )
|
|
|
|
{
|
|
|
|
removeSymbologyFromLayer( nodeLayer );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( _numLayerCount( mRootNode, nodeLayer->layerId() ) == 1 )
|
|
|
|
{
|
|
|
|
// last instance of the layer in the tree: disconnect from all signals from layer!
|
|
|
|
disconnect( nodeLayer->layer(), 0, this, 0 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-13 18:04:08 +07:00
|
|
|
void QgsLayerTreeModel::recursivelyEmitDataChanged( const QModelIndex& idx )
|
|
|
|
{
|
|
|
|
QgsLayerTreeNode* node = index2node( idx );
|
|
|
|
if ( !node )
|
|
|
|
return;
|
|
|
|
|
|
|
|
int count = node->children().count();
|
|
|
|
if ( count == 0 )
|
|
|
|
return;
|
|
|
|
emit dataChanged( index( 0, 0, idx ), index( count - 1, 0, idx ) );
|
|
|
|
for ( int i = 0; i < count; ++i )
|
|
|
|
recursivelyEmitDataChanged( index( i, 0, idx ) );
|
|
|
|
}
|
|
|
|
|
2014-05-22 17:55:30 +07:00
|
|
|
|
2014-05-05 16:58:10 +02:00
|
|
|
Qt::DropActions QgsLayerTreeModel::supportedDropActions() const
|
|
|
|
{
|
2014-05-23 00:14:39 +07:00
|
|
|
return Qt::MoveAction;
|
2014-05-05 16:58:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QStringList QgsLayerTreeModel::mimeTypes() const
|
|
|
|
{
|
|
|
|
QStringList types;
|
|
|
|
types << "application/qgis.layertreemodeldata";
|
|
|
|
return types;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QMimeData* QgsLayerTreeModel::mimeData( const QModelIndexList& indexes ) const
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QList<QgsLayerTreeNode*> nodesFinal = indexes2nodes( indexes, true );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( nodesFinal.count() == 0 )
|
2014-05-05 16:58:10 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
QMimeData *mimeData = new QMimeData();
|
|
|
|
|
|
|
|
QDomDocument doc;
|
2014-05-21 15:28:23 +07:00
|
|
|
QDomElement rootElem = doc.createElement( "layer_tree_model_data" );
|
|
|
|
foreach ( QgsLayerTreeNode* node, nodesFinal )
|
|
|
|
node->writeXML( rootElem );
|
|
|
|
doc.appendChild( rootElem );
|
2014-05-05 16:58:10 +02:00
|
|
|
QString txt = doc.toString();
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
mimeData->setData( "application/qgis.layertreemodeldata", txt.toUtf8() );
|
2014-05-05 16:58:10 +02:00
|
|
|
return mimeData;
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
bool QgsLayerTreeModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( action == Qt::IgnoreAction )
|
2014-05-05 16:58:10 +02:00
|
|
|
return true;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !data->hasFormat( "application/qgis.layertreemodeldata" ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
return false;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( column > 0 )
|
2014-05-05 16:58:10 +02:00
|
|
|
return false;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeNode* nodeParent = index2node( parent );
|
|
|
|
if ( !QgsLayerTree::isGroup( nodeParent ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
return false;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QByteArray encodedData = data->data( "application/qgis.layertreemodeldata" );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
|
|
|
QDomDocument doc;
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( !doc.setContent( QString::fromUtf8( encodedData ) ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
QDomElement rootElem = doc.documentElement();
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( rootElem.tagName() != "layer_tree_model_data" )
|
2014-05-05 16:58:10 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
QList<QgsLayerTreeNode*> nodes;
|
|
|
|
|
|
|
|
QDomElement elem = rootElem.firstChildElement();
|
2014-05-21 15:28:23 +07:00
|
|
|
while ( !elem.isNull() )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeNode* node = QgsLayerTreeNode::readXML( elem );
|
|
|
|
if ( node )
|
2014-05-05 16:58:10 +02:00
|
|
|
nodes << node;
|
|
|
|
|
|
|
|
elem = elem.nextSiblingElement();
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( nodes.count() == 0 )
|
2014-05-05 16:58:10 +02:00
|
|
|
return false;
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
if ( parent.isValid() && row == -1 )
|
2014-05-18 00:34:03 +07:00
|
|
|
row = 0; // if dropped directly onto group item, insert at first position
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTree::toGroup( nodeParent )->insertChildNodes( row, nodes );
|
2014-05-05 16:58:10 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-05-21 15:28:23 +07:00
|
|
|
bool QgsLayerTreeModel::removeRows( int row, int count, const QModelIndex& parent )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTreeNode* parentNode = index2node( parent );
|
|
|
|
if ( QgsLayerTree::isGroup( parentNode ) )
|
2014-05-05 16:58:10 +02:00
|
|
|
{
|
2014-05-21 15:28:23 +07:00
|
|
|
QgsLayerTree::toGroup( parentNode )->removeChildren( row, count );
|
2014-05-05 16:58:10 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2014-05-23 18:50:31 +07:00
|
|
|
|
2014-05-27 20:49:47 +07:00
|
|
|
void QgsLayerTreeModel::setFlags( QgsLayerTreeModel::Flags f )
|
|
|
|
{
|
|
|
|
mFlags = f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QgsLayerTreeModel::setFlag( QgsLayerTreeModel::Flag f, bool on )
|
|
|
|
{
|
|
|
|
if ( on )
|
|
|
|
mFlags |= f;
|
|
|
|
else
|
|
|
|
mFlags &= ~f;
|
|
|
|
}
|
|
|
|
|
|
|
|
QgsLayerTreeModel::Flags QgsLayerTreeModel::flags() const
|
|
|
|
{
|
|
|
|
return mFlags;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QgsLayerTreeModel::testFlag( QgsLayerTreeModel::Flag f ) const
|
|
|
|
{
|
|
|
|
return mFlags.testFlag( f );
|
|
|
|
}
|
|
|
|
|
2014-05-23 18:50:31 +07:00
|
|
|
|
|
|
|
const QIcon& QgsLayerTreeModel::iconGroup()
|
|
|
|
{
|
|
|
|
static QIcon icon;
|
|
|
|
|
|
|
|
if ( icon.isNull() )
|
|
|
|
icon = QgsApplication::getThemeIcon( "/mActionFolder.png" );
|
|
|
|
|
|
|
|
return icon;
|
|
|
|
}
|