QGIS API Documentation  2.99.0-Master (90ae728)
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 <QCheckBox>
19 #include <QListView>
20 #include <QMimeData>
21 #include <QVBoxLayout>
22 
23 #include "qgslayertree.h"
25 
26 #include "qgsmaplayer.h"
27 #include "qgsproject.h"
28 
29 
30 
31 
33  : QWidget( parent )
34  , mBridge( bridge )
35 {
36  mModel = new CustomLayerOrderModel( bridge, this );
37 
38  mView = new QListView( this );
39  mView->setDragEnabled( true );
40  mView->setAcceptDrops( true );
41  mView->setDropIndicatorShown( true );
42  mView->setSelectionMode( QAbstractItemView::ExtendedSelection );
43  mView->setDefaultDropAction( Qt::MoveAction );
44 
45  mView->setModel( mModel );
46 
47  mChkOverride = new QCheckBox( tr( "Control rendering order" ) );
49  connect( mChkOverride, SIGNAL( toggled( bool ) ), bridge, SLOT( setHasCustomLayerOrder( bool ) ) );
50 
51  connect( bridge, SIGNAL( hasCustomLayerOrderChanged( bool ) ), this, SLOT( bridgeHasCustomLayerOrderChanged( bool ) ) );
52  connect( bridge, SIGNAL( customLayerOrderChanged( QStringList ) ), this, SLOT( bridgeCustomLayerOrderChanged( QStringList ) ) );
53 
54  connect( mModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( modelUpdated() ) );
55  connect( mModel, SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( modelUpdated() ) );
56 
58 
59  QVBoxLayout* l = new QVBoxLayout;
60  l->setMargin( 0 );
61  l->addWidget( mView );
62  l->addWidget( mChkOverride );
63  setLayout( l );
64 }
65 
67 {
68  mChkOverride->setChecked( state );
70  mView->setEnabled( state );
71 }
72 
74 {
75  Q_UNUSED( order );
77 }
78 
80 {
81  if ( QgsLayerTree::isLayer( node ) )
82  {
83  mModel->updateLayerVisibility( QgsLayerTree::toLayer( node )->layerId() );
84  }
85 }
86 
88 {
89  mBridge->setCustomLayerOrder( mModel->order() );
90 }
91 
92 
93 
95 
96 CustomLayerOrderModel::CustomLayerOrderModel( QgsLayerTreeMapCanvasBridge* bridge, QObject* parent )
97  : QAbstractListModel( parent )
98  , mBridge( bridge )
99 {
100 }
101 
102 int CustomLayerOrderModel::rowCount( const QModelIndex& ) const
103 {
104  return mOrder.count();
105 }
106 
107 QVariant CustomLayerOrderModel::data( const QModelIndex& index, int role ) const
108 {
109  QString id = mOrder.at( index.row() );
110 
111  if ( role == Qt::DisplayRole )
112  {
113  QgsMapLayer* layer = QgsProject::instance()->mapLayer( id );
114  if ( layer )
115  return layer->name();
116  }
117 
118  if ( role == Qt::UserRole + 1 )
119  {
120  QgsMapLayer* layer = QgsProject::instance()->mapLayer( id );
121  if ( layer )
122  return layer->id();
123  }
124 
125  if ( role == Qt::CheckStateRole )
126  {
127  QgsLayerTreeLayer* nodeLayer = mBridge->rootGroup()->findLayer( id );
128  if ( nodeLayer )
129  return nodeLayer->isVisible();
130  }
131 
132  return QVariant();
133 }
134 
135 bool CustomLayerOrderModel::setData( const QModelIndex& index, const QVariant& value, int role )
136 {
137  if ( role == Qt::CheckStateRole )
138  {
139  QString id = mOrder.at( index.row() );
140  QgsLayerTreeLayer* nodeLayer = mBridge->rootGroup()->findLayer( id );
141  if ( nodeLayer )
142  {
143  nodeLayer->setItemVisibilityChecked( static_cast< Qt::CheckState >( value.toInt() ) == Qt::Checked );
144  return true;
145  }
146  }
147  return false;
148 }
149 
150 Qt::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 
157 Qt::DropActions CustomLayerOrderModel::supportedDropActions() const
158 {
159  return Qt::CopyAction | Qt::MoveAction;
160 }
161 
162 QStringList CustomLayerOrderModel::mimeTypes() const
163 {
164  QStringList types;
165  types << QStringLiteral( "application/qgis.layerorderdata" );
166  return types;
167 }
168 
169 QMimeData*CustomLayerOrderModel::mimeData( const QModelIndexList& indexes ) const
170 {
171  QStringList lst;
172  Q_FOREACH ( const QModelIndex& index, indexes )
173  lst << data( index, Qt::UserRole + 1 ).toString();
174 
175  QMimeData* mimeData = new QMimeData();
176  mimeData->setData( QStringLiteral( "application/qgis.layerorderdata" ), lst.join( QStringLiteral( "\n" ) ).toUtf8() );
177  return mimeData;
178 }
179 
180 bool CustomLayerOrderModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent )
181 {
182  Q_UNUSED( parent );
183  Q_UNUSED( column );
184 
185  if ( action == Qt::IgnoreAction )
186  return true;
187 
188  if ( !data->hasFormat( QStringLiteral( "application/qgis.layerorderdata" ) ) )
189  return false;
190 
191  QByteArray encodedData = data->data( QStringLiteral( "application/qgis.layerorderdata" ) );
192  QStringList lst = QString::fromUtf8( encodedData ).split( '\n' );
193 
194  if ( row < 0 )
195  row = mOrder.count();
196 
197  beginInsertRows( QModelIndex(), row, row + lst.count() - 1 );
198  for ( int i = 0; i < lst.count(); ++i )
199  mOrder.insert( row + i, lst[i] );
200  endInsertRows();
201 
202  return true;
203 }
204 
205 bool CustomLayerOrderModel::removeRows( int row, int count, const QModelIndex& parent )
206 {
207  Q_UNUSED( parent );
208  if ( count <= 0 )
209  return false;
210 
211  beginRemoveRows( QModelIndex(), row, row + count - 1 );
212  while ( --count >= 0 )
213  mOrder.removeAt( row );
214  endRemoveRows();
215  return true;
216 }
217 
218 void CustomLayerOrderModel::refreshModel( const QStringList& order )
219 {
220  beginResetModel();
221  mOrder = order;
222  endResetModel();
223 }
224 
225 void CustomLayerOrderModel::updateLayerVisibility( const QString& layerId )
226 {
227  int row = mOrder.indexOf( layerId );
228  if ( row != -1 )
229  emit dataChanged( index( row ), index( row ) );
230 }
231 
232 
233 
static unsigned index
Base class for all map layer types.
Definition: qgsmaplayer.h:52
void setCustomLayerOrder(const QStringList &order)
The QgsLayerTreeMapCanvasBridge class takes care of updates of layer set for QgsMapCanvas from a laye...
void bridgeHasCustomLayerOrderChanged(bool state)
void nodeVisibilityChanged(QgsLayerTreeNode *node)
Slot triggered when the ivsibility of a node changes.
bool isVisible() const
Returns whether a node is really visible (ie checked and all its ancestors checked as well) ...
QgsLayerTreeMapCanvasBridge * mBridge
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
CustomLayerOrderModel * mModel
This class is a base class for nodes in a layer tree.
bool isLayer(QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:40
QgsLayerTreeGroup * rootGroup() const
QgsCustomLayerOrderWidget(QgsLayerTreeMapCanvasBridge *bridge, QWidget *parent=nullptr)
QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer. No type checking is done - use isLayer() to find out whether this operation is ...
Definition: qgslayertree.h:52
void visibilityChanged(QgsLayerTreeNode *node)
Emitted when check state of a node within the tree has been changed.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:355
QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
void setItemVisibilityChecked(bool checked)
Check or uncheck a node (independently of its ancestors or children)
QString name
Read property of QString layerName.
Definition: qgsmaplayer.h:56
void bridgeCustomLayerOrderChanged(const QStringList &order)
QgsLayerTreeLayer * findLayer(QgsMapLayer *layer) const
Find layer node representing the map layer.
Layer tree node points to a map layer.