QGIS API Documentation  2.99.0-Master (19b062c)
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( 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 {
63  QAction *a = new QAction( tr( "Re&name" ), parent );
64  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::renameGroupOrLayer );
65  return a;
66 }
67 
69 {
71  if ( !node )
72  return nullptr;
73 
74  QAction *a = new QAction( tr( "Show Feature Count" ), parent );
75  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::showFeatureCount );
76  a->setCheckable( true );
77  a->setChecked( node->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toInt() );
78  return a;
79 }
80 
82 {
83  QAction *a = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomToLayer.svg" ) ),
84  tr( "&Zoom to Layer" ), parent );
85  a->setData( QVariant::fromValue( reinterpret_cast<void *>( canvas ) ) );
86  connect( a, &QAction::triggered, this, static_cast<void ( QgsLayerTreeViewDefaultActions::* )()>( &QgsLayerTreeViewDefaultActions::zoomToLayer ) );
87  return a;
88 }
89 
91 {
92  QAction *a = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomToLayer.svg" ) ),
93  tr( "&Zoom to Group" ), parent );
94  a->setData( QVariant::fromValue( reinterpret_cast<void *>( canvas ) ) );
95  connect( a, &QAction::triggered, this, static_cast<void ( QgsLayerTreeViewDefaultActions::* )()>( &QgsLayerTreeViewDefaultActions::zoomToGroup ) );
96  return a;
97 }
98 
100 {
101  QAction *a = new QAction( tr( "&Move to Top-level" ), parent );
102  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::makeTopLevel );
103  return a;
104 }
105 
107 {
108  QAction *a = new QAction( tr( "&Group Selected" ), parent );
109  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::groupSelected );
110  return a;
111 }
112 
114 {
116  if ( !node || !QgsLayerTree::isGroup( node ) )
117  return nullptr;
118 
119  QAction *a = new QAction( tr( "Mutually Exclusive Group" ), parent );
120  a->setCheckable( true );
121  a->setChecked( QgsLayerTree::toGroup( node )->isMutuallyExclusive() );
122  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::mutuallyExclusiveGroup );
123  return a;
124 }
125 
127 {
129  if ( !node || !QgsLayerTree::isGroup( node ) || node->isItemVisibilityCheckedRecursive() )
130  return nullptr;
131 #ifdef Q_OS_MACX
132  QAction *a = new QAction( tr( "Check and all its children (⌘-click)" ), parent );
133 #else
134  QAction *a = new QAction( tr( "Check and all its children (Ctrl-click)" ), parent );
135 #endif
136  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::checkAndAllChildren );
137  return a;
138 }
139 
141 {
143  if ( !node || !QgsLayerTree::isGroup( node ) || node->isItemVisibilityUncheckedRecursive() )
144  return nullptr;
145 #ifdef Q_OS_MACX
146  QAction *a = new QAction( tr( "Uncheck and all its children (⌘-click)" ), parent );
147 #else
148  QAction *a = new QAction( tr( "Uncheck and all its children (Ctrl-click)" ), parent );
149 #endif
150  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::uncheckAndAllChildren );
151  return a;
152 }
153 
155 {
157  if ( !node || !QgsLayerTree::isLayer( node ) || node->isVisible() )
158  return nullptr;
159  QAction *a = new QAction( tr( "Check and all its parents" ), parent );
160  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::checkAndAllParents );
161  return a;
162 }
163 
164 void QgsLayerTreeViewDefaultActions::checkAndAllChildren()
165 {
167  if ( !node )
168  return;
169  node->setItemVisibilityCheckedRecursive( true );
170 }
171 
172 void QgsLayerTreeViewDefaultActions::uncheckAndAllChildren()
173 {
175  if ( !node )
176  return;
177  node->setItemVisibilityCheckedRecursive( false );
178 }
179 
180 void QgsLayerTreeViewDefaultActions::checkAndAllParents()
181 {
183  if ( !node )
184  return;
186 }
187 
189 {
191  if ( !group )
192  group = mView->layerTreeModel()->rootGroup();
193 
194  QgsLayerTreeGroup *newGroup = group->addGroup( uniqueGroupName( group ) );
195  mView->edit( mView->layerTreeModel()->node2index( newGroup ) );
196 }
197 
199 {
200  Q_FOREACH ( QgsLayerTreeNode *node, mView->selectedNodes( true ) )
201  {
202  // could be more efficient if working directly with ranges instead of individual nodes
203  qobject_cast<QgsLayerTreeGroup *>( node->parent() )->removeChildNode( node );
204  }
205 }
206 
208 {
209  mView->edit( mView->currentIndex() );
210 }
211 
213 {
215  if ( !node )
216  return;
217  int newValue = node->customProperty( QStringLiteral( "overview" ), 0 ).toInt();
218  Q_FOREACH ( QgsLayerTreeLayer *l, mView->selectedLayerNodes() )
219  l->setCustomProperty( QStringLiteral( "overview" ), newValue ? 0 : 1 );
220 }
221 
223 {
225  if ( !QgsLayerTree::isLayer( node ) )
226  return;
227 
228  int newValue = node->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toInt();
229  Q_FOREACH ( QgsLayerTreeLayer *l, mView->selectedLayerNodes() )
230  l->setCustomProperty( QStringLiteral( "showFeatureCount" ), newValue ? 0 : 1 );
231 }
232 
233 
235 {
236  QgsMapLayer *layer = mView->currentLayer();
237  if ( !layer )
238  return;
239 
240  QList<QgsMapLayer *> layers;
241  layers << layer;
242  zoomToLayers( canvas, layers );
243 }
244 
246 {
247  QgsLayerTreeGroup *groupNode = mView->currentGroupNode();
248  if ( !groupNode )
249  return;
250 
251  QList<QgsMapLayer *> layers;
252  Q_FOREACH ( const QString &layerId, groupNode->findLayerIds() )
253  layers << QgsProject::instance()->mapLayer( layerId );
254 
255  zoomToLayers( canvas, layers );
256 }
257 
259 {
260  QAction *s = qobject_cast<QAction *>( sender() );
261  QgsMapCanvas *canvas = reinterpret_cast<QgsMapCanvas *>( s->data().value<void *>() );
262  QApplication::setOverrideCursor( Qt::WaitCursor );
263  zoomToLayer( canvas );
264  QApplication::restoreOverrideCursor();
265 }
266 
268 {
269  QAction *s = qobject_cast<QAction *>( sender() );
270  QgsMapCanvas *canvas = reinterpret_cast<QgsMapCanvas *>( s->data().value<void *>() );
271  QApplication::setOverrideCursor( Qt::WaitCursor );
272  zoomToGroup( canvas );
273  QApplication::restoreOverrideCursor();
274 }
275 
276 
277 void QgsLayerTreeViewDefaultActions::zoomToLayers( QgsMapCanvas *canvas, const QList<QgsMapLayer *> &layers )
278 {
279  QgsRectangle extent;
280  extent.setMinimal();
281 
282  for ( int i = 0; i < layers.size(); ++i )
283  {
284  QgsMapLayer *layer = layers.at( i );
285  QgsRectangle layerExtent = layer->extent();
286 
287  QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( layer );
288  if ( vLayer )
289  {
290  if ( vLayer->geometryType() == QgsWkbTypes::NullGeometry )
291  continue;
292 
293  if ( layerExtent.isEmpty() )
294  {
295  vLayer->updateExtents();
296  layerExtent = vLayer->extent();
297  }
298  }
299 
300  if ( layerExtent.isNull() )
301  continue;
302 
303  //transform extent
304  layerExtent = canvas->mapSettings().layerExtentToOutputExtent( layer, layerExtent );
305 
306  extent.combineExtentWith( layerExtent );
307  }
308 
309  if ( extent.isNull() )
310  return;
311 
312  // Increase bounding box with 5%, so that layer is a bit inside the borders
313  extent.scale( 1.05 );
314 
315  //zoom to bounding box
316  canvas->setExtent( extent );
317  canvas->refresh();
318 }
319 
320 
322 {
323  QString prefix = parentGroup == mView->layerTreeModel()->rootGroup() ? "group" : "sub-group";
324  QString newName = prefix + '1';
325  for ( int i = 2; parentGroup->findGroup( newName ); ++i )
326  newName = prefix + QString::number( i );
327  return newName;
328 }
329 
330 
332 {
333  Q_FOREACH ( QgsLayerTreeLayer *l, mView->selectedLayerNodes() )
334  {
335  QgsLayerTreeGroup *rootGroup = mView->layerTreeModel()->rootGroup();
336  QgsLayerTreeGroup *parentGroup = qobject_cast<QgsLayerTreeGroup *>( l->parent() );
337  if ( !parentGroup || parentGroup == rootGroup )
338  continue;
339  QgsLayerTreeLayer *clonedLayer = l->clone();
340  rootGroup->addChildNode( clonedLayer );
341  parentGroup->removeChildNode( l );
342  }
343 }
344 
345 
347 {
348  QList<QgsLayerTreeNode *> nodes = mView->selectedNodes( true );
349  if ( nodes.count() < 2 || ! QgsLayerTree::isGroup( nodes[0]->parent() ) )
350  return;
351 
352  QgsLayerTreeGroup *parentGroup = QgsLayerTree::toGroup( nodes[0]->parent() );
353  int insertIdx = parentGroup->children().indexOf( nodes[0] );
354 
355  QgsLayerTreeGroup *newGroup = new QgsLayerTreeGroup( uniqueGroupName( parentGroup ) );
356  Q_FOREACH ( QgsLayerTreeNode *node, nodes )
357  newGroup->addChildNode( node->clone() );
358 
359  parentGroup->insertChildNode( insertIdx, newGroup );
360 
361  Q_FOREACH ( QgsLayerTreeNode *node, nodes )
362  {
363  QgsLayerTreeGroup *group = qobject_cast<QgsLayerTreeGroup *>( node->parent() );
364  if ( group )
365  group->removeChildNode( node );
366  }
367 
368  mView->setCurrentIndex( mView->layerTreeModel()->node2index( newGroup ) );
369 }
370 
372 {
374  if ( !node || !QgsLayerTree::isGroup( node ) )
375  return;
376 
377  QgsLayerTree::toGroup( node )->setIsMutuallyExclusive( !QgsLayerTree::toGroup( node )->isMutuallyExclusive() );
378 }
Layer tree group node serves as a container for layers and further groups.
A rectangle specified with double values.
Definition: qgsrectangle.h:39
Base class for all map layer types.
Definition: qgsmaplayer.h:56
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.
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:43
bool isItemVisibilityUncheckedRecursive() const
Return 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.
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.
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
Get currently selected layer. May be null.
QModelIndex node2index(QgsLayerTreeNode *node) const
Return index for a given node. If the node does not belong to the layer tree, the result is undefined...
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
Return list of selected nodes filtered to just layer nodes.
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()
Get 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.
QAction * actionMakeTopLevel(QObject *parent=nullptr)
void mutuallyExclusiveGroup()
Slot to enable/disable mutually exclusive group flag.
QgsLayerTreeNode * parent()
Get pointer to the parent. If parent is a null pointer, the node is a root node.
QgsLayerTreeGroup * currentGroupNode() const
Get 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
Get access to the model casted to QgsLayerTreeModel.
void setItemVisibilityCheckedParentRecursive(bool checked)
Check or uncheck a node and all its parents.
bool isItemVisibilityCheckedRecursive() const
Return whether this node is checked and all its children.
QAction * actionZoomToLayer(QgsMapCanvas *canvas, QObject *parent=nullptr)
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
void combineExtentWith(const QgsRectangle &rect)
Expand the rectangle so that covers both the original rectangle and the given rectangle.
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
Return list of selected nodes.
void insertChildNode(int index, QgsLayerTreeNode *node)
Insert existing node at specified position.
QgsLayerTree * rootGroup() const
Return 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:383
QString uniqueGroupName(QgsLayerTreeGroup *parentGroup)
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
void addChildNode(QgsLayerTreeNode *node)
Append an existing node.
void setExtent(const QgsRectangle &r, bool magnified=false)
Set the extent of the map canvas.
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.
virtual 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)
Set 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.
QgsLayerTreeNode * currentNode() const
Get current node. May be null.