Skip to content

Commit 6a5b752

Browse files
committedMay 21, 2014
Support for default actions in layer tree view
1 parent c3315c4 commit 6a5b752

File tree

5 files changed

+245
-67
lines changed

5 files changed

+245
-67
lines changed
 

‎src/gui/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ layertree/qgscustomlayerorderwidget.cpp
6262
layertree/qgslayertreemapcanvasbridge.cpp
6363
layertree/qgslayertreemodel.cpp
6464
layertree/qgslayertreeview.cpp
65+
layertree/qgslayertreeviewdefaultactions.cpp
6566

6667
qgisgui.cpp
6768
qgisinterface.cpp
@@ -223,6 +224,7 @@ layertree/qgscustomlayerorderwidget.h
223224
layertree/qgslayertreemapcanvasbridge.h
224225
layertree/qgslayertreemodel.h
225226
layertree/qgslayertreeview.h
227+
layertree/qgslayertreeviewdefaultactions.h
226228

227229
qgisinterface.h
228230
qgsattributedialog.h

‎src/gui/layertree/qgslayertreeview.cpp

Lines changed: 39 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
#include "qgslayertreemodel.h"
44
#include "qgslayertreenode.h"
5+
#include "qgslayertreeviewdefaultactions.h"
56

67
#include <QMenu>
78
#include <QContextMenuEvent>
89

910
QgsLayerTreeView::QgsLayerTreeView(QWidget *parent)
1011
: QTreeView(parent)
1112
, mCurrentLayer(0)
13+
, mDefaultActions(0)
1214
{
1315
setHeaderHidden(true);
1416

@@ -36,11 +38,18 @@ void QgsLayerTreeView::setModel(QAbstractItemModel* model)
3638
updateExpandedStateFromNode(layerTreeModel()->rootGroup());
3739
}
3840

39-
QgsLayerTreeModel *QgsLayerTreeView::layerTreeModel()
41+
QgsLayerTreeModel *QgsLayerTreeView::layerTreeModel() const
4042
{
4143
return qobject_cast<QgsLayerTreeModel*>(model());
4244
}
4345

46+
QgsLayerTreeViewDefaultActions* QgsLayerTreeView::defaultActions()
47+
{
48+
if (!mDefaultActions)
49+
mDefaultActions = new QgsLayerTreeViewDefaultActions(this);
50+
return mDefaultActions;
51+
}
52+
4453
QgsMapLayer* QgsLayerTreeView::currentLayer() const
4554
{
4655
return mCurrentLayer;
@@ -63,7 +72,9 @@ void QgsLayerTreeView::contextMenuEvent(QContextMenuEvent *event)
6372
QModelIndex idx = indexAt(event->pos());
6473
if (!idx.isValid())
6574
{
66-
menu.addAction(create_addGroup(&menu));
75+
setCurrentIndex(QModelIndex());
76+
77+
menu.addAction( defaultActions()->actionAddGroup(&menu) );
6778
}
6879
else
6980
{
@@ -72,70 +83,20 @@ void QgsLayerTreeView::contextMenuEvent(QContextMenuEvent *event)
7283
return; // probably a symbology item
7384

7485
if (node->nodeType() == QgsLayerTreeNode::NodeGroup)
75-
menu.addAction(create_addGroup(&menu, node));
86+
menu.addAction( defaultActions()->actionAddGroup(&menu) );
7687
else if (node->nodeType() == QgsLayerTreeNode::NodeLayer)
77-
menu.addAction(create_showInOverview(&menu, node)); // TODO: should be custom action
88+
{
89+
// TODO menu.addAction( defaultActions()->actionZoomToLayer(canvas, &menu) );
90+
menu.addAction( defaultActions()->actionShowInOverview(&menu) ); // TODO: should be custom action
91+
}
7892

79-
menu.addAction(create_removeGroupOrLayer(&menu, node));
93+
menu.addAction( defaultActions()->actionRemoveGroupOrLayer(&menu) );
94+
menu.addAction( defaultActions()->actionRenameGroupOrLayer(&menu) );
8095
}
8196

8297
menu.exec(mapToGlobal(event->pos()));
8398
}
8499

