QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgslayertreeview.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslayertreeview.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
16#include "qgslayertreeview.h"
17
18#include "qgslayertree.h"
20#include "qgslayertreemodel.h"
22#include "qgslayertreeutils.h"
24#include "qgsmaplayer.h"
25#include "qgsmessagebar.h"
27
28#include "qgsgui.h"
29
30#include <QMenu>
31#include <QContextMenuEvent>
32#include <QHeaderView>
33#include <QScrollBar>
34
35#ifdef ENABLE_MODELTEST
36#include "modeltest.h"
37#endif
38
41
42
44 : QTreeView( parent )
45
46{
47 setHeaderHidden( true );
48
49 setDragEnabled( true );
50 setAcceptDrops( true );
51 setDropIndicatorShown( true );
52 setEditTriggers( EditKeyPressed );
53 setExpandsOnDoubleClick( false ); // normally used for other actions
54
55 // Ensure legend graphics are scrollable
56 header()->setStretchLastSection( false );
57 header()->setSectionResizeMode( QHeaderView::ResizeToContents );
58
59 // If vertically scrolling by item, legend graphics can get clipped
60 setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
61
62 setSelectionMode( ExtendedSelection );
63 setDefaultDropAction( Qt::MoveAction );
64
65 // we need a custom item delegate in order to draw indicators
66 setItemDelegate( new QgsLayerTreeViewItemDelegate( this ) );
67 setStyle( new QgsLayerTreeViewProxyStyle( this ) );
68
69 setLayerMarkWidth( static_cast< int >( QFontMetricsF( font() ).horizontalAdvance( 'l' ) * Qgis::UI_SCALE_FACTOR ) );
70
71 connect( this, &QTreeView::collapsed, this, &QgsLayerTreeView::updateExpandedStateToNode );
72 connect( this, &QTreeView::expanded, this, &QgsLayerTreeView::updateExpandedStateToNode );
73
74 connect( horizontalScrollBar(), &QScrollBar::valueChanged, this, &QgsLayerTreeView::onHorizontalScroll );
75}
76
78{
79 delete mMenuProvider;
80}
81
82void QgsLayerTreeView::setModel( QAbstractItemModel *model )
83{
84 QgsLayerTreeModel *treeModel = qobject_cast<QgsLayerTreeModel *>( model );
85 if ( !treeModel )
86 return;
87
88 if ( mMessageBar )
89 connect( treeModel, &QgsLayerTreeModel::messageEmitted, this,
90 [ = ]( const QString & message, Qgis::MessageLevel level = Qgis::MessageLevel::Info, int duration = 5 )
91 {
92 Q_UNUSED( duration )
93 mMessageBar->pushMessage( message, level );
94 }
95 );
96
97 mProxyModel = new QgsLayerTreeProxyModel( treeModel, this );
98
99 connect( mProxyModel, &QAbstractItemModel::rowsInserted, this, &QgsLayerTreeView::modelRowsInserted );
100 connect( mProxyModel, &QAbstractItemModel::rowsRemoved, this, &QgsLayerTreeView::modelRowsRemoved );
101
102#ifdef ENABLE_MODELTEST
103 new ModelTest( mProxyModel, this );
104#endif
105
106 mProxyModel->setShowPrivateLayers( mShowPrivateLayers );
107 QTreeView::setModel( mProxyModel );
108
110 connect( treeModel->rootGroup(), &QgsLayerTreeNode::customPropertyChanged, this, &QgsLayerTreeView::onCustomPropertyChanged );
111
112 connect( selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsLayerTreeView::onCurrentChanged );
113
114 connect( treeModel, &QAbstractItemModel::modelReset, this, &QgsLayerTreeView::onModelReset );
115
116 connect( treeModel, &QAbstractItemModel::dataChanged, this, &QgsLayerTreeView::onDataChanged );
117
119
120 //checkModel();
121}
122
124{
125 return mProxyModel ? qobject_cast<QgsLayerTreeModel *>( mProxyModel->sourceModel() ) : nullptr;
126}
127
129{
130 if ( !mDefaultActions )
132 return mDefaultActions;
133}
134
136{
137 delete mMenuProvider;
139}
140
142{
143 return layerForIndex( currentIndex() );
144}
145
147{
148 if ( !layer )
149 {
150 setCurrentIndex( QModelIndex() );
151 return;
152 }
153
154 QgsLayerTreeLayer *nodeLayer = layerTreeModel()->rootGroup()->findLayer( layer->id() );
155 if ( !nodeLayer )
156 return;
157
158 setCurrentIndex( node2index( nodeLayer ) );
159}
160
162{
163 if ( !layer )
164 return;
165 QgsLayerTreeLayer *nodeLayer = layerTreeModel()->rootGroup()->findLayer( layer->id() );
166 if ( !nodeLayer )
167 return;
168 nodeLayer->setItemVisibilityChecked( visible );
169}
170
171void QgsLayerTreeView::contextMenuEvent( QContextMenuEvent *event )
172{
173 if ( !mMenuProvider )
174 return;
175
176 const QModelIndex idx = indexAt( event->pos() );
177 if ( !idx.isValid() )
178 setCurrentIndex( QModelIndex() );
179
180 QMenu *menu = mMenuProvider->createContextMenu();
181 if ( menu && menu->actions().count() != 0 )
182 menu->exec( mapToGlobal( event->pos() ) );
183 delete menu;
184}
185
186
187void QgsLayerTreeView::modelRowsInserted( const QModelIndex &index, int start, int end )
188{
189 QgsLayerTreeNode *parentNode = index2node( index );
190 if ( !parentNode )
191 return;
192
193 // Embedded widgets - replace placeholders in the model by actual widgets
195 {
196 QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( parentNode );
197 if ( QgsMapLayer *layer = nodeLayer->layer() )
198 {
199 const int widgetsCount = layer->customProperty( QStringLiteral( "embeddedWidgets/count" ), 0 ).toInt();
200 QList<QgsLayerTreeModelLegendNode *> legendNodes = layerTreeModel()->layerLegendNodes( nodeLayer, true );
201 for ( int i = 0; i < widgetsCount; ++i )
202 {
203 const QString providerId = layer->customProperty( QStringLiteral( "embeddedWidgets/%1/id" ).arg( i ) ).toString();
204 if ( QgsLayerTreeEmbeddedWidgetProvider *provider = QgsGui::layerTreeEmbeddedWidgetRegistry()->provider( providerId ) )
205 {
206 const QModelIndex index = legendNode2index( legendNodes[i] );
207 QWidget *wdgt = provider->createWidget( layer, i );
208 // Since column is resized to contents, limit the expanded width of embedded
209 // widgets, if they are not already limited, e.g. have the default MAX value.
210 // Else, embedded widget may grow very wide due to large legend graphics.
211 // NOTE: This approach DOES NOT work right. It causes horizontal scroll
212 // bar to disappear if the embedded widget is expanded and part
213 // of the last layer in the panel, even if much wider legend items
214 // are expanded above it. The correct width-limiting method should
215 // be setting fixed-width, hidpi-aware embedded widget items in a
216 // layout and appending an expanding QSpacerItem to end. This ensures
217 // full width is always created in the column by the embedded widget.
218 // See QgsLayerTreeOpacityWidget
219 //if ( wdgt->maximumWidth() == QWIDGETSIZE_MAX )
220 //{
221 // wdgt->setMaximumWidth( 250 );
222 //}
223
224 setIndexWidget( index, wdgt );
225 }
226 }
227 }
228 }
229
230
231 if ( QgsLayerTree::isLayer( parentNode ) )
232 {
233 // if ShowLegendAsTree flag is enabled in model, we may need to expand some legend nodes
234 const QStringList expandedNodeKeys = parentNode->customProperty( QStringLiteral( "expandedLegendNodes" ) ).toStringList();
235 if ( expandedNodeKeys.isEmpty() )
236 return;
237
238 const auto constLayerLegendNodes = layerTreeModel()->layerLegendNodes( QgsLayerTree::toLayer( parentNode ), true );
239 for ( QgsLayerTreeModelLegendNode *legendNode : constLayerLegendNodes )
240 {
241 const QString ruleKey = legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString();
242 if ( expandedNodeKeys.contains( ruleKey ) )
243 setExpanded( legendNode2index( legendNode ), true );
244 }
245 return;
246 }
247
248 QList<QgsLayerTreeNode *> children = parentNode->children();
249 for ( int i = start; i <= end; ++i )
250 {
251 updateExpandedStateFromNode( children[i] );
252 }
253
254 // make sure we still have correct current layer
256}
257
259{
260 // make sure we still have correct current layer
262}
263
264void QgsLayerTreeView::updateExpandedStateToNode( const QModelIndex &index )
265{
266 if ( QgsLayerTreeNode *node = index2node( index ) )
267 {
268 node->setExpanded( isExpanded( index ) );
269 }
270 else if ( QgsLayerTreeModelLegendNode *node = index2legendNode( index ) )
271 {
272 const QString ruleKey = node->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString();
273 QStringList lst = node->layerNode()->customProperty( QStringLiteral( "expandedLegendNodes" ) ).toStringList();
274 const bool expanded = isExpanded( index );
275 const bool isInList = lst.contains( ruleKey );
276 if ( expanded && !isInList )
277 {
278 lst.append( ruleKey );
279 node->layerNode()->setCustomProperty( QStringLiteral( "expandedLegendNodes" ), lst );
280 }
281 else if ( !expanded && isInList )
282 {
283 lst.removeAll( ruleKey );
284 node->layerNode()->setCustomProperty( QStringLiteral( "expandedLegendNodes" ), lst );
285 }
286 }
287}
288
290{
291 QgsMapLayer *layerCurrent = layerForIndex( currentIndex() );
292 const QString layerCurrentID = layerCurrent ? layerCurrent->id() : QString();
293 if ( mCurrentLayerID == layerCurrentID )
294 return;
295
296 // update the current index in model (the item will be underlined)
297 QModelIndex proxyModelNodeLayerIndex;
298 if ( layerCurrent )
299 {
300 QgsLayerTreeLayer *nodeLayer = layerTreeModel()->rootGroup()->findLayer( layerCurrentID );
301 if ( nodeLayer )
302 proxyModelNodeLayerIndex = node2index( nodeLayer );
303 }
304
305 if ( ! proxyModelNodeLayerIndex.isValid() )
306 {
307 mCurrentLayerID = QString();
308 layerTreeModel()->setCurrentIndex( QModelIndex() );
309 }
310 else
311 {
312 mCurrentLayerID = layerCurrentID;
313 layerTreeModel()->setCurrentIndex( mProxyModel->mapToSource( proxyModelNodeLayerIndex ) );
314 }
315
316 //checkModel();
317
318 emit currentLayerChanged( layerCurrent );
319}
320
322{
323 const QModelIndex idx = node2index( node );
324 if ( isExpanded( idx ) != expanded )
325 setExpanded( idx, expanded );
326}
327
328void QgsLayerTreeView::onCustomPropertyChanged( QgsLayerTreeNode *node, const QString &key )
329{
330 if ( key != QLatin1String( "expandedLegendNodes" ) || !QgsLayerTree::isLayer( node ) )
331 return;
332
333 const QSet<QString> expandedLegendNodes = qgis::listToSet( node->customProperty( QStringLiteral( "expandedLegendNodes" ) ).toStringList() );
334
335 const QList<QgsLayerTreeModelLegendNode *> legendNodes = layerTreeModel()->layerLegendNodes( QgsLayerTree::toLayer( node ), true );
336 for ( QgsLayerTreeModelLegendNode *legendNode : legendNodes )
337 {
338 const QString key = legendNode->data( QgsLayerTreeModelLegendNode::RuleKeyRole ).toString();
339 if ( !key.isEmpty() )
340 setExpanded( legendNode2index( legendNode ), expandedLegendNodes.contains( key ) );
341 }
342}
343
345{
347 //checkModel();
348}
349
351{
352 const QModelIndex idx = node2index( node );
353 setExpanded( idx, node->isExpanded() );
354
355 const auto constChildren = node->children();
356 for ( QgsLayerTreeNode *child : constChildren )
358}
359
360QgsMapLayer *QgsLayerTreeView::layerForIndex( const QModelIndex &index ) const
361{
362 // Check if model has been set and index is valid
363 if ( layerTreeModel() && index.isValid() )
364 {
365 QgsLayerTreeNode *node = index2node( index );
366 if ( node )
367 {
368 if ( QgsLayerTree::isLayer( node ) )
369 return QgsLayerTree::toLayer( node )->layer();
370 }
371 else
372 {
373 // possibly a legend node
375 if ( legendNode )
376 return legendNode->layerNode()->layer();
377 }
378 }
379 return nullptr;
380}
381
383{
384 return index2node( selectionModel()->currentIndex() );
385}
386
388{
390 if ( QgsLayerTree::isGroup( node ) )
391 return QgsLayerTree::toGroup( node );
392 else if ( QgsLayerTree::isLayer( node ) )
393 {
394 QgsLayerTreeNode *parent = node->parent();
395 if ( QgsLayerTree::isGroup( parent ) )
396 return QgsLayerTree::toGroup( parent );
397 }
398
399 if ( QgsLayerTreeModelLegendNode *legendNode = index2legendNode( selectionModel()->currentIndex() ) )
400 {
402 if ( QgsLayerTree::isGroup( parent->parent() ) )
403 return QgsLayerTree::toGroup( parent->parent() );
404 }
405
406 return nullptr;
407}
408
410{
411 return index2legendNode( selectionModel()->currentIndex() );
412}
413
414QList<QgsLayerTreeNode *> QgsLayerTreeView::selectedNodes( bool skipInternal ) const
415{
416 QModelIndexList mapped;
417 const QModelIndexList selected = selectionModel()->selectedIndexes();
418 mapped.reserve( selected.size() );
419 for ( const QModelIndex &index : selected )
420 mapped << mProxyModel->mapToSource( index );
421
422 return layerTreeModel()->indexes2nodes( mapped, skipInternal );
423}
424
425QList<QgsLayerTreeLayer *> QgsLayerTreeView::selectedLayerNodes() const
426{
427 QList<QgsLayerTreeLayer *> layerNodes;
428 const auto constSelectedNodes = selectedNodes();
429 for ( QgsLayerTreeNode *node : constSelectedNodes )
430 {
431 if ( QgsLayerTree::isLayer( node ) )
432 layerNodes << QgsLayerTree::toLayer( node );
433 }
434 return layerNodes;
435}
436
437QList<QgsMapLayer *> QgsLayerTreeView::selectedLayers() const
438{
439 QList<QgsMapLayer *> list;
440 const auto constSelectedLayerNodes = selectedLayerNodes();
441 for ( QgsLayerTreeLayer *node : constSelectedLayerNodes )
442 {
443 if ( node->layer() )
444 list << node->layer();
445 }
446 return list;
447}
448
450{
451 QModelIndexList mapped;
452 const QModelIndexList selected = selectionModel()->selectedIndexes();
453 mapped.reserve( selected.size() );
454 for ( const QModelIndex &index : selected )
455 mapped << mProxyModel->mapToSource( index );
456
457 const QList<QgsLayerTreeNode *> nodes = layerTreeModel()->indexes2nodes( mapped, false );
458 const QSet<QgsMapLayer *> layersSet = QgsLayerTreeUtils::collectMapLayersRecursive( nodes );
459 return qgis::setToList( layersSet );
460}
461
463{
464 if ( !mIndicators[node].contains( indicator ) )
465 {
466 mIndicators[node].append( indicator );
467 connect( indicator, &QgsLayerTreeViewIndicator::changed, this, [ = ]
468 {
469 update();
470 viewport()->repaint();
471 } );
472 update();
473 viewport()->repaint(); //update() does not automatically trigger a repaint()
474 }
475}
476
478{
479 mIndicators[node].removeOne( indicator );
480 update();
481}
482
483QList<QgsLayerTreeViewIndicator *> QgsLayerTreeView::indicators( QgsLayerTreeNode *node ) const
484{
485 return mIndicators.value( node );
486}
487
489QStringList QgsLayerTreeView::viewOnlyCustomProperties()
490{
491 return QStringList() << QStringLiteral( "expandedLegendNodes" );
492}
494
495void QgsLayerTreeView::refreshLayerSymbology( const QString &layerId )
496{
497 QgsLayerTreeLayer *nodeLayer = layerTreeModel()->rootGroup()->findLayer( layerId );
498 if ( nodeLayer )
499 layerTreeModel()->refreshLayerLegend( nodeLayer );
500}
501
502
503static void _expandAllLegendNodes( QgsLayerTreeLayer *nodeLayer, bool expanded, QgsLayerTreeModel *model )
504{
505 // for layers we also need to find out with legend nodes contain some children and make them expanded/collapsed
506 // if we are collapsing, we just write out an empty list
507 QStringList lst;
508 if ( expanded )
509 {
510 const auto constLayerLegendNodes = model->layerLegendNodes( nodeLayer, true );
511 for ( QgsLayerTreeModelLegendNode *legendNode : constLayerLegendNodes )
512 {
513 const QString parentKey = legendNode->data( QgsLayerTreeModelLegendNode::ParentRuleKeyRole ).toString();
514 if ( !parentKey.isEmpty() && !lst.contains( parentKey ) )
515 lst << parentKey;
516 }
517 }
518 nodeLayer->setCustomProperty( QStringLiteral( "expandedLegendNodes" ), lst );
519}
520
521
522static void _expandAllNodes( QgsLayerTreeGroup *parent, bool expanded, QgsLayerTreeModel *model )
523{
524 const auto constChildren = parent->children();
525 for ( QgsLayerTreeNode *node : constChildren )
526 {
527 node->setExpanded( expanded );
528 if ( QgsLayerTree::isGroup( node ) )
529 _expandAllNodes( QgsLayerTree::toGroup( node ), expanded, model );
530 else if ( QgsLayerTree::isLayer( node ) )
531 _expandAllLegendNodes( QgsLayerTree::toLayer( node ), expanded, model );
532 }
533}
534
535
537{
538 // unfortunately expandAll() does not emit expanded() signals
539 _expandAllNodes( layerTreeModel()->rootGroup(), true, layerTreeModel() );
540 expandAll();
541}
542
544{
545 // unfortunately collapseAll() does not emit collapsed() signals
546 _expandAllNodes( layerTreeModel()->rootGroup(), false, layerTreeModel() );
547 collapseAll();
548}
549
551{
552 if ( mMessageBar == messageBar )
553 return;
554
555 mMessageBar = messageBar;
556
557 if ( mMessageBar )
559 [ = ]( const QString & message, Qgis::MessageLevel level = Qgis::MessageLevel::Info, int duration = 5 )
560 {
561 Q_UNUSED( duration )
562 mMessageBar->pushMessage( message, level );
563 }
564 );
565}
566
568{
569 mShowPrivateLayers = showPrivate;
570 mProxyModel->setShowPrivateLayers( showPrivate );
571}
572
574{
575 return mShowPrivateLayers;
576}
577
578void QgsLayerTreeView::mouseReleaseEvent( QMouseEvent *event )
579{
580 // we need to keep last mouse position in order to know whether to emit an indicator's clicked() signal
581 // (the item delegate needs to know which indicator has been clicked)
582 mLastReleaseMousePos = event->pos();
583
584 const QgsLayerTreeModel::Flags oldFlags = layerTreeModel()->flags();
585 if ( event->modifiers() & Qt::ControlModifier )
587 else
589 QTreeView::mouseReleaseEvent( event );
590 layerTreeModel()->setFlags( oldFlags );
591}
592
593void QgsLayerTreeView::keyPressEvent( QKeyEvent *event )
594{
595 if ( event->key() == Qt::Key_Space )
596 {
597 const auto constSelectedNodes = selectedNodes();
598
599 if ( ! constSelectedNodes.isEmpty() )
600 {
601 const bool isFirstNodeChecked = constSelectedNodes[0]->itemVisibilityChecked();
602 for ( QgsLayerTreeNode *node : constSelectedNodes )
603 {
604 node->setItemVisibilityChecked( ! isFirstNodeChecked );
605 }
606
607 // if we call the original keyPress handler, the current item will be checked to the original state yet again
608 return;
609 }
610 }
611
612 const QgsLayerTreeModel::Flags oldFlags = layerTreeModel()->flags();
613 if ( event->modifiers() & Qt::ControlModifier )
615 else
617 QTreeView::keyPressEvent( event );
618 layerTreeModel()->setFlags( oldFlags );
619}
620
621void QgsLayerTreeView::dropEvent( QDropEvent *event )
622{
623 if ( event->keyboardModifiers() & Qt::AltModifier )
624 {
625 event->accept();
626 }
627 QTreeView::dropEvent( event );
628}
629
630void QgsLayerTreeView::resizeEvent( QResizeEvent *event )
631{
632 // Since last column is resized to content (instead of stretched), the active
633 // selection rectangle ends at width of widest visible item in tree,
634 // regardless of which item is selected. This causes layer indicators to
635 // become 'inactive' (not clickable and no tool tip) unless their rectangle
636 // enters the view item's selection (active) rectangle.
637 // Always resetting the minimum section size relative to the viewport ensures
638 // the view item's selection rectangle extends to the right edge of the
639 // viewport, which allows indicators to become active again.
640 header()->setMinimumSectionSize( viewport()->width() );
641 QTreeView::resizeEvent( event );
642}
643
644void QgsLayerTreeView::onHorizontalScroll( int value )
645{
646 Q_UNUSED( value )
647 viewport()->update();
648}
649
650void QgsLayerTreeView::onDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles )
651{
652 Q_UNUSED( topLeft )
653 Q_UNUSED( bottomRight )
654
655 // If an item is resized asynchronously (e.g. wms legend)
656 // The items below will need to be shifted vertically.
657 // This doesn't happen automatically, unless the viewport update is triggered.
658
659 if ( roles.contains( Qt::SizeHintRole ) )
660 viewport()->update();
661
662 //checkModel();
663}
664
665#if 0
666// for model debugging
667void QgsLayerTreeView::checkModel()
668{
669 std::function<void( QgsLayerTreeNode *, int )> debug;
670 debug = [ & ]( QgsLayerTreeNode * node, int depth )
671 {
672 if ( depth == 1 )
673 qDebug() << "----------------------------------------------";
674
675 qDebug() << depth << node->name() << node2index( node ) << layerTreeModel()->rowCount( node2sourceIndex( node ) ) << mProxyModel->rowCount( node2index( node ) );
676 Q_ASSERT( node == index2node( node2index( node ) ) );
677 Q_ASSERT( node == layerTreeModel()->index2node( node2sourceIndex( node ) ) );
678 Q_ASSERT( layerTreeModel()->rowCount( node2sourceIndex( node ) ) == mProxyModel->rowCount( node2index( node ) ) );
679
680 for ( int i = 0; i < mProxyModel->rowCount( node2index( node ) ); i++ )
681 {
682 QgsLayerTreeNode *childNode { index2node( mProxyModel->index( i, 0, node2index( node ) ) ) };
683 if ( childNode )
684 debug( childNode, depth + 1 );
685 else
686 qDebug() << "Warning no child node!";
687 }
688 };
689 debug( layerTreeModel()->rootGroup(), 1 );
690}
691#endif
692
694{
695 return mProxyModel;
696}
697
698QgsLayerTreeNode *QgsLayerTreeView::index2node( const QModelIndex &index ) const
699{
700 return layerTreeModel()->index2node( mProxyModel->mapToSource( index ) );
701}
702
704{
705 return mProxyModel->mapFromSource( node2sourceIndex( node ) );
706}
707
709{
710 return layerTreeModel()->node2index( node );
711}
712
714{
715 return QgsLayerTreeModel::index2legendNode( mProxyModel->mapToSource( index ) );
716}
717
719{
720 return mProxyModel->mapFromSource( legendNode2sourceIndex( legendNode ) );
721}
722
724{
726}
727
729 : QSortFilterProxyModel( parent )
730 , mLayerTreeModel( treeModel )
731{
732 setSourceModel( treeModel );
733}
734
735void QgsLayerTreeProxyModel::setFilterText( const QString &filterText )
736{
737 if ( filterText == mFilterText )
738 return;
739
740 mFilterText = filterText;
741 invalidateFilter();
742}
743
744bool QgsLayerTreeProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
745{
746 QgsLayerTreeNode *node = mLayerTreeModel->index2node( mLayerTreeModel->index( sourceRow, 0, sourceParent ) );
747 return nodeShown( node );
748}
749
750bool QgsLayerTreeProxyModel::nodeShown( QgsLayerTreeNode *node ) const
751{
752 if ( !node )
753 return true;
754
755 if ( node->nodeType() == QgsLayerTreeNode::NodeGroup )
756 {
757 return true;
758 }
759 else
760 {
761 QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer();
762 if ( !layer )
763 return true;
764 if ( !mFilterText.isEmpty() && !layer->name().contains( mFilterText, Qt::CaseInsensitive ) )
765 return false;
766 if ( ! mShowPrivateLayers && layer->flags().testFlag( QgsMapLayer::LayerFlag::Private ) )
767 {
768 return false;
769 }
770 return true;
771 }
772}
773
775{
776 return mShowPrivateLayers;
777}
778
780{
781 mShowPrivateLayers = showPrivate;
782 invalidateFilter();
783}
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition: qgis.h:115
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:2304
static QgsLayerTreeEmbeddedWidgetRegistry * layerTreeEmbeddedWidgetRegistry()
Returns the global layer tree embedded widget registry, used for registering widgets that may be embe...
Definition: qgsgui.cpp:118
Provider interface to be implemented in order to introduce new kinds of embedded widgets for use in l...
Layer tree group node serves as a container for layers and further groups.
QgsLayerTreeLayer * findLayer(QgsMapLayer *layer) const
Find layer node representing the map layer.
Layer tree node points to a map layer.
QgsMapLayer * layer() const
Returns the map layer associated with this node.
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
virtual QVariant data(int role) const =0
Returns data associated with the item. Must be implemented in derived class.
@ ParentRuleKeyRole
Rule key of the parent legend node - for legends with tree hierarchy (QString). Added in 2....
@ RuleKeyRole
Rule key of the node (QString)
QgsLayerTreeLayer * layerNode() const
Returns pointer to the parent layer node.
The QgsLayerTreeModel class is model implementation for Qt item views framework.
QModelIndex node2index(QgsLayerTreeNode *node) const
Returns index for a given node. If the node does not belong to the layer tree, the result is undefine...
QList< QgsLayerTreeModelLegendNode * > layerLegendNodes(QgsLayerTreeLayer *nodeLayer, bool skipNodeEmbeddedInParent=false)
Returns filtered list of active legend nodes attached to a particular layer node (by default it retur...
QModelIndex legendNode2index(QgsLayerTreeModelLegendNode *legendNode)
Returns index for a given legend node.
Qt::ItemFlags flags(const QModelIndex &index) const override
void setCurrentIndex(const QModelIndex &currentIndex)
Sets index of the current item. May be used by view. Item marked as current is underlined.
void setFlags(QgsLayerTreeModel::Flags f)
Sets OR-ed combination of model flags.
QgsLayerTree * rootGroup() const
Returns pointer to the root node of the layer tree. Always a non nullptr value.
QgsLayerTreeNode * index2node(const QModelIndex &index) const
Returns layer tree node for given index.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void messageEmitted(const QString &message, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=5)
Emits a message than can be displayed to the user in a GUI class.
QList< QgsLayerTreeNode * > indexes2nodes(const QModelIndexList &list, bool skipInternal=false) const
Convert a list of indexes to a list of layer tree nodes.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
static QgsLayerTreeModelLegendNode * index2legendNode(const QModelIndex &index)
Returns legend node for given index.
void refreshLayerLegend(QgsLayerTreeLayer *nodeLayer)
Force a refresh of legend nodes of a layer node.
@ ActionHierarchical
Check/uncheck action has consequences on children (or parents for leaf node)
@ UseEmbeddedWidgets
Layer nodes may optionally include extra embedded widgets (if used in QgsLayerTreeView)....
This class is a base class for nodes in a layer tree.
@ NodeGroup
Container of other groups and layers.
void setCustomProperty(const QString &key, const QVariant &value)
Sets a custom property for the node. Properties are stored in a map and saved in project file.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer. Properties are stored in a map and saved in project file.
void setExpanded(bool expanded)
Sets whether the node should be shown as expanded or collapsed in GUI.
virtual QString name() const =0
Returns name of the node.
QgsLayerTreeNode * parent()
Gets pointer to the parent. If parent is nullptr, the node is a root node.
NodeType nodeType() const
Find out about type of the node. It is usually shorter to use convenience functions from QgsLayerTree...
void customPropertyChanged(QgsLayerTreeNode *node, const QString &key)
Emitted when a custom property of a node within the tree has been changed or removed.
bool isExpanded() const
Returns whether the node should be shown as expanded or collapsed in GUI.
void setItemVisibilityChecked(bool checked)
Check or uncheck a node (independently of its ancestors or children)
void expandedChanged(QgsLayerTreeNode *node, bool expanded)
Emitted when the collapsed/expanded state of a node within the tree has been changed.
The QgsLayerTreeProxyModel class is a proxy model for QgsLayerTreeModel, supports private layers and ...
bool showPrivateLayers() const
Returns if private layers are shown.
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
void setFilterText(const QString &filterText=QString())
Sets filter to filterText.
void setShowPrivateLayers(bool showPrivate)
Determines if private layers are shown.
QgsLayerTreeProxyModel(QgsLayerTreeModel *treeModel, QObject *parent)
Constructs QgsLayerTreeProxyModel with source model treeModel and a parent.
static QSet< QgsMapLayer * > collectMapLayersRecursive(const QList< QgsLayerTreeNode * > &nodes)
Returns map layers from the given list of layer tree nodes.
The QgsLayerTreeViewDefaultActions class serves as a factory of actions that can be used together wit...
Indicator that can be used in a layer tree view to display icons next to items of the layer tree.
void changed()
Emitted when the indicator changes state (e.g.
Implementation of this interface can be implemented to allow QgsLayerTreeView instance to provide cus...
virtual QMenu * createContextMenu()=0
Returns a newly created menu instance (or nullptr on error)
void expandAllNodes()
Enhancement of QTreeView::expandAll() that also records expanded state in layer tree nodes.
QList< QgsLayerTreeViewIndicator * > indicators(QgsLayerTreeNode *node) const
Returns list of indicators associated with a particular layer tree node.
void currentLayerChanged(QgsMapLayer *layer)
Emitted when a current layer is changed.
void collapseAllNodes()
Enhancement of QTreeView::collapseAll() that also records expanded state in layer tree nodes.
QModelIndex legendNode2index(QgsLayerTreeModelLegendNode *legendNode)
Returns proxy model index for a given legend node.
QgsLayerTreeViewDefaultActions * defaultActions()
Gets access to the default actions that may be used with the tree view.
QString mCurrentLayerID
Keeps track of current layer ID (to check when to emit signal about change of current layer)
void setModel(QAbstractItemModel *model) override
Overridden setModel() from base class. Only QgsLayerTreeModel is an acceptable model.
QHash< QgsLayerTreeNode *, QList< QgsLayerTreeViewIndicator * > > mIndicators
Storage of indicators used with the tree view.
QList< QgsLayerTreeLayer * > selectedLayerNodes() const
Returns list of selected nodes filtered to just layer nodes.
void removeIndicator(QgsLayerTreeNode *node, QgsLayerTreeViewIndicator *indicator)
Removes a previously added indicator to a layer tree node.
void refreshLayerSymbology(const QString &layerId)
Force refresh of layer symbology. Normally not needed as the changes of layer's renderer are monitore...
void dropEvent(QDropEvent *event) override
QgsLayerTreeView(QWidget *parent=nullptr)
Constructor for QgsLayerTreeView.
QgsMapLayer * currentLayer() const
Returns the currently selected layer, or nullptr if no layers is selected.
QgsLayerTreeViewMenuProvider * menuProvider() const
Returns pointer to the context menu provider. May be nullptr.
void onExpandedChanged(QgsLayerTreeNode *node, bool expanded)
QgsLayerTreeNode * index2node(const QModelIndex &index) const
Returns layer tree node for given proxy model tree index.
void resizeEvent(QResizeEvent *event) override
QList< QgsMapLayer * > selectedLayersRecursive() const
Gets list of selected layers, including those that are not directly selected, but their ancestor grou...
void mouseReleaseEvent(QMouseEvent *event) override
void updateExpandedStateFromNode(QgsLayerTreeNode *node)
QgsLayerTreeModelLegendNode * currentLegendNode() const
Gets current legend node.
QgsLayerTreeModel * layerTreeModel() const
Gets access to the model casted to QgsLayerTreeModel.
void setMenuProvider(QgsLayerTreeViewMenuProvider *menuProvider)
Sets provider for context menu. Takes ownership of the instance.
bool showPrivateLayers()
Returns the show private layers status.
void setLayerVisible(QgsMapLayer *layer, bool visible)
Convenience methods which sets the visible state of the specified map layer.
QModelIndex node2sourceIndex(QgsLayerTreeNode *node) const
Returns source model index for a given node.
QgsMapLayer * layerForIndex(const QModelIndex &index) const
QPoint mLastReleaseMousePos
Used by the item delegate for identification of which indicator has been clicked.
friend class QgsLayerTreeViewItemDelegate
void updateExpandedStateToNode(const QModelIndex &index)
QgsLayerTreeProxyModel * proxyModel() const
Returns the proxy model used by the view.
QgsLayerTreeViewMenuProvider * mMenuProvider
Context menu provider. Owned by the view.
QgsLayerTreeModelLegendNode * index2legendNode(const QModelIndex &index) const
Returns legend node for given proxy model tree index.
void contextMenuEvent(QContextMenuEvent *event) override
void keyPressEvent(QKeyEvent *event) override
void setMessageBar(QgsMessageBar *messageBar)
Set the message bar to display messages from the layer tree.
void addIndicator(QgsLayerTreeNode *node, QgsLayerTreeViewIndicator *indicator)
Adds an indicator to the given layer tree node.
void modelRowsInserted(const QModelIndex &index, int start, int end)
QList< QgsLayerTreeNode * > selectedNodes(bool skipInternal=false) const
Returns list of selected nodes.
void setLayerMarkWidth(int width)
Set width of contextual menu mark, at right of layer node items.
QModelIndex node2index(QgsLayerTreeNode *node) const
Returns proxy model index for a given node.
void setCurrentLayer(QgsMapLayer *layer)
Sets the currently selected layer.
void setShowPrivateLayers(bool showPrivate)
Set the show private layers to showPrivate.
QgsLayerTreeNode * currentNode() const
Gets current node. May be nullptr.
~QgsLayerTreeView() override
QgsLayerTreeGroup * currentGroupNode() const
Gets current group node. If a layer is current node, the function will return parent group....
QgsLayerTreeViewDefaultActions * mDefaultActions
helper class with default actions. Lazily initialized.
QList< QgsMapLayer * > selectedLayers() const
Gets list of selected layers.
QModelIndex legendNode2sourceIndex(QgsLayerTreeModelLegendNode *legendNode)
Returns index for a given legend node.
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:75
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:53
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:43
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
Definition: qgslayertree.h:64
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString name
Definition: qgsmaplayer.h:76
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
QgsLayerTreeModelLegendNode * legendNode(const QString &rule, QgsLayerTreeModel &model)