QGIS API Documentation  2.5.0-Master
 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 == override )
71  return;
72 
73  mHasCustomLayerOrder = override;
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 
static bool readOldLegendLayerOrder(const QDomElement &legendElem, bool &hasCustomOrder, QStringList &order)
Try to load custom layer order from.
Layer tree group node serves as a container for layers and further groups.
void hasCustomLayerOrderChanged(bool)
void setCustomLayerOrder(const QStringList &order)
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QgsMapLayer * layer() const
A class that stores visibility and presence in overview flags together with pointer to the layer...
Definition: qgsmapcanvas.h:74
QgsLayerTreeLayer * findLayer(const QString &layerId)
Find layer node representing the map layer specified by its ID. Searches recursively the whole sub-tr...
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
void setCanvasLayers()
force update of canvas layers from the layer tree. Normally this should not be needed to be called...
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:104
QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group. No type checking is done - use isGroup() to find out whether this operation is ...
Definition: qgslayertree.h:46
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
sets destination coordinate reference system
void setCrsTransformEnabled(bool enabled)
sets whether to use projections for this layer set
Qt::CheckState isVisible() const
void nodeCustomPropertyChanged(QgsLayerTreeNode *node, QString key)
void setLayerSet(QList< QgsMapCanvasLayer > &layers)
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes. Searches recursively the whole sub-tree.
void nodeAddedChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)
This class is a base class for nodes in a layer tree.
QString layerId() const
QList< QgsLayerTreeNode * > children()
Get list of children of the node. Children are owned by the parent.
bool isLayer(QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:40
void readProject(const QDomDocument &doc)
QgsLayerTreeMapCanvasBridge(QgsLayerTreeGroup *root, QgsMapCanvas *canvas, QObject *parent=0)
Constructor: does not take ownership of the layer tree nor canvas.
QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer. No type checking is done - use isLayer() to find out whether this operation is ...
Definition: qgslayertree.h:52
void zoomToFullExtent()
Zoom to the full extent of all layers.
Class for storing a coordinate reference system (CRS)
const QgsCoordinateReferenceSystem & crs() const
Returns layer's spatial reference system.
void customLayerOrderChanged(const QStringList &order)
void setMapUnits(QGis::UnitType mapUnits)
Set map units (needed by project properties dialog)
QgsCoordinateReferenceSystem mFirstCRS
Represents a vector layer which manages a vector based data sets.
bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:34
Layer tree node points to a map layer.