QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsbrowsertreeview.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsbrowsertreeview.cpp
3  --------------------------------------
4  Date : January 2015
5  Copyright : (C) 2015 by Radim Blazek
6  Email : [email protected]
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 "qgssettings.h"
17 #include "qgsbrowserguimodel.h"
18 #include "qgsbrowsertreeview.h"
19 #include "qgslogger.h"
20 #include "qgsguiutils.h"
21 #include "qgsdataitem.h"
22 
24  : QTreeView( parent )
25  , mSettingsSection( QStringLiteral( "browser" ) )
26 {
27  setEditTriggers( QAbstractItemView::EditKeyPressed );
28  setIndentation( QgsGuiUtils::scaleIconSize( 16 ) );
29 }
30 
31 void QgsBrowserTreeView::setModel( QAbstractItemModel *model )
32 {
33 
34  QTreeView::setModel( model );
35 
36  restoreState();
37 }
38 
40 {
41  mBrowserModel = model;
42 }
43 
44 void QgsBrowserTreeView::showEvent( QShowEvent *e )
45 {
46  Q_UNUSED( e )
47  if ( model() )
48  restoreState();
49  QTreeView::showEvent( e );
50 }
51 
52 // closeEvent is not called when application is closed
53 void QgsBrowserTreeView::hideEvent( QHideEvent *e )
54 {
55  Q_UNUSED( e )
56  // hideEvent() may be called (Mac) before showEvent
57  if ( model() )
58  saveState();
59  QTreeView::hideEvent( e );
60 }
61 
62 void QgsBrowserTreeView::saveState()
63 {
64  QgsSettings settings;
65  QStringList expandedPaths = expandedPathsList( QModelIndex() );
66  settings.setValue( expandedPathsKey(), expandedPaths );
67  QgsDebugMsgLevel( "expandedPaths = " + expandedPaths.join( ' ' ), 4 );
68 }
69 
70 void QgsBrowserTreeView::restoreState()
71 {
72  QgsSettings settings;
73  mExpandPaths = settings.value( expandedPathsKey(), QVariant() ).toStringList();
74 
75  QgsDebugMsgLevel( "mExpandPaths = " + mExpandPaths.join( ' ' ), 4 );
76  if ( !mExpandPaths.isEmpty() )
77  {
78  QSet<QModelIndex> expandIndexSet;
79  const auto constMExpandPaths = mExpandPaths;
80  for ( const QString &path : constMExpandPaths )
81  {
82  QModelIndex expandIndex = QgsBrowserGuiModel::findPath( model(), path, Qt::MatchStartsWith );
83  if ( expandIndex.isValid() )
84  {
85  QModelIndex modelIndex = browserModel()->findPath( path, Qt::MatchExactly );
86  if ( modelIndex.isValid() )
87  {
88  QgsDataItem *ptr = browserModel()->dataItem( modelIndex );
89  if ( ptr && ( ptr->capabilities2() & Qgis::BrowserItemCapability::Collapse ) )
90  {
91  QgsDebugMsgLevel( "do not expand index for path " + path, 4 );
92  QModelIndex parentIndex = model()->parent( expandIndex );
93  // Still we need to store the parent in order to expand it
94  if ( parentIndex.isValid() )
95  expandIndexSet.insert( parentIndex );
96  }
97  else
98  {
99  expandIndexSet.insert( expandIndex );
100  }
101  }
102  }
103  else
104  {
105  QgsDebugMsgLevel( "index for path " + path + " not found", 4 );
106  }
107  }
108  const auto constExpandIndexSet = expandIndexSet;
109  for ( const QModelIndex &expandIndex : constExpandIndexSet )
110  {
111  expandTree( expandIndex );
112  }
113  }
114 
115  // expand root favorites item
116  QModelIndex index = QgsBrowserGuiModel::findPath( model(), QStringLiteral( "favorites:" ) );
117  expand( index );
118 }
119 
120 void QgsBrowserTreeView::expandTree( const QModelIndex &index )
121 {
122  if ( !model() )
123  return;
124 
125  QgsDebugMsgLevel( "itemPath = " + model()->data( index, QgsBrowserGuiModel::PathRole ).toString(), 4 );
126 
127  expand( index );
128  QModelIndex parentIndex = model()->parent( index );
129  if ( parentIndex.isValid() )
130  expandTree( parentIndex );
131 }
132 
133 bool QgsBrowserTreeView::treeExpanded( const QModelIndex &index )
134 {
135  if ( !model() )
136  return false;
137  if ( !isExpanded( index ) )
138  return false;
139  QModelIndex parentIndex = model()->parent( index );
140  if ( parentIndex.isValid() )
141  return treeExpanded( parentIndex );
142 
143  return true; // root
144 }
145 
146 bool QgsBrowserTreeView::hasExpandedDescendant( const QModelIndex &index ) const
147 {
148  if ( !model() || !index.isValid() )
149  return false;
150 
151  for ( int i = 0; i < model()->rowCount( index ); i++ )
152  {
153  QModelIndex childIndex = model()->index( i, 0, index );
154  if ( isExpanded( childIndex ) )
155  return true;
156 
157  if ( hasExpandedDescendant( childIndex ) )
158  return true;
159  }
160  return false;
161 }
162 
163 // rowsInserted signal is used to continue in state restoring
164 void QgsBrowserTreeView::rowsInserted( const QModelIndex &parentIndex, int start, int end )
165 {
166  QTreeView::rowsInserted( parentIndex, start, end );
167 
168  if ( !model() )
169  return;
170 
171  if ( mExpandPaths.isEmpty() )
172  return;
173 
174  QgsDebugMsgLevel( "mExpandPaths = " + mExpandPaths.join( ',' ), 2 );
175 
176  QString parentPath = model()->data( parentIndex, QgsBrowserGuiModel::PathRole ).toString();
177  QgsDebugMsgLevel( "parentPath = " + parentPath, 2 );
178 
179  // remove parentPath from paths to be expanded
180  mExpandPaths.removeOne( parentPath );
181 
182  // Remove the subtree from mExpandPaths if user collapsed the item in the meantime
183  if ( !treeExpanded( parentIndex ) )
184  {
185  const auto constMExpandPaths = mExpandPaths;
186  for ( const QString &path : constMExpandPaths )
187  {
188  if ( path.startsWith( parentPath + '/' ) )
189  mExpandPaths.removeOne( path );
190  }
191  return;
192  }
193 
194  for ( int i = start; i <= end; i++ )
195  {
196  QModelIndex childIndex = model()->index( i, 0, parentIndex );
197  QString childPath = model()->data( childIndex, QgsBrowserGuiModel::PathRole ).toString();
198  QString escapedChildPath = childPath;
199  escapedChildPath.replace( '|', QLatin1String( "\\|" ) );
200 
201  QgsDebugMsgLevel( "childPath = " + childPath + " escapedChildPath = " + escapedChildPath, 2 );
202  if ( mExpandPaths.contains( childPath ) || mExpandPaths.indexOf( QRegExp( "^" + escapedChildPath + "/.*" ) ) != -1 )
203  {
204  QgsDebugMsgLevel( QStringLiteral( "-> expand" ), 2 );
205  QModelIndex modelIndex = browserModel()->findPath( childPath, Qt::MatchExactly );
206  if ( modelIndex.isValid() )
207  {
208  QgsDataItem *ptr = browserModel()->dataItem( modelIndex );
209  if ( !ptr || !( ptr->capabilities2() & Qgis::BrowserItemCapability::Collapse ) )
210  {
211  expand( childIndex );
212  }
213  }
214  }
215  }
216 }
217 
218 QString QgsBrowserTreeView::expandedPathsKey() const
219 {
220  return '/' + mSettingsSection + "/expandedPaths";
221 }
222 
223 QStringList QgsBrowserTreeView::expandedPathsList( const QModelIndex &index )
224 {
225  QStringList paths;
226 
227  if ( !model() )
228  return paths;
229 
230  for ( int i = 0; i < model()->rowCount( index ); i++ )
231  {
232  QModelIndex childIndex = model()->index( i, 0, index );
233  if ( isExpanded( childIndex ) )
234  {
235  QStringList childrenPaths = expandedPathsList( childIndex );
236  if ( !childrenPaths.isEmpty() )
237  {
238  paths.append( childrenPaths );
239  }
240  else
241  {
242  paths.append( model()->data( childIndex, QgsBrowserGuiModel::PathRole ).toString() );
243  }
244  }
245  }
246  return paths;
247 }
@ Collapse
The collapse/expand status for this items children should be ignored in order to avoid undesired netw...
A model for showing available data sources and other items in a structured tree.
QgsDataItem * dataItem(const QModelIndex &idx) const
Returns the data item at the specified index, or nullptr if no item exists at the index.
QModelIndex findPath(const QString &path, Qt::MatchFlag matchFlag=Qt::MatchExactly)
Returns index of item with given path.
@ PathRole
Item path used to access path in the tree, see QgsDataItem::mPath.
void showEvent(QShowEvent *e) override
QgsBrowserTreeView(QWidget *parent=nullptr)
Constructor for QgsBrowserTreeView.
QgsBrowserGuiModel * browserModel()
Returns the browser model.
void setBrowserModel(QgsBrowserGuiModel *model)
Sets the browser model.
void setModel(QAbstractItemModel *model) override
void hideEvent(QHideEvent *e) override
bool hasExpandedDescendant(const QModelIndex &index) const
void rowsInserted(const QModelIndex &parentIndex, int start, int end) override
Base class for all items in the model.
Definition: qgsdataitem.h:46
virtual Qgis::BrowserItemCapabilities capabilities2() const
Returns the capabilities for the data item.
Definition: qgsdataitem.h:295
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39