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