QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
Loading...
Searching...
No Matches
qgscustomlayerorderwidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgscustomlayerorderwidget.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#include "moc_qgscustomlayerorderwidget.cpp"
18
19#include <QCheckBox>
20#include <QListView>
21#include <QMimeData>
22#include <QVBoxLayout>
23
24#include "qgslayertree.h"
26
27#include "qgsmaplayer.h"
28#include "qgsproject.h"
29
30
31
32
34 : QWidget( parent )
35 , mBridge( bridge )
36{
37 mModel = new CustomLayerOrderModel( bridge, this );
38
39 mView = new QListView( this );
40 mView->setDragEnabled( true );
41 mView->setAcceptDrops( true );
42 mView->setDropIndicatorShown( true );
43 mView->setSelectionMode( QAbstractItemView::ExtendedSelection );
44 mView->setDefaultDropAction( Qt::MoveAction );
45
46 mView->setModel( mModel );
47
48 mChkOverride = new QCheckBox( tr( "Control rendering order" ) );
49 bridgeHasCustomLayerOrderChanged( bridge->rootGroup()->hasCustomLayerOrder() );
50 connect( mChkOverride, &QAbstractButton::toggled, bridge->rootGroup(), &QgsLayerTree::setHasCustomLayerOrder );
51
52 connect( bridge->rootGroup(), &QgsLayerTree::hasCustomLayerOrderChanged, this, &QgsCustomLayerOrderWidget::bridgeHasCustomLayerOrderChanged );
53 connect( bridge->rootGroup(), &QgsLayerTree::customLayerOrderChanged, this, &QgsCustomLayerOrderWidget::bridgeCustomLayerOrderChanged );
54
55 connect( mModel, &QAbstractItemModel::rowsInserted, this, &QgsCustomLayerOrderWidget::modelUpdated );
56 connect( mModel, &QAbstractItemModel::rowsRemoved, this, &QgsCustomLayerOrderWidget::modelUpdated );
57
58 connect( bridge->rootGroup(), &QgsLayerTreeNode::visibilityChanged, this, &QgsCustomLayerOrderWidget::nodeVisibilityChanged );
59
60 QVBoxLayout *l = new QVBoxLayout;
61 l->setContentsMargins( 0, 0, 0, 0 );
62 l->addWidget( mView );
63 l->addWidget( mChkOverride );
64 setLayout( l );
65}
66
67void QgsCustomLayerOrderWidget::bridgeHasCustomLayerOrderChanged( bool state )
68{
69 mChkOverride->setChecked( state );
70 mView->setEnabled( state );
71}
72
73void QgsCustomLayerOrderWidget::bridgeCustomLayerOrderChanged()
74{
75 mModel->refreshModel( mBridge->rootGroup()->layerOrder() );
76}
77
78void QgsCustomLayerOrderWidget::nodeVisibilityChanged( QgsLayerTreeNode *node )
79{
80 if ( QgsLayerTree::isLayer( node ) )
81 {
82 mModel->updateLayerVisibility( QgsLayerTree::toLayer( node )->layerId() );
83 }
84}
85
86void QgsCustomLayerOrderWidget::modelUpdated()
87{
88 mBridge->rootGroup()->setCustomLayerOrder( mModel->order() );
89}
90
91
92
94
95CustomLayerOrderModel::CustomLayerOrderModel( QgsLayerTreeMapCanvasBridge *bridge, QObject *parent )
96 : QAbstractListModel( parent )
97 , mBridge( bridge )
98{
99}
100
101int CustomLayerOrderModel::rowCount( const QModelIndex & ) const
102{
103 return mOrder.count();
104}
105
106QVariant CustomLayerOrderModel::data( const QModelIndex &index, int role ) const
107{
108 const QString id = mOrder.at( index.row() );
109
110 if ( role == Qt::DisplayRole )
111 {
112 QgsMapLayer *layer = QgsProject::instance()->mapLayer( id );
113 if ( layer )
114 return layer->name();
115 }
116
117 if ( role == Qt::UserRole + 1 )
118 {
119 QgsMapLayer *layer = QgsProject::instance()->mapLayer( id );
120 if ( layer )
121 return layer->id();
122 }
123
124 if ( role == Qt::CheckStateRole )
125 {
126 QgsLayerTreeLayer *nodeLayer = mBridge->rootGroup()->findLayer( id );
127 if ( nodeLayer )
128 return nodeLayer->isVisible();
129 }
130
131 return QVariant();
132}
133
134bool CustomLayerOrderModel::setData( const QModelIndex &index, const QVariant &value, int role )
135{
136 Q_UNUSED( value ); // Toggle
137 if ( role == Qt::CheckStateRole )
138 {
139 const QString id = mOrder.at( index.row() );
140 QgsLayerTreeLayer *nodeLayer = mBridge->rootGroup()->findLayer( id );
141 if ( nodeLayer )
142 {
143 nodeLayer->setItemVisibilityChecked( ! nodeLayer->itemVisibilityChecked() );
144 return true;
145 }
146 }
147 return false;
148}
149
150Qt::ItemFlags CustomLayerOrderModel::flags( const QModelIndex &index ) const
151{
152 if ( !index.isValid() )
153 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
154 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable;
155}
156
157Qt::DropActions CustomLayerOrderModel::supportedDropActions() const
158{
159 return Qt::CopyAction | Qt::MoveAction;
160}
161
162QStringList CustomLayerOrderModel::mimeTypes() const
163{
164 QStringList types;
165 types << QStringLiteral( "application/qgis.layerorderdata" );
166 return types;
167}
168
169QMimeData *CustomLayerOrderModel::mimeData( const QModelIndexList &indexes ) const
170{
171 QStringList lst;
172 const auto constIndexes = indexes;
173 for ( const QModelIndex &index : constIndexes )
174 lst << data( index, Qt::UserRole + 1 ).toString();
175
176 QMimeData *mimeData = new QMimeData();
177 mimeData->setData( QStringLiteral( "application/qgis.layerorderdata" ), lst.join( QLatin1Char( '\n' ) ).toUtf8() );
178 return mimeData;
179}
180
181bool CustomLayerOrderModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
182{
183 Q_UNUSED( parent )
184 Q_UNUSED( column )
185
186 if ( action == Qt::IgnoreAction )
187 return true;
188
189 if ( !data->hasFormat( QStringLiteral( "application/qgis.layerorderdata" ) ) )
190 return false;
191
192 const QByteArray encodedData = data->data( QStringLiteral( "application/qgis.layerorderdata" ) );
193 QStringList lst = QString::fromUtf8( encodedData ).split( '\n' );
194
195 if ( row < 0 )
196 row = mOrder.count();
197
198 beginInsertRows( QModelIndex(), row, row + lst.count() - 1 );
199 for ( int i = 0; i < lst.count(); ++i )
200 mOrder.insert( row + i, lst[i] );
201 endInsertRows();
202
203 return true;
204}
205
206bool CustomLayerOrderModel::removeRows( int row, int count, const QModelIndex &parent )
207{
208 Q_UNUSED( parent )
209 if ( count <= 0 )
210 return false;
211
212 beginRemoveRows( QModelIndex(), row, row + count - 1 );
213 while ( --count >= 0 )
214 mOrder.removeAt( row );
215 endRemoveRows();
216 return true;
217}
218
219void CustomLayerOrderModel::refreshModel( const QList<QgsMapLayer *> &order )
220{
221 QStringList orderedIds;
222 const auto constOrder = order;
223 for ( QgsMapLayer *layer : constOrder )
224 {
225 if ( layer )
226 orderedIds.append( layer->id() );
227 }
228
229 if ( orderedIds != mOrder )
230 {
231 beginResetModel();
232 mOrder = orderedIds;
233 endResetModel();
234 }
235}
236
237void CustomLayerOrderModel::updateLayerVisibility( const QString &layerId )
238{
239 const int row = mOrder.indexOf( layerId );
240 if ( row != -1 )
241 emit dataChanged( index( row ), index( row ) );
242}
243
244
245
QgsCustomLayerOrderWidget(QgsLayerTreeMapCanvasBridge *bridge, QWidget *parent=nullptr)
Constructor for QgsCustomLayerOrderWidget.
Layer tree node points to a map layer.
The QgsLayerTreeMapCanvasBridge class takes care of updates of layer set for QgsMapCanvas from a laye...
This class is a base class for nodes in a layer tree.
bool isVisible() const
Returns whether a node is really visible (ie checked and all its ancestors checked as well)
void visibilityChanged(QgsLayerTreeNode *node)
Emitted when check state of a node within the tree has been changed.
void setItemVisibilityChecked(bool checked)
Check or uncheck a node (independently of its ancestors or children)
bool itemVisibilityChecked() const
Returns whether a node is checked (independently of its ancestors or children)
bool hasCustomLayerOrder() const
Determines if the layer order should be derived from the layer tree or if a custom override order sha...
void customLayerOrderChanged()
Emitted when the custom layer order has changed.
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
QList< QgsMapLayer * > layerOrder() const
The order in which layers will be rendered on the canvas.
void hasCustomLayerOrderChanged(bool hasCustomLayerOrder)
Emitted when the hasCustomLayerOrder flag changes.
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
void setHasCustomLayerOrder(bool hasCustomLayerOrder)
Determines if the layer order should be derived from the layer tree or if a custom override order sha...
void setCustomLayerOrder(const QList< QgsMapLayer * > &customLayerOrder)
The order in which layers will be rendered on the canvas.
Base class for all map layer types.
Definition qgsmaplayer.h:76
QString name
Definition qgsmaplayer.h:80
QString id
Definition qgsmaplayer.h:79
static QgsProject * instance()
Returns the QgsProject singleton instance.
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.