QGIS API Documentation  2.99.0-Master (08c2e66)
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, SIGNAL( triggered() ), this, SLOT( addGroup() ) );
38  return a;
39 }
40 
42 {
43  QAction* a = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionRemoveLayer.svg" ) ), tr( "&Remove" ), parent );
44  connect( a, SIGNAL( triggered() ), this, SLOT( 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, SIGNAL( triggered() ), this, SLOT( 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, SIGNAL( triggered() ), this, SLOT( 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, SIGNAL( triggered() ), this, SLOT( 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, SIGNAL( triggered() ), this, SLOT( 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, SIGNAL( triggered() ), this, SLOT( zoomToGroup() ) );
96  return a;
97 }
98 
100 {
101  QAction* a = new QAction( tr( "&Move to Top-level" ), parent );
102  connect( a, SIGNAL( triggered() ), this, SLOT( makeTopLevel() ) );
103  return a;
104 }
105 
107 {
108  QAction* a = new QAction( tr( "&Group Selected" ), parent );
109  connect( a, SIGNAL( triggered() ), this, SLOT( 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, SIGNAL( triggered() ), this, SLOT( mutuallyExclusiveGroup() ) );
123  return a;
124 }
125 
127 {
129  if ( !node || !QgsLayerTree::isGroup( node ) || node->isItemVisibilityCheckedRecursive() )
130  return nullptr;
131  QAction* a = new QAction( tr( "Check and all its children (Ctrl-click)" ), parent );
132  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::checkAndAllChildren );
133  return a;
134 }
135 
137 {
139  if ( !node || !QgsLayerTree::isGroup( node ) || node->isItemVisibilityUncheckedRecursive() )
140  return nullptr;
141  QAction* a = new QAction( tr( "Uncheck and all its children (Ctrl-click)" ), parent );
142  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::uncheckAndAllChildren );
143  return a;
144 }
145 
147 {
149  if ( !node || !QgsLayerTree::isLayer( node ) || node->isVisible() )
150  return nullptr;
151  QAction* a = new QAction( tr( "Check and all its parents" ), parent );
152  connect( a, &QAction::triggered, this, &QgsLayerTreeViewDefaultActions::checkAndAllParents );
153  return a;
154 }
155 
156 void QgsLayerTreeViewDefaultActions::checkAndAllChildren()
157 {
159  if ( !node )
160  return;
161  node->setItemVisibilityCheckedRecursive( true );
162 }
163 
164 void QgsLayerTreeViewDefaultActions::uncheckAndAllChildren()
165 {
167  if ( !node )
168  return;
169  node->setItemVisibilityCheckedRecursive( false );
170 }
171 
172 void QgsLayerTreeViewDefaultActions::checkAndAllParents()
173 {
175  if ( !node )
176  return;
178 }
179 
181 {
183  if ( !group )
184  group = mView->layerTreeModel()->rootGroup();
185 
186  QgsLayerTreeGroup* newGroup = group->addGroup( uniqueGroupName( group ) );
187  mView->edit( mView->layerTreeModel()->node2index( newGroup ) );
188 }
189 
191 {
192  Q_FOREACH ( QgsLayerTreeNode* node, mView->selectedNodes( true ) )
193  {
194  // could be more efficient if working directly with ranges instead of individual nodes
195  qobject_cast<QgsLayerTreeGroup*>( node->parent() )->removeChildNode( node );
196  }
197 }
198 
200 {
201  mView->edit( mView->currentIndex() );
202 }
203 
205 {
207  if ( !node )
208  return;
209  int newValue = node->customProperty( QStringLiteral( "overview" ), 0 ).toInt();
210  Q_FOREACH ( QgsLayerTreeLayer* l, mView->selectedLayerNodes() )
211  l->setCustomProperty( QStringLiteral( "overview" ), newValue ? 0 : 1 );
212 }
213 
215 {
217  if ( !QgsLayerTree::isLayer( node ) )
218  return;
219 
220  int newValue = node->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toInt();
221  Q_FOREACH ( QgsLayerTreeLayer* l, mView->selectedLayerNodes() )
222  l->setCustomProperty( QStringLiteral( "showFeatureCount" ), newValue ? 0 : 1 );
223 }
224 
225 
227 {
228  QgsMapLayer* layer = mView->currentLayer();
229  if ( !layer )
230  return;
231 
232  QList<QgsMapLayer*> layers;
233  layers << layer;
234  zoomToLayers( canvas, layers );
235 }
236 
238 {
239  QgsLayerTreeGroup* groupNode = mView->currentGroupNode();
240  if ( !groupNode )
241  return;
242 
243  QList<QgsMapLayer*> layers;
244  Q_FOREACH ( const QString& layerId, groupNode->findLayerIds() )
245  layers << QgsProject::instance()->mapLayer( layerId );
246 
247  zoomToLayers( canvas, layers );
248 }
249 
251 {
252  QAction* s = qobject_cast<QAction*>( sender() );
253  QgsMapCanvas* canvas = reinterpret_cast<QgsMapCanvas*>( s->data().value<void*>() );
254  QApplication::setOverrideCursor( Qt::WaitCursor );
255  zoomToLayer( canvas );
256  QApplication::restoreOverrideCursor();
257 }
258 
260 {
261  QAction* s = qobject_cast<QAction*>( sender() );
262  QgsMapCanvas* canvas = reinterpret_cast<QgsMapCanvas*>( s->data().value<void*>() );
263  QApplication::setOverrideCursor( Qt::WaitCursor );
264  zoomToGroup( canvas );
265  QApplication::restoreOverrideCursor();
266 }
267 
268 
269 void QgsLayerTreeViewDefaultActions::zoomToLayers( QgsMapCanvas* canvas, const QList<QgsMapLayer*>& layers )
270 {
271  QgsRectangle extent;
272  extent.setMinimal();
273 
274  for ( int i = 0; i < layers.size(); ++i )
275  {
276  QgsMapLayer* layer = layers.at( i );
277  QgsRectangle layerExtent = layer->extent();
278 
279  QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer*>( layer );
280  if ( vLayer )
281  {
282  if ( vLayer->geometryType() == QgsWkbTypes::NullGeometry )
283  continue;
284 
285  if ( layerExtent.isEmpty() )
286  {
287  vLayer->updateExtents();
288  layerExtent = vLayer->extent();
289  }
290  }
291 
292  if ( layerExtent.isNull() )
293  continue;
294 
295  //transform extent if otf-projection is on
296  if ( canvas->hasCrsTransformEnabled() )
297  layerExtent = canvas->mapSettings().layerExtentToOutputExtent( layer, layerExtent );
298 
299  extent.combineExtentWith( layerExtent );
300  }
301 
302  if ( extent.isNull() )
303  return;
304 
305  // Increase bounding box with 5%, so that layer is a bit inside the borders
306  extent.scale( 1.05 );
307 
308  //zoom to bounding box
309  canvas->setExtent( extent );
310  canvas->refresh();
311 }
312 
313 
315 {
316  QString prefix = parentGroup == mView->layerTreeModel()->rootGroup() ? "group" : "sub-group";
317  QString newName = prefix + '1';
318  for ( int i = 2; parentGroup->findGroup( newName ); ++i )
319  newName = prefix + QString::number( i );
320  return newName;
321 }
322 
323 
325 {
326  Q_FOREACH ( QgsLayerTreeLayer* l, mView->selectedLayerNodes() )
327  {
328  QgsLayerTreeGroup* rootGroup = mView->layerTreeModel()->rootGroup();
329  QgsLayerTreeGroup* parentGroup = qobject_cast<QgsLayerTreeGroup*>( l->parent() );
330  if ( !parentGroup || parentGroup == rootGroup )
331  continue;
332  QgsLayerTreeLayer* clonedLayer = l->clone();
333  rootGroup->addChildNode( clonedLayer );
334  parentGroup->removeChildNode( l );
335  }
336 }
337 
338 
340 {
341  QList<QgsLayerTreeNode*> nodes = mView->selectedNodes( true );
342  if ( nodes.count() < 2 || ! QgsLayerTree::isGroup( nodes[0]->parent() ) )
343  return;
344 
345  QgsLayerTreeGroup* parentGroup = QgsLayerTree::toGroup( nodes[0]->parent() );
346  int insertIdx = parentGroup->children().indexOf( nodes[0] );
347 
348  QgsLayerTreeGroup* newGroup = new QgsLayerTreeGroup( uniqueGroupName( parentGroup ) );
349  Q_FOREACH ( QgsLayerTreeNode* node, nodes )
350  newGroup->addChildNode( node->clone() );
351 
352  parentGroup->insertChildNode( insertIdx, newGroup );
353 
354  Q_FOREACH ( QgsLayerTreeNode* node, nodes )
355  {
356  QgsLayerTreeGroup* group = qobject_cast<QgsLayerTreeGroup*>( node->parent() );
357  if ( group )
358  group->removeChildNode( node );
359  }
360 
361  mView->setCurrentIndex( mView->layerTreeModel()->node2index( newGroup ) );
362 }
363 
365 {
367  if ( !node || !QgsLayerTree::isGroup( node ) )
368  return;
369 
370  QgsLayerTree::toGroup( node )->setIsMutuallyExclusive( !QgsLayerTree::toGroup( node )->isMutuallyExclusive() );
371 }
Layer tree group node serves as a container for layers and further groups.
QgsLayerTreeModel * layerTreeModel() const
Get access to the model casted to QgsLayerTreeModel.
A rectangle specified with double values.
Definition: qgsrectangle.h:36
Base class for all map layer types.
Definition: qgsmaplayer.h:52
The QgsLayerTreeView class extends QTreeView and provides some additional functionality when working ...
bool isEmpty() const
test if rectangle is empty.
QgsLayerTreeGroup * addGroup(const QString &name)
Append a new group node with given name. Newly created node is owned by this group.
QgsMapLayer * currentLayer() const
Get currently selected layer. May be null.
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
void setIsMutuallyExclusive(bool enabled, int initialChildIndex=-1)
Set whether the group is mutually exclusive (only one child can be checked at a time).
QgsLayerTreeGroup * rootGroup() const
Return pointer to the root node of the layer tree. Always a non-null pointer.
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...
QAction * actionZoomToGroup(QgsMapCanvas *canvas, QObject *parent=nullptr)
virtual QgsLayerTreeNode * clone() const =0
Create a copy of the node. Returns new instance.
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 QgsPoint *c=nullptr)
Scale the rectangle around its center point.
bool isNull() const
test if the rectangle is null (all coordinates zero or after call to setMinimal()).
bool hasCrsTransformEnabled()
A simple helper method to find out if on the fly projections are enabled or not.
QAction * actionGroupSelected(QObject *parent=nullptr)
QgsLayerTreeNode * currentNode() const
Get current node. May be null.
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
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. The node will be deleted.
bool isItemVisibilityCheckedRecursive() const
Return whether this node is checked and all its children.
QList< QgsLayerTreeNode * > selectedNodes(bool skipInternal=false) const
Return list of selected nodes.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:72
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
virtual void updateExtents()
Update the extents for the layer.
bool isVisible() const
Returns whether a node is really visible (ie checked and all its ancestors checked as well) ...
virtual void setItemVisibilityCheckedRecursive(bool checked)
Check or uncheck a node and all its children (taking into account exclusion rules) ...
QgsRectangle extent() const override
Return the extent of the layer.
virtual QgsRectangle extent() const
Returns the extent of the layer.
QAction * actionMakeTopLevel(QObject *parent=nullptr)
void mutuallyExclusiveGroup()
Slot to enable/disable mutually exclusive group flag.
QgsLayerTreeGroup * currentGroupNode() const
Get current group node. If a layer is current node, the function will return parent group...
QgsLayerTreeNode * parent()
Get pointer to the parent. If parent is a null pointer, the node is a root node.
QAction * actionCheckAndAllParents(QObject *parent=nullptr)
Action to check a group and all its parents.
This class is a base class for nodes in a layer tree.
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
QList< QgsLayerTreeLayer * > selectedLayerNodes() const
Return list of selected nodes filtered to just layer nodes.
void setItemVisibilityCheckedParentRecursive(bool checked)
Check or uncheck a node and all its parents.
QAction * actionZoomToLayer(QgsMapCanvas *canvas, QObject *parent=nullptr)
void combineExtentWith(const QgsRectangle &rect)
expand the rectangle so that covers both the original rectangle and the given rectangle ...
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...
QAction * actionMutuallyExclusiveGroup(QObject *parent=nullptr)
Action to enable/disable mutually exclusive flag of a group (only one child node may be checked) ...
void insertChildNode(int index, QgsLayerTreeNode *node)
Insert existing node at specified position. The node must not have a parent yet. The node will be own...
QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
QgsRectangle layerExtentToOutputExtent(QgsMapLayer *layer, QgsRectangle extent) const
transform bounding box from layer&#39;s CRS to output CRS
QStringList findLayerIds() const
Find layer IDs used in all layer nodes. Searches recursively the whole sub-tree.
QgsLayerTreeGroup * findGroup(const QString &name)
Find group node with specified name. Searches recursively the whole sub-tree.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:355
QString uniqueGroupName(QgsLayerTreeGroup *parentGroup)
void zoomToLayers(QgsMapCanvas *canvas, const QList< QgsMapLayer * > &layers)
void addChildNode(QgsLayerTreeNode *node)
Append an existing node. The node must not have a parent yet. The node will be owned by this group...
void setExtent(const QgsRectangle &r, bool magnified=false)
Set the extent of the map canvas.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
QAction * actionShowFeatureCount(QObject *parent=nullptr)
QAction * actionRenameGroupOrLayer(QObject *parent=nullptr)
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
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.
bool isItemVisibilityUncheckedRecursive() const
Return whether this node is unchecked and all its children.