85-
QAction *QgsLayerTreeView::create_addGroup(QObject* parent, QgsLayerTreeNode* parentNode)
86-
{
87-
QAction* a = new QAction(tr("Add Group"), parent);
88-
connect(a, SIGNAL(triggered()), this, SLOT(addGroup()));
89-
a->setData(QVariant::fromValue((QObject*)parentNode));
90-
return a;
91-
}
92-
93-
QAction *QgsLayerTreeView::create_removeGroupOrLayer(QObject *parent, QgsLayerTreeNode *parentNode)
94-
{
95-
QAction* a = new QAction(tr("Remove"), parent);
96-
connect(a, SIGNAL(triggered()), this, SLOT(removeGroupOrLayer()));
97-
a->setData(QVariant::fromValue((QObject*)parentNode));
98-
return a;
99-
}
100-
101-
QAction* QgsLayerTreeView::create_showInOverview(QObject* parent, QgsLayerTreeNode* parentNode)
102-
{
103-
QAction* a = new QAction(tr("Show in overview"), parent);
104-
connect(a, SIGNAL(triggered()), this, SLOT(showInOverview()));
105-
a->setData(QVariant::fromValue((QObject*)parentNode));
106-
a->setCheckable(true);
107-
a->setChecked(parentNode->customProperty("overview", 0).toInt());
108-
return a;
109-
}
110-
111-
void QgsLayerTreeView::addGroup()
112-
{
113-
QVariant v = qobject_cast<QAction*>(sender())->data();
114-
QgsLayerTreeGroup* group = qobject_cast<QgsLayerTreeGroup*>(v.value<QObject*>());
115-
if (!group)
116-
group = layerTreeModel()->rootGroup();
117-
118-
group->addGroup("group");
119-
}
120-
121-
void QgsLayerTreeView::removeGroupOrLayer()
122-
{
123-
QList<QgsLayerTreeNode*> nodes = layerTreeModel()->indexes2nodes(selectionModel()->selectedIndexes(), true);
124-
foreach (QgsLayerTreeNode* node, nodes)
125-
{
126-
// could be more efficient if working directly with ranges instead of individual nodes
127-
qobject_cast<QgsLayerTreeGroup*>(node->parent())->removeChildNode(node);
128-
}
129-
}
130-
131-
void QgsLayerTreeView::showInOverview()
132-
{
133-
QVariant v = qobject_cast<QAction*>(sender())->data();
134-
QgsLayerTreeNode* node = qobject_cast<QgsLayerTreeNode*>(v.value<QObject*>());
135-
Q_ASSERT(node);
136-
137-
node->setCustomProperty("overview", node->customProperty("overview", 0).toInt() ? 0 : 1);
138-
}
139100

140101
void QgsLayerTreeView::modelRowsInserted(QModelIndex index, int start, int end)
141102
{
@@ -182,3 +143,22 @@ void QgsLayerTreeView::updateExpandedStateFromNode(QgsLayerTreeNode* node)
182143
foreach (QgsLayerTreeNode* child, node->children())
183144
updateExpandedStateFromNode(child);
184145
}
146+
147+
QgsLayerTreeNode* QgsLayerTreeView::currentNode() const
148+
{
149+
return layerTreeModel()->index2node(selectionModel()->currentIndex());
150+
}
151+
152+
QgsLayerTreeGroup* QgsLayerTreeView::currentGroupNode() const
153+
{
154+
// TODO: also handle if a layer / symbology is selected within a group?
155+
QgsLayerTreeNode* node = currentNode();
156+
if (node && node->nodeType() == QgsLayerTreeNode::NodeGroup)
157+
return static_cast<QgsLayerTreeGroup*>(node);
158+
return 0;
159+
}
160+
161+
QList<QgsLayerTreeNode*> QgsLayerTreeView::selectedNodes(bool skipInternal) const
162+
{
163+
return layerTreeModel()->indexes2nodes(selectionModel()->selectedIndexes(), skipInternal);
164+
}

‎src/gui/layertree/qgslayertreeview.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33

44
#include <QTreeView>
55

6+
class QgsLayerTreeGroup;
67
class QgsLayerTreeModel;
78
class QgsLayerTreeNode;
9+
class QgsLayerTreeViewDefaultActions;
810
class QgsMapLayer;
911

1012
class GUI_EXPORT QgsLayerTreeView : public QTreeView
@@ -15,18 +17,21 @@ class GUI_EXPORT QgsLayerTreeView : public QTreeView
1517

1618
virtual void setModel(QAbstractItemModel* model);
1719

18-
QgsLayerTreeModel* layerTreeModel();
20+
QgsLayerTreeModel* layerTreeModel() const;
21+
22+
QgsLayerTreeViewDefaultActions* defaultActions();
1923

2024
QgsMapLayer* currentLayer() const;
2125
void setCurrentLayer(QgsMapLayer* layer);
2226

