QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 "qgsmaplayerregistry.h"
28 
29 
30 class CustomLayerOrderModel : public QAbstractListModel
31 {
32  public:
33  CustomLayerOrderModel( QgsLayerTreeMapCanvasBridge* bridge, QObject* parent = 0 )
34  : QAbstractListModel( parent ), mBridge( bridge )
35  {
36  }
37 
38  int rowCount( const QModelIndex & ) const
39  {
40  return mOrder.count();
41  }
42 
43  QVariant data( const QModelIndex &index, int role ) const
44  {
45  QString id = mOrder.at( index.row() );
46 
47  if ( role == Qt::DisplayRole )
48  {
50  if ( layer )
51  return layer->name();
52  }
53 
54  if ( role == Qt::UserRole + 1 )
55  {
57  if ( layer )
58  return layer->id();
59  }
60 
61  if ( role == Qt::CheckStateRole )
62  {
63  QgsLayerTreeLayer* nodeLayer = mBridge->rootGroup()->findLayer( id );
64  if ( nodeLayer )
65  return nodeLayer->isVisible();
66  }
67 
68  return QVariant();
69  }
70 
71  bool setData( const QModelIndex &index, const QVariant &value, int role )
72  {
73  if ( role == Qt::CheckStateRole )
74  {
75  QString id = mOrder.at( index.row() );
76  QgsLayerTreeLayer* nodeLayer = mBridge->rootGroup()->findLayer( id );
77  if ( nodeLayer )
78  {
79  nodeLayer->setVisible(( Qt::CheckState )value.toInt() );
80  return true;
81  }
82  }
83  return false;
84  }
85 
86  Qt::ItemFlags flags( const QModelIndex &index ) const
87  {
88  if ( !index.isValid() )
89  return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
90  return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable;
91  }
92 
93  Qt::DropActions supportedDropActions() const
94  {
95  return Qt::MoveAction;
96  }
97 
98  QStringList mimeTypes() const
99  {
100  QStringList types;
101  types << "application/qgis.layerorderdata";
102  return types;
103  }
104 
105  QMimeData* mimeData( const QModelIndexList& indexes ) const
106  {
107  QStringList lst;
108  foreach ( QModelIndex index, indexes )
109  lst << data( index, Qt::UserRole + 1 ).toString();
110 
111  QMimeData* mimeData = new QMimeData();
112  mimeData->setData( "application/qgis.layerorderdata", lst.join( "\n" ).toUtf8() );
113  return mimeData;
114  }
115 
116  bool dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
117  {
118  Q_UNUSED( parent );
119  Q_UNUSED( column );
120 
121  if ( action == Qt::IgnoreAction )
122  return true;
123 
124  if ( !data->hasFormat( "application/qgis.layerorderdata" ) )
125  return false;
126 
127  QByteArray encodedData = data->data( "application/qgis.layerorderdata" );
128  QStringList lst = QString::fromUtf8( encodedData ).split( "\n" );
129 
130  if ( row < 0 )
131  row = mOrder.count();
132 
133  beginInsertRows( QModelIndex(), row, row + lst.count() - 1 );
134  for ( int i = 0; i < lst.count(); ++i )
135  mOrder.insert( row + i, lst[i] );
136  endInsertRows();
137 
138  return true;
139  }
140 
141  bool removeRows( int row, int count, const QModelIndex& parent )
142  {
143  Q_UNUSED( parent );
144  if ( count <= 0 )
145  return false;
146 
147  beginRemoveRows( QModelIndex(), row, row + count - 1 );
148  while ( --count >= 0 )
149  mOrder.removeAt( row );
150  endRemoveRows();
151  return true;
152  }
153 
154  void refreshModel( const QStringList& order )
155  {
156  beginResetModel();
157  mOrder = order;
158  endResetModel();
159  }
160 
161  QStringList order() const { return mOrder; }
162 
163  void updateLayerVisibility( const QString& layerId )
164  {
165  int row = mOrder.indexOf( layerId );
166  if ( row != -1 )
167  emit dataChanged( index( row ), index( row ) );
168  }
169 
170  protected:
172  QStringList mOrder;
173 };
174 
175 
177  : QWidget( parent )
178  , mBridge( bridge )
179 {
180  mModel = new CustomLayerOrderModel( bridge, this );
181 
182  mView = new QListView( this );
183  mView->setDragEnabled( true );
184  mView->setAcceptDrops( true );
185  mView->setDropIndicatorShown( true );
186  mView->setDragDropMode( QAbstractItemView::InternalMove );
187  mView->setSelectionMode( QAbstractItemView::ExtendedSelection );
188 
189  mView->setModel( mModel );
190 
191  mChkOverride = new QCheckBox( tr( "Control rendering order" ) );
193  connect( mChkOverride, SIGNAL( toggled( bool ) ), bridge, SLOT( setHasCustomLayerOrder( bool ) ) );
194 
195  connect( bridge, SIGNAL( hasCustomLayerOrderChanged( bool ) ), this, SLOT( bridgeHasCustomLayerOrderChanged( bool ) ) );
196  connect( bridge, SIGNAL( customLayerOrderChanged( QStringList ) ), this, SLOT( bridgeCustomLayerOrderChanged( QStringList ) ) );
197 
198  connect( mModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( modelUpdated() ) );
199  connect( mModel, SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( modelUpdated() ) );
200 
201  connect( bridge->rootGroup(), SIGNAL( visibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ), this, SLOT( nodeVisibilityChanged( QgsLayerTreeNode*, Qt::CheckState ) ) );
202 
203  QVBoxLayout* l = new QVBoxLayout;
204  l->setMargin( 0 );
205  l->addWidget( mView );
206  l->addWidget( mChkOverride );
207  setLayout( l );
208 }
209 
211 {
212  mChkOverride->setChecked( override );
214  mView->setEnabled( override );
215 }
216 
218 {
219  Q_UNUSED( order );
221 }
222 
224 {
225  Q_UNUSED( state );
226  if ( QgsLayerTree::isLayer( node ) )
227  {
228  mModel->updateLayerVisibility( QgsLayerTree::toLayer( node )->layerId() );
229  }
230 }
231 
233 {
235 }
static unsigned index
Base class for all map layer types.
Definition: qgsmaplayer.h:48
void setCustomLayerOrder(const QStringList &order)
bool removeRows(int row, int count, const QModelIndex &parent)
The QgsLayerTreeMapCanvasBridge class takes care of updates of layer set for QgsMapCanvas from a laye...
int rowCount(const QModelIndex &) const
QgsCustomLayerOrderWidget(QgsLayerTreeMapCanvasBridge *bridge, QWidget *parent=0)
CustomLayerOrderModel(QgsLayerTreeMapCanvasBridge *bridge, QObject *parent=0)
QgsLayerTreeMapCanvasBridge * mBridge
bool setData(const QModelIndex &index, const QVariant &value, int role)
Qt::DropActions supportedDropActions() const
const QString & name() const
Get the display name of the layer.
Qt::ItemFlags flags(const QModelIndex &index) const
QgsLayerTreeGroup * rootGroup() const
Qt::CheckState isVisible() const
void nodeVisibilityChanged(QgsLayerTreeNode *node, Qt::CheckState state)
CustomLayerOrderModel * mModel
This class is a base class for nodes in a layer tree.
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
Definition: qgsmaplayer.cpp:95
void setVisible(Qt::CheckState visible)
bool isLayer(QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:40
QVariant data(const QModelIndex &index, int role) const
void bridgeHasCustomLayerOrderChanged(bool override)
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
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
QgsLayerTreeLayer * findLayer(const QString &layerId) const
Find layer node representing the map layer specified by its ID. Searches recursively the whole sub-tr...
QgsLayerTreeMapCanvasBridge * mBridge
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
void bridgeCustomLayerOrderChanged(const QStringList &order)
void updateLayerVisibility(const QString &layerId)
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
void refreshModel(const QStringList &order)
Layer tree node points to a map layer.
QMimeData * mimeData(const QModelIndexList &indexes) const
#define tr(sourceText)