QGIS API Documentation 3.41.0-Master (cea29feecf2)
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
32 : QWidget( parent )
33 , mBridge( bridge )
34{
35 mModel = new CustomLayerOrderModel( bridge, this );
36
37 mView = new QListView( this );
38 mView->setDragEnabled( true );
39 mView->setAcceptDrops( true );
40 mView->setDropIndicatorShown( true );
41 mView->setSelectionMode( QAbstractItemView::ExtendedSelection );
42 mView->setDefaultDropAction( Qt::MoveAction );
43
44 mView->setModel( mModel );
45
46 mChkOverride = new QCheckBox( tr( "Control rendering order" ) );
47 bridgeHasCustomLayerOrderChanged( bridge->rootGroup()->hasCustomLayerOrder() );
48 connect( mChkOverride, &QAbstractButton::toggled, bridge->rootGroup(), &QgsLayerTree::setHasCustomLayerOrder );
49
50 connect( bridge->rootGroup(), &QgsLayerTree::hasCustomLayerOrderChanged, this, &QgsCustomLayerOrderWidget::bridgeHasCustomLayerOrderChanged );
51 connect( bridge->rootGroup(), &QgsLayerTree::customLayerOrderChanged, this, &QgsCustomLayerOrderWidget::bridgeCustomLayerOrderChanged );
52
53 connect( mModel, &QAbstractItemModel::rowsInserted, this, &QgsCustomLayerOrderWidget::modelUpdated );
54 connect( mModel, &QAbstractItemModel::rowsRemoved, this, &QgsCustomLayerOrderWidget::modelUpdated );
55
56 connect( bridge->rootGroup(), &QgsLayerTreeNode::visibilityChanged, this, &QgsCustomLayerOrderWidget::nodeVisibilityChanged );
57
58 QVBoxLayout *l = new QVBoxLayout;
59 l->setContentsMargins( 0, 0, 0, 0 );
60 l->addWidget( mView );
61 l->addWidget( mChkOverride );
62 setLayout( l );
63}
64
65void QgsCustomLayerOrderWidget::bridgeHasCustomLayerOrderChanged( bool state )
66{
67 mChkOverride->setChecked( state );
68 mView->setEnabled( state );
69}
70
71void QgsCustomLayerOrderWidget::bridgeCustomLayerOrderChanged()
72{
73 mModel->refreshModel( mBridge->rootGroup()->layerOrder() );
74}
75
76void QgsCustomLayerOrderWidget::nodeVisibilityChanged( QgsLayerTreeNode *node )
77{
78 if ( QgsLayerTree::isLayer( node ) )
79 {
80 mModel->updateLayerVisibility( QgsLayerTree::toLayer( node )->layerId() );
81 }
82}
83
84void QgsCustomLayerOrderWidget::modelUpdated()
85{
86 mBridge->rootGroup()->setCustomLayerOrder( mModel->order() );
87}
88
89
91
92CustomLayerOrderModel::CustomLayerOrderModel( QgsLayerTreeMapCanvasBridge *bridge, QObject *parent )
93 : QAbstractListModel( parent )
94 , mBridge( bridge )
95{
96}
97
98int CustomLayerOrderModel::rowCount( const QModelIndex & ) const
99{
100 return mOrder.count();
101}
102
103QVariant CustomLayerOrderModel::data( const QModelIndex &index, int role ) const
104{
105 const QString id = mOrder.at( index.row() );
106
107 if ( role == Qt::DisplayRole )
108 {
109 QgsMapLayer *layer = QgsProject::instance()->mapLayer( id );
110 if ( layer )
111 return layer->name();
112 }
113
114 if ( role == Qt::UserRole + 1 )
115 {
116 QgsMapLayer *layer = QgsProject::instance()->mapLayer( id );
117 if ( layer )
118 return layer->id();
119 }
120
121 if ( role == Qt::CheckStateRole )
122 {
123 QgsLayerTreeLayer *nodeLayer = mBridge->rootGroup()->findLayer( id );
124 if ( nodeLayer )
125 return nodeLayer->isVisible();
126 }
127
128 return QVariant();
129}
130
131bool CustomLayerOrderModel::setData( const QModelIndex &index, const QVariant &value, int role )
132{
133 Q_UNUSED( value ); // Toggle
134 if ( role == Qt::CheckStateRole )
135 {
136 const QString id = mOrder.at( index.row() );
137 QgsLayerTreeLayer *nodeLayer = mBridge->rootGroup()->findLayer( id );
138 if ( nodeLayer )
139 {
140 nodeLayer->setItemVisibilityChecked( !nodeLayer->itemVisibilityChecked() );
141 return true;
142 }
143 }
144 return false;
145}
146
147Qt::ItemFlags CustomLayerOrderModel::flags( const QModelIndex &index ) const
148{
149 if ( !index.isValid() )
150 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
151 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable;
152}
153
154Qt::DropActions CustomLayerOrderModel::supportedDropActions() const
155{
156 return Qt::CopyAction | Qt::MoveAction;
157}
158
159QStringList CustomLayerOrderModel::mimeTypes() const
160{
161 QStringList types;
162 types << QStringLiteral( "application/qgis.layerorderdata" );
163 return types;
164}
165
166QMimeData *CustomLayerOrderModel::mimeData( const QModelIndexList &indexes ) const
167{
168 QStringList lst;
169 const auto constIndexes = indexes;
170 for ( const QModelIndex &index : constIndexes )
171 lst << data( index, Qt::UserRole + 1 ).toString();
172
173 QMimeData *mimeData = new QMimeData();
174 mimeData->setData( QStringLiteral( "application/qgis.layerorderdata" ), lst.join( QLatin1Char( '\n' ) ).toUtf8() );
175 return mimeData;
176}
177
178bool CustomLayerOrderModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
179{
180 Q_UNUSED( parent )
181 Q_UNUSED( column )
182
183 if ( action == Qt::IgnoreAction )
184 return true;
185
186 if ( !data->hasFormat( QStringLiteral( "application/qgis.layerorderdata" ) ) )
187 return false;
188
189 const QByteArray encodedData = data->data( QStringLiteral( "application/qgis.layerorderdata" ) );
190 QStringList lst = QString::fromUtf8( encodedData ).split( '\n' );
191
192 if ( row < 0 )
193 row = mOrder.count();
194
195 beginInsertRows( QModelIndex(), row, row + lst.count() - 1 );
196 for ( int i = 0; i < lst.count(); ++i )
197 mOrder.insert( row + i, lst[i] );
198 endInsertRows();
199
200 return true;
201}
202
203bool CustomLayerOrderModel::removeRows( int row, int count, const QModelIndex &parent )
204{
205 Q_UNUSED( parent )
206 if ( count <= 0 )
207 return false;
208
209 beginRemoveRows( QModelIndex(), row, row + count - 1 );
210 while ( --count >= 0 )
211 mOrder.removeAt( row );
212 endRemoveRows();
213 return true;
214}
215
216void CustomLayerOrderModel::refreshModel( const QList<QgsMapLayer *> &order )
217{
218 QStringList orderedIds;
219 const auto constOrder = order;
220 for ( QgsMapLayer *layer : constOrder )
221 {
222 if ( layer )
223 orderedIds.append( layer->id() );
224 }
225
226 if ( orderedIds != mOrder )
227 {
228 beginResetModel();
229 mOrder = orderedIds;
230 endResetModel();
231 }
232}
233
234void CustomLayerOrderModel::updateLayerVisibility( const QString &layerId )
235{
236 const int row = mOrder.indexOf( layerId );
237 if ( row != -1 )
238 emit dataChanged( index( row ), index( row ) );
239}
240
241
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.