Skip to content

Commit 6b66b20

Browse files
committed
switch to legend tree for Identify Layers tab in project properties
also add a 'searchable' option for vector layers (they won't be searched in the locator)
1 parent b55ab2e commit 6b66b20

9 files changed

+527
-118
lines changed

python/core/auto_generated/qgsvectorlayer.sip.in

+19
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,18 @@ If you need only the count of committed features call this method on this layer'
14961496
Make layer read-only (editing disabled) or not
14971497

14981498
:return: false if the layer is in editing yet
1499+
%End
1500+
1501+
bool searchable() const;
1502+
%Docstring
1503+
Returns true if the provider is in read-only mode
1504+
%End
1505+
1506+
void setSearchable( bool searchable );
1507+
%Docstring
1508+
Make layer searchable or not
1509+
1510+
.. versionadded:: 3.4
14991511
%End
15001512

15011513
bool changeGeometry( QgsFeatureId fid, QgsGeometry &geometry, bool skipDefaultValue = false );
@@ -2581,6 +2593,13 @@ Emitted when the read only state of this layer is changed.
25812593
Only applies to manually set readonly state, not to the edit mode.
25822594

25832595
.. versionadded:: 3.0
2596+
%End
2597+
2598+
void searchableChanged();
2599+
%Docstring
2600+
Emitted when the search state of this layer is changed.
2601+
2602+
.. versionadded:: 3.4
25842603
%End
25852604

25862605
void symbolFeatureCountMapChanged();

src/app/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ SET(QGIS_APP_SRCS
5454
qgslabelengineconfigdialog.cpp
5555
qgslabelinggui.cpp
5656
qgslabelingwidget.cpp
57+
qgslayercapabilitiesmodel.cpp
5758
qgslayertreeviewembeddedindicator.cpp
5859
qgslayertreeviewfilterindicator.cpp
5960
qgslayertreeviewmemoryindicator.cpp
@@ -275,6 +276,7 @@ SET (QGIS_APP_MOC_HDRS
275276
qgslabelinggui.h
276277
qgslabelingwidget.h
277278
qgslabelpropertydialog.h
279+
qgslayercapabilitiesmodel.h
278280
qgslayertreeviewembeddedindicator.h
279281
qgslayertreeviewmemoryindicator.h
280282
qgslayertreeviewfilterindicator.h

src/app/qgslayercapabilitiesmodel.cpp

+300
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
/***************************************************************************
2+
qgslayercapabilitiesmodel.h
3+
----------------------------
4+
begin : August 2018
5+
copyright : (C) 2018 by Denis Rouzaud
6+
email : denis@opengis.ch
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgslayercapabilitiesmodel.h"
19+
20+
#include "qgslayertree.h"
21+
#include "qgslayertreemodel.h"
22+
23+
QgsLayerCapabilitiesModel::QgsLayerCapabilitiesModel( QgsProject *project, QObject *parent )
24+
: QSortFilterProxyModel( parent )
25+
{
26+
mNonIdentifiableLayers = project->nonIdentifiableLayers();
27+
28+
const QMap<QString, QgsMapLayer *> &mapLayers = QgsProject::instance()->mapLayers();
29+
for ( QMap<QString, QgsMapLayer *>::const_iterator it = mapLayers.constBegin(); it != mapLayers.constEnd(); ++it )
30+
{
31+
mReadOnlyLayers.insert( it.value(), it.value()->readOnly() );
32+
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
33+
mSearchableLayers.insert( it.value(), vl && vl->searchable() );
34+
}
35+
}
36+
37+
38+
QgsLayerTreeModel *QgsLayerCapabilitiesModel::layerTreeModel() const
39+
{
40+
return mLayerTreeModel;
41+
}
42+
43+
void QgsLayerCapabilitiesModel::setLayerTreeModel( QgsLayerTreeModel *layerTreeModel )
44+
{
45+
mLayerTreeModel = layerTreeModel;
46+
QSortFilterProxyModel::setSourceModel( layerTreeModel );
47+
}
48+
49+
void QgsLayerCapabilitiesModel::setFilterText( const QString &filterText )
50+
{
51+
if ( filterText == mFilterText )
52+
return;
53+
54+
mFilterText = filterText;
55+
invalidateFilter();
56+
}
57+
58+
void QgsLayerCapabilitiesModel::checkSelectedItems( const QModelIndexList &checkedIndexes, bool check )
59+
{
60+
QVector<int> roles = QVector<int>() << Qt::CheckStateRole;
61+
// beginResetModel();
62+
for ( const QModelIndex &index : checkedIndexes )
63+
{
64+
if ( setData( index, check ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole ) )
65+
emit dataChanged( index, index ); //), roles);
66+
}
67+
//endResetModel();
68+
}
69+
70+
QStringList QgsLayerCapabilitiesModel::nonIdentifiableLayers() const
71+
{
72+
return mNonIdentifiableLayers;
73+
}
74+
75+
bool QgsLayerCapabilitiesModel::readOnly( QgsMapLayer *layer ) const
76+
{
77+
return mReadOnlyLayers.value( layer, true );
78+
}
79+
80+
bool QgsLayerCapabilitiesModel::searchable( QgsMapLayer *layer ) const
81+
{
82+
return mSearchableLayers.value( layer, false );
83+
}
84+
85+
int QgsLayerCapabilitiesModel::columnCount( const QModelIndex &parent ) const
86+
{
87+
Q_UNUSED( parent );
88+
return 4;
89+
}
90+
91+
QVariant QgsLayerCapabilitiesModel::headerData( int section, Qt::Orientation orientation, int role ) const
92+
{
93+
if ( orientation == Qt::Horizontal )
94+
{
95+
if ( role == Qt::DisplayRole )
96+
{
97+
switch ( section )
98+
{
99+
case 0:
100+
return tr( "Layer" );
101+
case 1:
102+
return tr( "Identifiable" );
103+
case 2:
104+
return tr( "Read-only" );
105+
case 3:
106+
return tr( "Searchable" );
107+
default:
108+
return QVariant();
109+
}
110+
}
111+
}
112+
return mLayerTreeModel->headerData( section, orientation, role );
113+
}
114+
115+
Qt::ItemFlags QgsLayerCapabilitiesModel::flags( const QModelIndex &idx ) const
116+
{
117+
if ( idx.column() == LayerColumn )
118+
{
119+
return Qt::ItemIsEnabled;
120+
}
121+
122+
QgsMapLayer *layer = mapLayer( idx );
123+
if ( !layer )
124+
{
125+
return Qt::NoItemFlags;
126+
}
127+
else
128+
{
129+
if ( idx.column() == IdentifiableColumn )
130+
{
131+
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsUserCheckable;
132+
}
133+
else if ( idx.column() == ReadOnlyColumn )
134+
{
135+
if ( layer->type() == QgsMapLayer::VectorLayer )
136+
{
137+
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsUserCheckable;
138+
}
139+
else
140+
{
141+
return Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
142+
}
143+
}
144+
else if ( idx.column() == SearchableColumn )
145+
{
146+
if ( layer->type() == QgsMapLayer::VectorLayer )
147+
{
148+
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsUserCheckable;
149+
}
150+
else
151+
{
152+
return nullptr;
153+
}
154+
}
155+
}
156+
return nullptr;
157+
}
158+
159+
QgsMapLayer *QgsLayerCapabilitiesModel::mapLayer( const QModelIndex &idx ) const
160+
{
161+
QgsLayerTreeNode *node = nullptr;
162+
if ( idx.column() == LayerColumn )
163+
{
164+
node = mLayerTreeModel->index2node( mapToSource( idx ) );
165+
}
166+
else
167+
{
168+
node = mLayerTreeModel->index2node( mapToSource( index( idx.row(), LayerColumn, idx.parent() ) ) );
169+
}
170+
171+
if ( !node || !QgsLayerTree::isLayer( node ) )
172+
return nullptr;
173+
174+
return QgsLayerTree::toLayer( node )->layer();
175+
}
176+
177+
QModelIndex QgsLayerCapabilitiesModel::index( int row, int column, const QModelIndex &parent ) const
178+
{
179+
QModelIndex newIndex = QSortFilterProxyModel::index( row, LayerColumn, parent );
180+
if ( column == LayerColumn )
181+
return newIndex;
182+
183+
return createIndex( row, column, newIndex.internalId() );
184+
}
185+
186+
QModelIndex QgsLayerCapabilitiesModel::parent( const QModelIndex &child ) const
187+
{
188+
return QSortFilterProxyModel::parent( createIndex( child.row(), LayerColumn, child.internalId() ) );
189+
}
190+
191+
QModelIndex QgsLayerCapabilitiesModel::sibling( int row, int column, const QModelIndex &idx ) const
192+
{
193+
QModelIndex parent = idx.parent();
194+
return index( row, column, parent );
195+
}
196+
197+
QVariant QgsLayerCapabilitiesModel::data( const QModelIndex &idx, int role ) const
198+
{
199+
if ( idx.column() == LayerColumn )
200+
{
201+
return mLayerTreeModel->data( mapToSource( idx ), role );
202+
}
203+
else
204+
{
205+
QgsMapLayer *layer = mapLayer( idx );
206+
207+
if ( !layer )
208+
{
209+
return QVariant();
210+
}
211+
212+
if ( role == Qt::CheckStateRole || role == Qt::UserRole )
213+
{
214+
QVariant trueValue = role == Qt::CheckStateRole ? Qt::Checked : true;
215+
QVariant falseValue = role == Qt::CheckStateRole ? Qt::Unchecked : false;
216+
if ( idx.column() == IdentifiableColumn )
217+
{
218+
return !mNonIdentifiableLayers.contains( layer->id() ) ? trueValue : falseValue;
219+
}
220+
else if ( idx.column() == ReadOnlyColumn )
221+
{
222+
return mReadOnlyLayers.value( layer, true ) ? trueValue : falseValue;
223+
}
224+
else if ( idx.column() == SearchableColumn )
225+
{
226+
return mSearchableLayers.value( layer, true ) ? trueValue : falseValue;
227+
}
228+
}
229+
}
230+
231+
return QVariant();
232+
}
233+
234+
bool QgsLayerCapabilitiesModel::setData( const QModelIndex &index, const QVariant &value, int role )
235+
{
236+
if ( role == Qt::CheckStateRole )
237+
{
238+
QgsMapLayer *layer = mapLayer( index );
239+
if ( layer )
240+
{
241+
if ( index.column() == IdentifiableColumn )
242+
{
243+
bool nonIdentifiable = value == Qt::Unchecked;
244+
bool containsLayer = mNonIdentifiableLayers.contains( layer->id() );
245+
if ( containsLayer && !nonIdentifiable )
246+
mNonIdentifiableLayers.removeAll( layer->id() );
247+
if ( !containsLayer && nonIdentifiable )
248+
mNonIdentifiableLayers.append( layer->id() );
249+
return true;
250+
}
251+
else if ( index.column() == ReadOnlyColumn )
252+
{
253+
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
254+
if ( vl )
255+
{
256+
mReadOnlyLayers.insert( layer, value == Qt::Checked );
257+
return true;
258+
}
259+
}
260+
else if ( index.column() == SearchableColumn )
261+
{
262+
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
263+
if ( vl )
264+
{
265+
mSearchableLayers.insert( layer, value == Qt::Checked );
266+
return true;
267+
}
268+
}
269+
}
270+
}
271+
return false;
272+
}
273+
274+
bool QgsLayerCapabilitiesModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
275+
{
276+
QgsLayerTreeNode *node = mLayerTreeModel->index2node( mLayerTreeModel->index( sourceRow, LayerColumn, sourceParent ) );
277+
return nodeShown( node );
278+
}
279+
280+
bool QgsLayerCapabilitiesModel::nodeShown( QgsLayerTreeNode *node ) const
281+
{
282+
if ( !node )
283+
return false;
284+
if ( node->nodeType() == QgsLayerTreeNode::NodeGroup )
285+
{
286+
Q_FOREACH ( QgsLayerTreeNode *child, node->children() )
287+
{
288+
if ( nodeShown( child ) )
289+
{
290+
return true;
291+
}
292+
}
293+
return false;
294+
}
295+
else
296+
{
297+
QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer();
298+
return layer && ( mFilterText.isEmpty() || layer->name().contains( mFilterText, Qt::CaseInsensitive ) );
299+
}
300+
}

0 commit comments

Comments
 (0)