QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgslayertreemapcanvasbridge.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayertreemapcanvasbridge.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 
17 
18 #include "qgslayertree.h"
19 #include "qgslayertreeutils.h"
20 #include "qgsmaplayer.h"
21 #include "qgsvectorlayer.h"
22 #include "qgsmapcanvas.h"
23 
25  : QObject( parent )
26  , mRoot( root )
27  , mCanvas( canvas )
28  , mPendingCanvasUpdate( false )
29  , mHasCustomLayerOrder( false )
30  , mAutoSetupOnFirstLayer( true )
31  , mAutoEnableCrsTransform( true )
32  , mLastLayerCount( root->findLayers().count() )
33 {
34  connect( root, SIGNAL( addedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeAddedChildren( QgsLayerTreeNode*, int, int ) ) );
35  connect( root, SIGNAL( customPropertyChanged( QgsLayerTreeNode*, QString ) ), this, SLOT( nodeCustomPropertyChanged( QgsLayerTreeNode*, QString ) ) );
36  connect( root, SIGNAL( removedChildren( QgsLayerTreeNode*, int, int ) ), this, SLOT( nodeRemovedChildren() ) );
37  connect( root, SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged() ) );
38 
40 }
41 
43 {
44  setHasCustomLayerOrder( false );
46 }
47 
49 {
50  QStringList order;
51  defaultLayerOrder( mRoot, order );
52  return order;
53 }
54 
56 {
57  if ( QgsLayerTree::isLayer( node ) )
58  {
59  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
60  order << nodeLayer->layerId();
61  }
62 
63  foreach ( QgsLayerTreeNode* child, node->children() )
64  defaultLayerOrder( child, order );
65 }
66 
67 
69 {
70  if ( mHasCustomLayerOrder == state )
71  return;
72 
73  mHasCustomLayerOrder = state;
75 
77 }
78 
79 void QgsLayerTreeMapCanvasBridge::setCustomLayerOrder( const QStringList& order )
80 {
81  if ( mCustomLayerOrder == order )
82  return;
83 
84  // verify that the new order is correct
85  QStringList defOrder = defaultLayerOrder();
86  QStringList sortedNewOrder = order;
87  qSort( defOrder );
88  qSort( sortedNewOrder );
89  if ( defOrder != sortedNewOrder )
90  return; // must be permutation of the default order
91 
92  mCustomLayerOrder = order;
94 
97 }
98 
100 {
101  QList<QgsMapCanvasLayer> layers;
102 
103  if ( mHasCustomLayerOrder )
104  {
105  foreach ( QString layerId, mCustomLayerOrder )
106  {
107  QgsLayerTreeLayer* nodeLayer = mRoot->findLayer( layerId );
108  if ( nodeLayer )
109  layers << QgsMapCanvasLayer( nodeLayer->layer(), nodeLayer->isVisible() == Qt::Checked, nodeLayer->customProperty( "overview", 0 ).toInt() );
110  }
111  }
112  else
113  setCanvasLayers( mRoot, layers );
114 
115  QList<QgsLayerTreeLayer*> layerNodes = mRoot->findLayers();
116  int currentLayerCount = layerNodes.count();
117  bool firstLayers = mAutoSetupOnFirstLayer && mLastLayerCount == 0 && currentLayerCount != 0;
118 
119  if ( firstLayers )
120  {
121  // also setup destination CRS and map units if the OTF projections are not yet enabled
123  {
124  foreach ( QgsLayerTreeLayer* layerNode, layerNodes )
125  {
126  if ( layerNode->layer() &&
127  (
128  qobject_cast<QgsVectorLayer *>( layerNode->layer() ) == 0 ||
129  qobject_cast<QgsVectorLayer *>( layerNode->layer() )->geometryType() != QGis::NoGeometry
130  )
131  )
132  {
133  mCanvas->setDestinationCrs( layerNode->layer()->crs() );
134  mCanvas->setMapUnits( layerNode->layer()->crs().mapUnits() );
135  break;
136  }
137  }
138  }
139  }
140 
141  mCanvas->setLayerSet( layers );
142 
143  if ( firstLayers )
144  {
145  // if we are moving from zero to non-zero layers, let's zoom to those data
147  }
148 
149  if ( !mFirstCRS.isValid() )
150  {
151  // find out what is the first used CRS in case we may need to turn on OTF projections later
152  foreach ( QgsLayerTreeLayer* layerNode, layerNodes )
153  {
154  if ( layerNode->layer() && layerNode->layer()->crs().isValid() )
155  {
156  mFirstCRS = layerNode->layer()->crs();
157  break;
158  }
159  }
160  }
161 
163  {
164  // check whether all layers still have the same CRS
165  foreach ( QgsLayerTreeLayer* layerNode, layerNodes )
166  {
167  if ( layerNode->layer() && layerNode->layer()->crs().isValid() && layerNode->layer()->crs() != mFirstCRS )
168  {
171  break;
172  }
173  }
174  }
175 
176  mLastLayerCount = currentLayerCount;
177  if ( currentLayerCount == 0 )
179 
180  mPendingCanvasUpdate = false;
181 }
182 
183 void QgsLayerTreeMapCanvasBridge::readProject( const QDomDocument& doc )
184 {
185  QDomElement elem = doc.documentElement().firstChildElement( "layer-tree-canvas" );
186  if ( elem.isNull() )
187  {
188  bool oldEnabled;
189  QStringList oldOrder;
190  if ( QgsLayerTreeUtils::readOldLegendLayerOrder( doc.documentElement().firstChildElement( "legend" ), oldEnabled, oldOrder ) )
191  {
192  setHasCustomLayerOrder( oldEnabled );
193  setCustomLayerOrder( oldOrder );
194  }
195  return;
196  }
197 
198  QDomElement customOrderElem = elem.firstChildElement( "custom-order" );
199  if ( !customOrderElem.isNull() )
200  {
201  QStringList order;
202  QDomElement itemElem = customOrderElem.firstChildElement( "item" );
203  while ( !itemElem.isNull() )
204  {
205  order.append( itemElem.text() );
206  itemElem = itemElem.nextSiblingElement( "item" );
207  }
208 
209  setHasCustomLayerOrder( customOrderElem.attribute( "enabled", 0 ).toInt() );
210  setCustomLayerOrder( order );
211  }
212 }
213 
215 {
216  QDomElement elem = doc.createElement( "layer-tree-canvas" );
217  QDomElement customOrderElem = doc.createElement( "custom-order" );
218  customOrderElem.setAttribute( "enabled", mHasCustomLayerOrder ? 1 : 0 );
219 
220  foreach ( QString layerId, mCustomLayerOrder )
221  {
222  QDomElement itemElem = doc.createElement( "item" );
223  itemElem.appendChild( doc.createTextNode( layerId ) );
224  customOrderElem.appendChild( itemElem );
225  }
226  elem.appendChild( customOrderElem );
227 
228  doc.documentElement().appendChild( elem );
229 }
230 
231 void QgsLayerTreeMapCanvasBridge::setCanvasLayers( QgsLayerTreeNode *node, QList<QgsMapCanvasLayer> &layers )
232 {
233  if ( QgsLayerTree::isLayer( node ) )
234  {
235  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
236  layers << QgsMapCanvasLayer( nodeLayer->layer(), nodeLayer->isVisible() == Qt::Checked, nodeLayer->customProperty( "overview", 0 ).toInt() );
237  }
238 
239  foreach ( QgsLayerTreeNode* child, node->children() )
240  setCanvasLayers( child, layers );
241 }
242 
244 {
245  if ( mPendingCanvasUpdate )
246  return;
247 
248  mPendingCanvasUpdate = true;
249  QMetaObject::invokeMethod( this, "setCanvasLayers", Qt::QueuedConnection );
250 }
251 
252 void QgsLayerTreeMapCanvasBridge::nodeAddedChildren( QgsLayerTreeNode* node, int indexFrom, int indexTo )
253 {
254  Q_ASSERT( node );
255 
256  // collect layer IDs that have been added in order to put them into custom layer order
257  QStringList layerIds;
258  QList<QgsLayerTreeNode*> children = node->children();
259  for ( int i = indexFrom; i <= indexTo; ++i )
260  {
261  QgsLayerTreeNode* child = children.at( i );
262  if ( QgsLayerTree::isLayer( child ) )
263  {
264  layerIds << QgsLayerTree::toLayer( child )->layerId();
265  }
266  else if ( QgsLayerTree::isGroup( child ) )
267  {
268  foreach ( QgsLayerTreeLayer* nodeL, QgsLayerTree::toGroup( child )->findLayers() )
269  layerIds << nodeL->layerId();
270  }
271  }
272 
273  foreach ( QString layerId, layerIds )
274  {
275  if ( !mCustomLayerOrder.contains( layerId ) )
276  mCustomLayerOrder.append( layerId );
277  }
278 
280 
282 }
283 
285 {
286  // no need to disconnect from removed nodes as they are deleted
287 
288  // check whether the layers are still there, if not, remove them from the layer order!
289  QList<int> toRemove;
290  for ( int i = 0; i < mCustomLayerOrder.count(); ++i )
291  {
293  if ( !node )
294  toRemove << i;
295  }
296  for ( int i = toRemove.count() - 1; i >= 0; --i )
297  mCustomLayerOrder.removeAt( toRemove[i] );
299 
301 }
302 
304 {
306 }
307 
309 {
310  Q_UNUSED( node );
311  if ( key == "overview" )
313 }
314