27+
QgsLayerTreeNode* currentNode() const;
28+
QgsLayerTreeGroup* currentGroupNode() const;
29+
30+
QList<QgsLayerTreeNode*> selectedNodes(bool skipInternal = false) const;
31+
2332
protected:
2433
void contextMenuEvent(QContextMenuEvent* event);
2534

26-
QAction* create_addGroup(QObject* parent, QgsLayerTreeNode* parentNode = 0);
27-
QAction* create_removeGroupOrLayer(QObject* parent, QgsLayerTreeNode* parentNode);
28-
QAction* create_showInOverview(QObject* parent, QgsLayerTreeNode* parentNode);
29-
3035
void updateExpandedStateFromNode(QgsLayerTreeNode* node);
3136

3237
signals:
@@ -35,9 +40,6 @@ class GUI_EXPORT QgsLayerTreeView : public QTreeView
3540
public slots:
3641

3742
protected slots:
38-
void addGroup();
39-
void removeGroupOrLayer();
40-
void showInOverview();
4143

4244
void modelRowsInserted(QModelIndex index, int start, int end);
4345

@@ -47,6 +49,9 @@ protected slots:
4749

4850
protected:
4951
QgsMapLayer* mCurrentLayer;
52+
53+
QgsLayerTreeViewDefaultActions* mDefaultActions;
5054
};
5155

