Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgslayertreeregistrybridge.cpp 3 : : -------------------------------------- 4 : : Date : May 2014 5 : : Copyright : (C) 2014 by Martin Dobias 6 : : Email : wonder dot sk at gmail dot com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : #include "qgslayertreeregistrybridge.h" 17 : : 18 : : #include "qgslayertree.h" 19 : : 20 : : #include "qgsproject.h" 21 : : #include "qgslogger.h" 22 : : 23 : 5 : QgsLayerTreeRegistryBridge::QgsLayerTreeRegistryBridge( QgsLayerTreeGroup *root, QgsProject *project, QObject *parent ) 24 : 5 : : QObject( parent ) 25 : 5 : , mRoot( root ) 26 : 5 : , mProject( project ) 27 : 5 : , mRegistryRemovingLayers( false ) 28 : 5 : , mEnabled( true ) 29 : 5 : , mNewLayersVisible( true ) 30 : 5 : , mInsertionPoint( root, 0 ) 31 : 10 : { 32 : 5 : connect( mProject, &QgsProject::legendLayersAdded, this, &QgsLayerTreeRegistryBridge::layersAdded ); 33 : 5 : connect( mProject, qOverload<const QStringList &>( &QgsProject::layersWillBeRemoved ), this, &QgsLayerTreeRegistryBridge::layersWillBeRemoved ); 34 : : 35 : 5 : connect( mRoot, &QgsLayerTreeNode::willRemoveChildren, this, &QgsLayerTreeRegistryBridge::groupWillRemoveChildren ); 36 : 5 : connect( mRoot, &QgsLayerTreeNode::removedChildren, this, &QgsLayerTreeRegistryBridge::groupRemovedChildren ); 37 : 5 : } 38 : : 39 : 0 : void QgsLayerTreeRegistryBridge::setLayerInsertionPoint( QgsLayerTreeGroup *parentGroup, int index ) 40 : : { 41 : 0 : mInsertionPoint.group = parentGroup; 42 : 0 : mInsertionPoint.position = index; 43 : 0 : } 44 : : 45 : 0 : void QgsLayerTreeRegistryBridge::setLayerInsertionPoint( const InsertionPoint &insertionPoint ) 46 : : { 47 : 0 : mInsertionPoint = insertionPoint; 48 : 0 : } 49 : : 50 : 1 : void QgsLayerTreeRegistryBridge::layersAdded( const QList<QgsMapLayer *> &layers ) 51 : : { 52 : 1 : if ( !mEnabled ) 53 : 0 : return; 54 : : 55 : 1 : QList<QgsLayerTreeNode *> nodes; 56 : 1 : const auto constLayers = layers; 57 : 2 : for ( QgsMapLayer *layer : constLayers ) 58 : : { 59 : 1 : QgsLayerTreeLayer *nodeLayer = new QgsLayerTreeLayer( layer ); 60 : 1 : nodeLayer->setItemVisibilityChecked( mNewLayersVisible ); 61 : : 62 : 1 : nodes << nodeLayer; 63 : : 64 : : // check whether the layer is marked as embedded 65 : 1 : QString projectFile = mProject->layerIsEmbedded( nodeLayer->layerId() ); 66 : 1 : if ( !projectFile.isEmpty() ) 67 : : { 68 : 0 : nodeLayer->setCustomProperty( QStringLiteral( "embedded" ), 1 ); 69 : 0 : nodeLayer->setCustomProperty( QStringLiteral( "embedded_project" ), projectFile ); 70 : 0 : } 71 : 1 : } 72 : : 73 : : // add new layers to the right place 74 : 1 : mInsertionPoint.group->insertChildNodes( mInsertionPoint.position, nodes ); 75 : : 76 : : // tell other components that layers have been added - this signal is used in QGIS to auto-select the first layer 77 : 1 : emit addedLayersToLayerTree( layers ); 78 : 1 : } 79 : : 80 : 0 : void QgsLayerTreeRegistryBridge::layersWillBeRemoved( const QStringList &layerIds ) 81 : : { 82 : 0 : QgsDebugMsgLevel( QStringLiteral( "%1 layers will be removed, enabled:%2" ).arg( layerIds.count() ).arg( mEnabled ), 4 ); 83 : : 84 : 0 : if ( !mEnabled ) 85 : 0 : return; 86 : : 87 : : // when we start removing child nodes, the bridge would try to remove those layers from 88 : : // the registry _again_ in groupRemovedChildren() - this prevents it 89 : 0 : mRegistryRemovingLayers = true; 90 : : 91 : 0 : const auto constLayerIds = layerIds; 92 : 0 : for ( const QString &layerId : constLayerIds ) 93 : : { 94 : 0 : QgsLayerTreeLayer *nodeLayer = mRoot->findLayer( layerId ); 95 : 0 : if ( nodeLayer ) 96 : 0 : qobject_cast<QgsLayerTreeGroup *>( nodeLayer->parent() )->removeChildNode( nodeLayer ); 97 : : } 98 : : 99 : 0 : mRegistryRemovingLayers = false; 100 : 0 : } 101 : : 102 : : 103 : 1 : static void _collectLayerIdsInGroup( QgsLayerTreeGroup *group, int indexFrom, int indexTo, QStringList &lst ) 104 : : { 105 : 2 : for ( int i = indexFrom; i <= indexTo; ++i ) 106 : : { 107 : 1 : QgsLayerTreeNode *child = group->children().at( i ); 108 : 1 : if ( QgsLayerTree::isLayer( child ) ) 109 : : { 110 : 1 : lst << QgsLayerTree::toLayer( child )->layerId(); 111 : 1 : } 112 : 0 : else if ( QgsLayerTree::isGroup( child ) ) 113 : : { 114 : 0 : _collectLayerIdsInGroup( QgsLayerTree::toGroup( child ), 0, child->children().count() - 1, lst ); 115 : 0 : } 116 : 1 : } 117 : 1 : } 118 : : 119 : 1 : void QgsLayerTreeRegistryBridge::groupWillRemoveChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo ) 120 : : { 121 : 1 : if ( mRegistryRemovingLayers ) 122 : 0 : return; // do not try to remove those layers again 123 : : 124 : : Q_ASSERT( mLayerIdsForRemoval.isEmpty() ); 125 : : 126 : : Q_ASSERT( QgsLayerTree::isGroup( node ) ); 127 : 1 : QgsLayerTreeGroup *group = QgsLayerTree::toGroup( node ); 128 : : 129 : 1 : _collectLayerIdsInGroup( group, indexFrom, indexTo, mLayerIdsForRemoval ); 130 : 1 : } 131 : : 132 : 1 : void QgsLayerTreeRegistryBridge::groupRemovedChildren() 133 : : { 134 : 1 : if ( mRegistryRemovingLayers ) 135 : 0 : return; // do not try to remove those layers again 136 : : 137 : : // remove only those that really do not exist in the tree 138 : : // (ignores layers that were dragged'n'dropped: 1. drop new 2. remove old) 139 : 1 : QStringList toRemove; 140 : 1 : const auto constMLayerIdsForRemoval = mLayerIdsForRemoval; 141 : 2 : for ( const QString &layerId : constMLayerIdsForRemoval ) 142 : 1 : if ( !mRoot->findLayer( layerId ) ) 143 : 1 : toRemove << layerId; 144 : 1 : mLayerIdsForRemoval.clear(); 145 : : 146 : 1 : QgsDebugMsgLevel( QStringLiteral( "%1 layers will be removed" ).arg( toRemove.count() ), 4 ); 147 : : 148 : : // delay the removal of layers from the registry. There may be other slots connected to map layer registry's signals 149 : : // that might disrupt the execution flow - e.g. a processEvents() call may force update of layer tree view with 150 : : // semi-broken tree model 151 : 1 : QMetaObject::invokeMethod( this, "removeLayersFromRegistry", Qt::QueuedConnection, Q_ARG( QStringList, toRemove ) ); 152 : 1 : } 153 : : 154 : 0 : void QgsLayerTreeRegistryBridge::removeLayersFromRegistry( const QStringList &layerIds ) 155 : : { 156 : 0 : mProject->removeMapLayers( layerIds ); 157 : 0 : }