QGIS API Documentation  3.2.0-Bonn (bc43194)
qgslayertreeviewdefaultactions.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayertreeviewdefaultactions.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 "qgsapplication.h"
19 #include "qgslayertree.h"
20 #include "qgslayertreemodel.h"
21 #include "qgslayertreeview.h"
22 #include "qgsmapcanvas.h"
23 #include "qgsproject.h"
24 #include "qgsvectorlayer.h"
25 
26 #include <QAction>
27 
29  : QObject( view )
30  , mView( view )
31 {
32 }
33 
35 {
36  QAction *a = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddGroup.svg" ) ), tr( "&Add Group" ), parent );
37  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::addGroup );
38  return a;
39 }
40 
42 {
43  QAction *a = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionRemoveLayer.svg" ) ), tr( "&Remove" ), parent );
44  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::removeGroupOrLayer );
45  return a;
46 }
47 
49 {
51  if ( !node )
52  return nullptr;
53 
54  QAction *a = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionInOverview.svg" ) ), tr( "&Show in Overview" ), parent );
55  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::showInOverview );
56  a->setCheckable( true );
57  a->setChecked( node->customProperty( QStringLiteral( "overview" ), 0 ).toInt() );
58  return a;
59 }
60 
62 {
64  if ( !node )
65  return nullptr;
66 
67  QString text;
68  if ( QgsLayerTree::isGroup( node ) )
69  text = tr( "Re&name Group" );
70  else
71  text = tr( "Re&name Layer" );
72 
73  QAction *a = new QAction( text, parent );
74  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::renameGroupOrLayer );
75  return a;
76 }
77 
79 {
81  if ( !node )
82  return nullptr;
83 
84  QAction *a = new QAction( tr( "Show Feature Count" ), parent );
85  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::showFeatureCount );
86  a->setCheckable( true );
87  a->setChecked( node->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toInt() );
88  return a;
89 }
90 
92 {
93  QAction *a = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomToLayer.svg" ) ),
94  tr( "&Zoom to Layer" ), parent );
95  a->setData( QVariant::fromValue( reinterpret_cast<void *>( canvas ) ) );
96  connect( a, &QAction::triggered, this, static_cast<void ( QgsLayerTreeViewDefaultActions::* )()>( &QgsLayerTreeViewDefaultActions::zoomToLayer ) );
97  return a;
98 }
99 
101 {
102  QAction *a = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomToSelected.svg" ) ),
103  tr( "&Zoom to Selection" ), parent );
104  a->setData( QVariant::fromValue( reinterpret_cast<void *>( canvas ) ) );
105  connect( a, &QAction::triggered, this, static_cast<void ( QgsLayerTreeViewDefaultActions::* )()>( &QgsLayerTreeViewDefaultActions::zoomToSelection ) );
106  return a;
107 }
108 
110 {
111  QAction *a = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomToLayer.svg" ) ),
112  tr( "&Zoom to Group" ), parent );
113  a->setData( QVariant::fromValue( reinterpret_cast<void *>( canvas ) ) );
114  connect( a, &QAction::triggered, this, static_cast<void ( QgsLayerTreeViewDefaultActions::* )()>( &QgsLayerTreeViewDefaultActions::zoomToGroup ) );
115  return a;
116 }
117 
119 {
120  QAction *a = new QAction( tr( "&Move to Top-level" ), parent );
122  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::makeTopLevel );
124  return a;
125 }
126 
128 {
129  QAction *a = new QAction( tr( "Move Out of &Group" ), parent );
130  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::moveOutOfGroup );
131  return a;
132 }
133 
135 {
136  QAction *a = new QAction( tr( "Move to &Top" ), parent );
137  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::moveToTop );
138  return a;
139 }
140 
142 {
143  QAction *a = new QAction( tr( "&Group Selected" ), parent );
144  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::groupSelected );
145  return a;
146 }
147 
149 {
151  if ( !node || !QgsLayerTree::isGroup( node ) )
152  return nullptr;
153 
154  QAction *a = new QAction( tr( "Mutually Exclusive Group" ), parent );
155  a->setCheckable( true );
156  a->setChecked( QgsLayerTree::toGroup( node )->isMutuallyExclusive() );
157  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::mutuallyExclusiveGroup );
158  return a;
159 }
160 
162 {
164  if ( !node || !QgsLayerTree::isGroup( node ) || node->isItemVisibilityCheckedRecursive() )
165  return nullptr;
166 #ifdef Q_OS_MACX
167  QAction *a = new QAction( tr( "Check and All its Children (⌘-click)" ), parent );
168 #else
169  QAction *a = new QAction( tr( "Check and All its Children (Ctrl-click)" ), parent );
170 #endif
171  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::checkAndAllChildren );
172  return a;
173 }
174 
176 {
178  if ( !node || !QgsLayerTree::isGroup( node ) || node->isItemVisibilityUncheckedRecursive() )
179  return nullptr;
180 #ifdef Q_OS_MACX
181  QAction *a = new QAction( tr( "Uncheck and All its Children (⌘-click)" ), parent );
182 #else
183  QAction *a = new QAction( tr( "Uncheck and All its Children (Ctrl-click)" ), parent );
184 #endif
185  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::uncheckAndAllChildren );
186  return a;
187 }
188 
190 {
192  if ( !node || !QgsLayerTree::isLayer( node ) || node->isVisible() )
193  return nullptr;
194  QAction *a = new QAction( tr( "Check and All its Parents" ), parent );
195  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::checkAndAllParents );
196  return a;
197 }
198 
199 void QgsLayerTreeViewDefaultActions::checkAndAllChildren()
200 {
202  if ( !node )
203  return;
204  node->setItemVisibilityCheckedRecursive( true );
205 }
206 
207 void QgsLayerTreeViewDefaultActions::uncheckAndAllChildren()
208 {
210  if ( !node )
211  return;
212  node->setItemVisibilityCheckedRecursive( false );
213 }
214 
215 void QgsLayerTreeViewDefaultActions::checkAndAllParents()
216 {
218  if ( !node )
219  return;
221 }
222 
224 {
226  if ( !group )
227  group = mView->layerTreeModel()->rootGroup();
228 
229  QgsLayerTreeGroup *newGroup = group->addGroup( uniqueGroupName( group ) );
230  mView->edit( mView->layerTreeModel()->node2index( newGroup ) );
231 }
232 
234 {
235  Q_FOREACH ( QgsLayerTreeNode *node, mView->selectedNodes( true ) )
236  {
237  // could be more efficient if working directly with ranges instead of individual nodes
238  qobject_cast<QgsLayerTreeGroup *>( node->parent() )->removeChildNode( node );
239  }
240 }
241 
243 {
244  mView->edit( mView->currentIndex() );
245 }
246 
248 {
250  if ( !node )
251  return;
252  int newValue = node->customProperty( QStringLiteral( "overview" ), 0 ).toInt();
253  Q_FOREACH ( QgsLayerTreeLayer *l, mView->selectedLayerNodes() )
254  l->setCustomProperty( QStringLiteral( "overview" ), newValue ? 0 : 1 );
255 }
256 
258 {
260  if ( !QgsLayerTree::isLayer( node ) )
261  return;
262 
263  int newValue = node->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toInt();
264  Q_FOREACH ( QgsLayerTreeLayer *l, mView->selectedLayerNodes() )
265  l->setCustomProperty( QStringLiteral( "showFeatureCount" ), newValue ? 0 : 1 );
266 }
267 
268 
270 {
271  QgsMapLayer *layer = mView->currentLayer();
272  if ( !layer )
273  return;
274 
275  QList<QgsMapLayer *> layers;
276  layers << layer;
277  zoomToLayers( canvas, layers );
278 }
279 
281 {
282  QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( mView->currentLayer() );
283  if ( !layer )
284  return;
285 
286  canvas->zoomToSelected( layer );
287 }
288 
290 {
291  QgsLayerTreeGroup *groupNode = mView->currentGroupNode();
292  if ( !groupNode )
293  return;
294 
295  QList<QgsMapLayer *> layers;
296  Q_FOREACH ( const QString &layerId, groupNode->findLayerIds() )
297  layers << QgsProject::instance()->mapLayer( layerId );
298 
299  zoomToLayers( canvas, layers );
300 }
301 
303 {
304  QAction *s = qobject_cast<QAction *>( sender() );
305  QgsMapCanvas *canvas = reinterpret_cast<QgsMapCanvas *>( s->data().value<void *>() );
306  QApplication::setOverrideCursor( Qt::WaitCursor );
307  zoomToLayer( canvas );
308  QApplication::restoreOverrideCursor();
309 }
310 
312 {
313  QAction *s = qobject_cast<QAction *>( sender() );
314  QgsMapCanvas *canvas = reinterpret_cast<QgsMapCanvas *>( s->data().value<void *>() );
315  QgsTemporaryCursorOverride waitCursor( Qt::WaitCursor );
316  zoomToSelection( canvas );
317 }
318 
320 {
321  QAction *s = qobject_cast<QAction *>( sender() );
322  QgsMapCanvas *canvas = reinterpret_cast<QgsMapCanvas *>( s->data().value<void *>() );
323  QApplication::setOverrideCursor( Qt::WaitCursor );
324  zoomToGroup( canvas );
325  QApplication::restoreOverrideCursor();
326 }
327 
328 
329 void QgsLayerTreeViewDefaultActions::zoomToLayers( QgsMapCanvas *canvas, const QList<QgsMapLayer *> &layers )
330 {
331  QgsRectangle extent;
332  extent.setMinimal();
333 
334  for ( int i = 0; i < layers.size(); ++i )
335  {
336  QgsMapLayer *layer = layers.at( i );
337  QgsRectangle layerExtent = layer->extent();
338 
339  QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( layer );
340  if ( vLayer )
341  {
342  if ( vLayer->geometryType() == QgsWkbTypes::NullGeometry )
343  continue;
344 
345  if ( layerExtent.isEmpty() )
346  {
347  vLayer->updateExtents();
348  layerExtent = vLayer->extent();
349  }
350  }
351 
352  if ( layerExtent.isNull() )
353  continue;
354 
355  //transform extent
356  layerExtent = canvas->mapSettings().layerExtentToOutputExtent( layer, layerExtent );
357 
358  extent.combineExtentWith( layerExtent );
359  }
360 
361  if ( extent.isNull() )
362  return;
363 
364  // Increase bounding box with 5%, so that layer is a bit inside the borders
365  extent.scale( 1.05 );
366 
367  //zoom to bounding box
368  canvas->setExtent( extent );
369  canvas->refresh();
370 }
371 
372 
374 {
375  QString prefix = parentGroup == mView->layerTreeModel()->rootGroup() ? "group" : "sub-group";
376  QString newName = prefix + '1';
377  for ( int i = 2; parentGroup->findGroup( newName ); ++i )
378  newName = prefix + QString::number( i );
379  return newName;
380 }
381 
382 
384 {
385  Q_FOREACH ( QgsLayerTreeLayer *l, mView->selectedLayerNodes() )
386  {
387  QgsLayerTreeGroup *rootGroup = mView->layerTreeModel()->rootGroup();
388  QgsLayerTreeGroup *parentGroup = qobject_cast<QgsLayerTreeGroup *>( l->parent() );
389  if ( !parentGroup || parentGroup == rootGroup )
390  continue;
391  QgsLayerTreeLayer *clonedLayer = l->clone();
392  rootGroup->addChildNode( clonedLayer );
393  parentGroup->removeChildNode( l );
394  }
395 }
396 
397 
399 {
400  const QList< QgsLayerTreeLayer * > selectedLayerNodes = mView->selectedLayerNodes();
401  for ( QgsLayerTreeLayer *l : selectedLayerNodes )
402  {
403  QgsLayerTreeGroup *rootGroup = mView->layerTreeModel()->rootGroup();
404  QgsLayerTreeGroup *parentGroup = qobject_cast<QgsLayerTreeGroup *>( l->parent() );
405  if ( !parentGroup || parentGroup == rootGroup )
406  continue;
407  QgsLayerTreeGroup *tempGroup = parentGroup;
408  while ( tempGroup->parent() != rootGroup )
409  {
410  tempGroup = qobject_cast<QgsLayerTreeGroup *>( tempGroup->parent() );
411  }
412  QgsLayerTreeLayer *clonedLayer = l->clone();
413  int insertIdx = rootGroup->children().indexOf( tempGroup );
414  rootGroup->insertChildNode( insertIdx, clonedLayer );
415  parentGroup->removeChildNode( l );
416  }
417 }
418 
419 
421 {
422  QMap <QgsLayerTreeGroup *, int> groupInsertIdx;
423  int insertIdx;
424  const QList< QgsLayerTreeNode * > selectedNodes = mView->selectedNodes();
425  for ( QgsLayerTreeNode *n : selectedNodes )
426  {
427  QgsLayerTreeGroup *parentGroup = qobject_cast<QgsLayerTreeGroup *>( n->parent() );
428  QgsLayerTreeNode *clonedNode = n->clone();
429  if ( groupInsertIdx.contains( parentGroup ) )
430  {
431  insertIdx = groupInsertIdx.value( parentGroup );
432  }
433  else
434  {
435  insertIdx = 0;
436  }
437  parentGroup->insertChildNode( insertIdx, clonedNode );
438  parentGroup->removeChildNode( n );
439  groupInsertIdx.insert( parentGroup, insertIdx + 1 );
440  }
441 }
442 
444 {
445  QList<QgsLayerTreeNode *> nodes = mView->selectedNodes( true );
446  if ( nodes.count() < 2 || ! QgsLayerTree::isGroup( nodes[0]->parent() ) )
447  return;
448 
449  QgsLayerTreeGroup *parentGroup = QgsLayerTree::toGroup( nodes[0]->parent() );
450  int insertIdx = parentGroup->children().indexOf( nodes[0] );
451 
452  QgsLayerTreeGroup *newGroup = new QgsLayerTreeGroup( uniqueGroupName( parentGroup ) );
453  Q_FOREACH ( QgsLayerTreeNode *node, nodes )
454  newGroup->addChildNode( node->clone() );
455 
456  parentGroup->insertChildNode( insertIdx, newGroup );
457 
458  Q_FOREACH ( QgsLayerTreeNode *node, nodes )
459  {
460  QgsLayerTreeGroup *group = qobject_cast<QgsLayerTreeGroup *>( node->parent() );
461  if ( group )
462  group->removeChildNode( node );
463  }
464 
465  mView->setCurrentIndex( mView->layerTreeModel()->node2index( newGroup ) );
466  mView->edit( mView->layerTreeModel()->node2index( newGroup ) );
467 }
468 
470 {
472  if ( !node || !QgsLayerTree::isGroup( node ) )
473  return;
474 
475  QgsLayerTree::toGroup( node )->setIsMutuallyExclusive( !QgsLayerTree::toGroup( node )->isMutuallyExclusive() );
476 }
Layer tree group node serves as a container for layers and further groups.
A rectangle specified with double values.
Definition: qgsrectangle.h:40
Base class for all map layer types.
Definition: qgsmaplayer.h:61
The QgsLayerTreeView class extends QTreeView and provides some additional functionality when working ...
QgsLayerTreeGroup * addGroup(const QString &name)
Append a new group node with given name.
Temporarily sets a cursor override for the QApplication for the lifetime of the object.
Definition: qgsguiutils.h:175
void zoomToSelection()
Slot to zoom to selected features of a vector layer.
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
Definition: qgsrectangle.h:150
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:43
bool isItemVisibilityUncheckedRecursive() const
Returns whether this node is unchecked and all its children.
void setIsMutuallyExclusive(bool enabled, int initialChildIndex=-1)
Set whether the group is mutually exclusive (only one child can be checked at a time).
void zoomToLayers(QgsMapCanvas *canvas, const QList< QgsMapLayer *> &layers)
QAction * actionZoomToGroup(QgsMapCanvas *canvas, QObject *parent=nullptr)
virtual QgsLayerTreeNode * clone() const =0
Create a copy of the node. Returns new instance.
QAction * actionMoveOutOfGroup(QObject *parent=nullptr)
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
Definition: qgslayertree.h:64
QAction * actionCheckAndAllChildren(QObject *parent=nullptr)
Action to check a group and all its children.
QgsLayerTreeViewDefaultActions(QgsLayerTreeView *view)
QAction * actionAddGroup(QObject *parent=nullptr)
void scale(double scaleFactor, const QgsPointXY *c=nullptr)
Scale the rectangle around its center point.
Definition: qgsrectangle.h:234
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:538
QAction * actionGroupSelected(QObject *parent=nullptr)
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
QAction * actionRemoveGroupOrLayer(QObject *parent=nullptr)
void refresh()
Repaints the canvas map.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
void removeChildNode(QgsLayerTreeNode *node)
Remove a child node from this group.
bool isVisible() const
Returns whether a node is really visible (ie checked and all its ancestors checked as well) ...
QgsMapLayer * currentLayer() const
Gets currently selected layer. May be null.
QModelIndex node2index(QgsLayerTreeNode *node) const
Returns index for a given node. If the node does not belong to the layer tree, the result is undefine...
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:74
virtual QgsRectangle extent() const
Returns the extent of the layer.
QList< QgsLayerTreeLayer * > selectedLayerNodes() const
Returns list of selected nodes filtered to just layer nodes.
void moveOutOfGroup()
Moves selected layer(s) out of the group(s) and places this/these above the group(s) ...
QAction * actionZoomToSelection(QgsMapCanvas *canvas, QObject *parent=nullptr)
Action to zoom to selected features of a vector layer.
The QgsLayerTreeViewDefaultActions class serves as a factory of actions that can be used together wit...
virtual void updateExtents(bool force=false)
Update the extents for the layer.
virtual void setItemVisibilityCheckedRecursive(bool checked)
Check or uncheck a node and all its children (taking into account exclusion rules) ...
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
QgsRectangle extent() const override
Returns the extent of the layer.
bool isEmpty() const
Returns true if the rectangle is empty.
Definition: qgsrectangle.h:419
Q_DECL_DEPRECATED QAction * actionMakeTopLevel(QObject *parent=nullptr)
void mutuallyExclusiveGroup()
Slot to enable/disable mutually exclusive group flag.
QgsLayerTreeNode * parent()
Gets pointer to the parent. If parent is a null pointer, the node is a root node. ...
QgsLayerTreeGroup * currentGroupNode() const
Gets current group node. If a layer is current node, the function will return parent group...
QAction * actionCheckAndAllParents(QObject *parent=nullptr)
Action to check a group and all its parents.
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer. Properties are stored in a map and saved in project file...
QgsRectangle layerExtentToOutputExtent(const QgsMapLayer *layer, QgsRectangle extent) const
transform bounding box from layer&#39;s CRS to output CRS
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:53
This class is a base class for nodes in a layer tree.
QgsLayerTreeModel * layerTreeModel() const
Gets access to the model casted to QgsLayerTreeModel.
void zoomToSelected(QgsVectorLayer *layer=nullptr)
Zoom to the extent of the selected features of provided (vector) layer.
void setItemVisibilityCheckedParentRecursive(bool checked)
Check or uncheck a node and all its parents.
bool isItemVisibilityCheckedRecursive() const
Returns whether this node is checked and all its children.
QAction * actionZoomToLayer(QgsMapCanvas *canvas, QObject *parent=nullptr)
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle...
Definition: qgsrectangle.h:352
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:539
QAction * actionMutuallyExclusiveGroup(QObject *parent=nullptr)
Action to enable/disable mutually exclusive flag of a group (only one child node may be checked) ...
QList< QgsLayerTreeNode * > selectedNodes(bool skipInternal=false) const
Returns list of selected nodes.
void insertChildNode(int index, QgsLayerTreeNode *node)
Insert existing node at specified position.
QgsLayerTree * rootGroup() const
Returns pointer to the root node of the layer tree. Always a non-null pointer.
QgsLayerTreeGroup * findGroup(const QString &name)
Find group node with specified name.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:391
QString uniqueGroupName(QgsLayerTreeGroup *parentGroup)
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:429
void addChildNode(QgsLayerTreeNode *node)
Append an existing node.
void setExtent(const QgsRectangle &r, bool magnified=false)
Sets the extent of the map canvas.
QAction * actionMoveToTop(QObject *parent=nullptr)
QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
QStringList findLayerIds() const
Find layer IDs used in all layer nodes.
QAction * actionShowFeatureCount(QObject *parent=nullptr)
QAction * actionRenameGroupOrLayer(QObject *parent=nullptr)
Represents a vector layer which manages a vector based data sets.
QAction * actionUncheckAndAllChildren(QObject *parent=nullptr)
Action to uncheck a group and all its children.
QgsLayerTreeLayer * clone() const override
Create a copy of the node. Returns new instance.
QAction * actionShowInOverview(QObject *parent=nullptr)
void setCustomProperty(const QString &key, const QVariant &value)
Sets a custom property for the node. Properties are stored in a map and saved in project file...
Layer tree node points to a map layer.
void moveToTop()
Moves selected layer(s) and/or group(s) to the top of the layer panel or the top of the group if the ...
QgsLayerTreeNode * currentNode() const
Gets current node. May be null.