QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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 <QString>
27#include <QVBoxLayout>
28
29#include "moc_qgscustomlayerorderwidget.cpp"
30
31using namespace Qt::StringLiterals;
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
93
94CustomLayerOrderModel::CustomLayerOrderModel( QgsLayerTreeMapCanvasBridge *bridge, QObject *parent )
95 : QAbstractListModel( parent )
96 , mBridge( bridge )
97{}
98
99int CustomLayerOrderModel::rowCount( const QModelIndex & ) const
100{
101 return mOrder.count();
102}
103
104QVariant CustomLayerOrderModel::data( const QModelIndex &index, int role ) const
105{
106 const QString id = mOrder.at( index.row() );
107
108 if ( role == Qt::DisplayRole )
109 {
110 QgsMapLayer *layer = QgsProject::instance()->mapLayer( id );
111 if ( layer )
112 return layer->name();
113 }
114
115 if ( role == Qt::UserRole + 1 )
116 {
117 QgsMapLayer *layer = QgsProject::instance()->mapLayer( id );
118 if ( layer )
119 return layer->id();
120 }
121
122 if ( role == Qt::CheckStateRole )
123 {
124 QgsLayerTreeLayer *nodeLayer = mBridge->rootGroup()->findLayer( id );
125 if ( nodeLayer )
126 return nodeLayer->isVisible();
127 }
128
129 return QVariant();
130}
131
132bool CustomLayerOrderModel::setData( const QModelIndex &index, const QVariant &value, int role )
133{
134 Q_UNUSED( value ); // Toggle
135 if ( role == Qt::CheckStateRole )
136 {
137 const QString id = mOrder.at( index.row() );
138 QgsLayerTreeLayer *nodeLayer = mBridge->rootGroup()->findLayer( id );
139 if ( nodeLayer )
140 {
141 nodeLayer->setItemVisibilityChecked( !nodeLayer->itemVisibilityChecked() );
142 return true;
143 }
144 }
145 return false;
146}
147
148Qt::ItemFlags CustomLayerOrderModel::flags( const QModelIndex &index ) const
149{
150 if ( !index.isValid() )
151 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
152 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable;
153}
154
155Qt::DropActions CustomLayerOrderModel::supportedDropActions() const
156{
157 return Qt::CopyAction | Qt::MoveAction;
158}
159
160QStringList CustomLayerOrderModel::mimeTypes() const
161{
162 QStringList types;
163 types << u"application/qgis.layerorderdata"_s;
164 return types;
165}
166
167QMimeData *CustomLayerOrderModel::mimeData( const QModelIndexList &indexes ) const
168{
169 QStringList lst;
170 const auto constIndexes = indexes;
171 for ( const QModelIndex &index : constIndexes )
172 lst << data( index, Qt::UserRole + 1 ).toString();
173
174 QMimeData *mimeData = new QMimeData();
175 mimeData->setData( u"application/qgis.layerorderdata"_s, lst.join( QLatin1Char( '\n' ) ).toUtf8() );
176 return mimeData;
177}
178
179bool CustomLayerOrderModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
180{
181 Q_UNUSED( parent )
182 Q_UNUSED( column )
183
184 if ( action == Qt::IgnoreAction )
185 return true;
186
187 if ( !data->hasFormat( u"application/qgis.layerorderdata"_s ) )
188 return false;
189
190 const QByteArray encodedData = data->data( u"application/qgis.layerorderdata"_s );
191 QStringList lst = QString::fromUtf8( encodedData ).split( '\n' );
192
193 if ( row < 0 )
194 row = mOrder.count();
195
196 beginInsertRows( QModelIndex(), row, row + lst.count() - 1 );
197 for ( int i = 0; i < lst.count(); ++i )
198 mOrder.insert( row + i, lst[i] );
199 endInsertRows();
200
201 return true;
202}
203
204bool CustomLayerOrderModel::removeRows( int row, int count, const QModelIndex &parent )
205{
206 Q_UNUSED( parent )
207 if ( count <= 0 )
208 return false;
209
210 beginRemoveRows( QModelIndex(), row, row + count - 1 );
211 while ( --count >= 0 )
212 mOrder.removeAt( row );
213 endRemoveRows();
214 return true;
215}
216
217void CustomLayerOrderModel::refreshModel( const QList<QgsMapLayer *> &order )
218{
219 QStringList orderedIds;
220 const auto constOrder = order;
221 for ( QgsMapLayer *layer : constOrder )
222 {
223 if ( layer )
224 orderedIds.append( layer->id() );
225 }
226
227 if ( orderedIds != mOrder )
228 {
229 beginResetModel();
230 mOrder = orderedIds;
231 endResetModel();
232 }
233}
234
235void CustomLayerOrderModel::updateLayerVisibility( const QString &layerId )
236{
237 const int row = mOrder.indexOf( layerId );
238 if ( row != -1 )
239 emit dataChanged( index( row ), index( row ) );
240}
241
242
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:83
QString name
Definition qgsmaplayer.h:87
QString id
Definition qgsmaplayer.h:86
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.