56+
5257
#endif // QGSLAYERTREEVIEW_H
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#include "qgslayertreeviewdefaultactions.h"
2+
3+
#include "qgsapplication.h"
4+
#include "qgslayertreemodel.h"
5+
#include "qgslayertreenode.h"
6+
#include "qgslayertreeview.h"
7+
#include "qgsmapcanvas.h"
8+
#include "qgsvectorlayer.h"
9+
10+
#include <QAction>
11+
12+
QgsLayerTreeViewDefaultActions::QgsLayerTreeViewDefaultActions(QgsLayerTreeView* view)
13+
: QObject(view)
14+
, mView(view)
15+
{
16+
}
17+
18+
QAction* QgsLayerTreeViewDefaultActions::actionAddGroup(QObject* parent)
19+
{
20+
QAction* a = new QAction(tr("&Add Group"), parent);
21+
connect(a, SIGNAL(triggered()), this, SLOT(addGroup()));
22+
return a;
23+
}
24+
25+
QAction* QgsLayerTreeViewDefaultActions::actionRemoveGroupOrLayer(QObject* parent)
26+
{
27+
QAction* a = new QAction(tr("Remove"), parent);
28+
connect(a, SIGNAL(triggered()), this, SLOT(removeGroupOrLayer()));
29+
return a;
30+
}
31+
32+
QAction* QgsLayerTreeViewDefaultActions::actionShowInOverview(QObject* parent)
33+
{
34+
QgsLayerTreeNode* node = mView->currentNode();
35+
if (!node)
36+
return 0;
37+
38+
QAction* a = new QAction(tr("Show in overview"), parent);
39+
connect(a, SIGNAL(triggered()), this, SLOT(showInOverview()));
40+
a->setCheckable(true);
41+
a->setChecked(node->customProperty("overview", 0).toInt());
42+
return a;
43+
}
44+
45+
QAction* QgsLayerTreeViewDefaultActions::actionRenameGroupOrLayer(QObject* parent)
46+
{
47+
QAction* a = new QAction(tr("Re&name"), parent);
48+
connect(a, SIGNAL(triggered()), this, SLOT(renameGroupOrLayer()));
49+
return a;
50+
}
51+
52+
QAction* QgsLayerTreeViewDefaultActions::actionZoomToLayer(QgsMapCanvas* canvas, QObject* parent)
53+
{
54+
QAction* a = new QAction(QgsApplication::getThemeIcon( "/mActionZoomToLayer.svg" ),
55+
tr("&Zoom to Layer Extent"), parent);
56+
a->setData(QVariant::fromValue(reinterpret_cast<void*>(canvas)));
57+
connect(a, SIGNAL(triggered()), this, SLOT(zoomToLayer()));
58+
return a;
59+
}
60+
61+
void QgsLayerTreeViewDefaultActions::addGroup()
62+
{
63+
QgsLayerTreeGroup* group = mView->currentGroupNode();
64+
QString prefix = group == mView->layerTreeModel()->rootGroup() ? "group" : "sub-group";
65+
66+
QString newName = prefix + "1";
67+
for ( int i = 2; group->findGroup(newName); ++i)
68+
newName = prefix + QString::number(i);
69+
70+
QgsLayerTreeGroup* newGroup = group->addGroup(newName);
71+
mView->edit( mView->layerTreeModel()->node2index(newGroup) );
72+
}
73+
74+
void QgsLayerTreeViewDefaultActions::removeGroupOrLayer()
75+
{
76+
foreach (QgsLayerTreeNode* node, mView->selectedNodes(true))
77+
{
78+
// could be more efficient if working directly with ranges instead of individual nodes
79+
qobject_cast<QgsLayerTreeGroup*>(node->parent())->removeChildNode(node);
80+
}
81+
}
82+
83+
void QgsLayerTreeViewDefaultActions::renameGroupOrLayer()
84+
{
85+
/*QgsLayerTreeNode* node = mView->currentNode();
86+
if (!node)
87+
return;*/
88+
89+
mView->edit(mView->currentIndex());
90+
}
91+
92+
void QgsLayerTreeViewDefaultActions::showInOverview()
93+
{
94+
QgsLayerTreeNode* node = mView->currentNode();
95+
if (!node)
96+
return;
97+
98+
node->setCustomProperty("overview", node->customProperty("overview", 0).toInt() ? 0 : 1);
99+
}
100+
101+
void QgsLayerTreeViewDefaultActions::zoomToLayer()
102+
{
103+
QAction* s = qobject_cast<QAction*>(sender());
104+
QgsMapCanvas* canvas = reinterpret_cast<QgsMapCanvas*>(s->data().value<void*>());
105+
106+
QgsMapLayer* layer = mView->currentLayer();
107+
if (!layer)
108+
return;
109+
110+
QList<QgsMapLayer*> layers;
111+
layers << layer;
112+
zoomToLayers(canvas, layers);
113+
}
114+
115+
116+
void QgsLayerTreeViewDefaultActions::zoomToLayers(QgsMapCanvas* canvas, const QList<QgsMapLayer*>& layers)
117+
{
118+
QgsRectangle extent;
119+
120+
for ( int i = 0; i < layers.size(); ++i )
121+
{
122+
QgsMapLayer* layer = layers.at( i );
123+
QgsRectangle layerExtent = layer->extent();
124+
125+
QgsVectorLayer* vLayer = qobject_cast<QgsVectorLayer*>( layer );
126+
127+
if ( layerExtent.isEmpty() && layer->type() == QgsMapLayer::VectorLayer )
128+
{
129+
qobject_cast<QgsVectorLayer*>( layer )->updateExtents();
130+
layerExtent = vLayer->extent();
131+
}
132+
133+
//transform extent if otf-projection is on
134+
if ( canvas->hasCrsTransformEnabled() )
135+
layerExtent = canvas->mapSettings().layerExtentToOutputExtent( layer, layerExtent );
136+
137+
if ( i == 0 )
138+
extent = layerExtent;
139+
else
140+
extent.combineExtentWith( &layerExtent );
141+
}
142+
143+
if ( extent.isEmpty() )
144+
return;
145+
146+
// Increase bounding box with 5%, so that layer is a bit inside the borders
147+
extent.scale( 1.05 );
148+
149+
//zoom to bounding box
150+
canvas->setExtent( extent );
151+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#ifndef QGSLAYERTREEVIEWDEFAULTACTIONS_H
2+
#define QGSLAYERTREEVIEWDEFAULTACTIONS_H
3+
4+
#include <QObject>
5+
6+
class QAction;
7+
8+
class QgsLayerTreeView;
9+
class QgsMapCanvas;
10+
class QgsMapLayer;
11+
12+
class GUI_EXPORT QgsLayerTreeViewDefaultActions : public QObject
13+
{
14+
Q_OBJECT
15+
public:
16+
QgsLayerTreeViewDefaultActions(QgsLayerTreeView* view);
17+
18+
QAction* actionAddGroup(QObject* parent = 0);
19+
QAction* actionRemoveGroupOrLayer(QObject* parent = 0);
20+
QAction* actionShowInOverview(QObject* parent = 0);
21+
QAction* actionRenameGroupOrLayer(QObject* parent = 0);
22+
23+
QAction* actionZoomToLayer(QgsMapCanvas* canvas, QObject* parent = 0);
24+
25+
protected slots:
26+
void addGroup();
27+
void removeGroupOrLayer();
28+
void renameGroupOrLayer();
29+
void showInOverview();
30+
void zoomToLayer();
31+
32+
protected:
33+
void zoomToLayers(QgsMapCanvas* canvas, const QList<QgsMapLayer*>& layers);
34+
35+
protected:
36+
QgsLayerTreeView* mView;
37+
};
38+
39+
40+
#endif // QGSLAYERTREEVIEWDEFAULTACTIONS_H

0 commit comments

Comments
 (0)
Please sign in to comment.