QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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 
23  : QTreeView( parent )
24  , mSettingsSection( QStringLiteral( "browser" ) )
25 {
26  setEditTriggers( QAbstractItemView::EditKeyPressed );
27  setIndentation( QgsGuiUtils::scaleIconSize( 16 ) );
28 }
29 
30 void QgsBrowserTreeView::setModel( QAbstractItemModel *model )
31 {
32 
33  QTreeView::setModel( model );
34 
35  restoreState();
36 }
37 
39 {
40  mBrowserModel = model;
41 }
42 
43 void QgsBrowserTreeView::showEvent( QShowEvent *e )
44 {
45  Q_UNUSED( e )
46  if ( model() )
47  restoreState();
48  QTreeView::showEvent( e );
49 }
50 
51 // closeEvent is not called when application is closed
52 void QgsBrowserTreeView::hideEvent( QHideEvent *e )
53 {
54  Q_UNUSED( e )
55  // hideEvent() may be called (Mac) before showEvent
56  if ( model() )
57  saveState();
58  QTreeView::hideEvent( e );
59 }
60 
61 void QgsBrowserTreeView::saveState()
62 {
63  QgsSettings settings;
64  QStringList expandedPaths = expandedPathsList( QModelIndex() );
65  settings.setValue( expandedPathsKey(), expandedPaths );
66  QgsDebugMsgLevel( "expandedPaths = " + expandedPaths.join( ' ' ), 4 );
67 }
68 
69 void QgsBrowserTreeView::restoreState()
70 {
71  QgsSettings settings;
72  mExpandPaths = settings.value( expandedPathsKey(), QVariant() ).toStringList();
73 
74  QgsDebugMsgLevel( "mExpandPaths = " + mExpandPaths.join( ' ' ), 4 );
75  if ( !mExpandPaths.isEmpty() )
76  {
77  QSet<QModelIndex> expandIndexSet;
78  const auto constMExpandPaths = mExpandPaths;
79  for ( const QString &path : constMExpandPaths )
80  {
81  QModelIndex expandIndex = QgsBrowserGuiModel::findPath( model(), path, Qt::MatchStartsWith );
82  if ( expandIndex.isValid() )
83  {
84  QModelIndex modelIndex = browserModel()->findPath( path, Qt::MatchExactly );
85  if ( modelIndex.isValid() )
86  {
87  QgsDataItem *ptr = browserModel()->dataItem( modelIndex );
88  if ( ptr && ( ptr->capabilities2() & QgsDataItem::Capability::Collapse ) )
89  {
90  QgsDebugMsgLevel( "do not expand index for path " + path, 4 );
91  QModelIndex parentIndex = model()->parent( expandIndex );
92  // Still we need to store the parent in order to expand it
93  if ( parentIndex.isValid() )
94  expandIndexSet.insert( parentIndex );
95  }
96  else
97  {
98  expandIndexSet.insert( expandIndex );
99  }
100  }
101  }
102  else
103  {
104  QgsDebugMsgLevel( "index for path " + path + " not found", 4 );
105  }
106  }
107  const auto constExpandIndexSet = expandIndexSet;
108  for ( const QModelIndex &expandIndex : constExpandIndexSet )
109  {
110  expandTree( expandIndex );
111  }
112  }
113 
114  // expand root favorites item
115  QModelIndex index = QgsBrowserGuiModel::findPath( model(), QStringLiteral( "favorites:" ) );
116  expand( index );
117 }
118 
119 void QgsBrowserTreeView::expandTree( const QModelIndex &index )
120 {
121  if ( !model() )
122  return;
123 
124  QgsDebugMsgLevel( "itemPath = " + model()->data( index, QgsBrowserGuiModel::PathRole ).toString(), 4 );
125 
126  expand( index );
127  QModelIndex parentIndex = model()->parent( index );
128  if ( parentIndex.isValid() )
129  expandTree( parentIndex );
130 }
131 
132 bool QgsBrowserTreeView::treeExpanded( const QModelIndex &index )
133 {
134  if ( !model() )
135  return false;
136  if ( !isExpanded( index ) )
137  return false;
138  QModelIndex parentIndex = model()->parent( index );
139  if ( parentIndex.isValid() )
140  return treeExpanded( parentIndex );
141 
142  return true; // root
143 }
144 
145 bool QgsBrowserTreeView::hasExpandedDescendant( const QModelIndex &index ) const
146 {
147  if ( !model() || !index.isValid() )
148  return false;
149 
150  for ( int i = 0; i < model()->rowCount( index ); i++ )
151  {
152  QModelIndex childIndex = model()->index( i, 0, index );
153  if ( isExpanded( childIndex ) )
154  return true;
155 
156  if ( hasExpandedDescendant( childIndex ) )
157  return true;
158  }
159  return false;
160 }
161 
162 // rowsInserted signal is used to continue in state restoring
163 void QgsBrowserTreeView::rowsInserted( const QModelIndex &parentIndex, int start, int end )
164 {
165  QTreeView::rowsInserted( parentIndex, start, end );
166 
167  if ( !model() )
168  return;
169 
170  if ( mExpandPaths.isEmpty() )
171  return;
172 
173  QgsDebugMsgLevel( "mExpandPaths = " + mExpandPaths.join( ',' ), 2 );
174 
175  QString parentPath = model()->data( parentIndex, QgsBrowserGuiModel::PathRole ).toString();
176  QgsDebugMsgLevel( "parentPath = " + parentPath, 2 );
177 
178  // remove parentPath from paths to be expanded
179  mExpandPaths.removeOne( parentPath );
180 
181  // Remove the subtree from mExpandPaths if user collapsed the item in the meantime
182  if ( !treeExpanded( parentIndex ) )
183  {
184  const auto constMExpandPaths = mExpandPaths;
185  for ( const QString &path : constMExpandPaths )
186  {
187  if ( path.startsWith( parentPath + '/' ) )
188  mExpandPaths.removeOne( path );
189  }
190  return;
191  }
192 
193  for ( int i = start; i <= end; i++ )
194  {
195  QModelIndex childIndex = model()->index( i, 0, parentIndex );
196  QString childPath = model()->data( childIndex, QgsBrowserGuiModel::PathRole ).toString();
197  QString escapedChildPath = childPath;
198  escapedChildPath.replace( '|', QLatin1String( "\\|" ) );
199 
200  QgsDebugMsgLevel( "childPath = " + childPath + " escapedChildPath = " + escapedChildPath, 2 );
201  if ( mExpandPaths.contains( childPath ) || mExpandPaths.indexOf( QRegExp( "^" + escapedChildPath + "/.*" ) ) != -1 )
202  {
203  QgsDebugMsgLevel( QStringLiteral( "-> expand" ), 2 );
204  QModelIndex modelIndex = browserModel()->findPath( childPath, Qt::MatchExactly );
205  if ( modelIndex.isValid() )
206  {
207  QgsDataItem *ptr = browserModel()->dataItem( modelIndex );
208  if ( !ptr || !( ptr->capabilities2() & QgsDataItem::Capability::Collapse ) )
209  {
210  expand( childIndex );
211  }
212  }
213  }
214  }
215 }
216 
217 QString QgsBrowserTreeView::expandedPathsKey() const
218 {
219  return '/' + mSettingsSection + "/expandedPaths";
220 }
221 
222 QStringList QgsBrowserTreeView::expandedPathsList( const QModelIndex &index )
223 {
224  QStringList paths;
225 
226  if ( !model() )
227  return paths;
228 
229  for ( int i = 0; i < model()->rowCount( index ); i++ )
230  {
231  QModelIndex childIndex = model()->index( i, 0, index );
232  if ( isExpanded( childIndex ) )
233  {
234  QStringList childrenPaths = expandedPathsList( childIndex );
235  if ( !childrenPaths.isEmpty() )
236  {
237  paths.append( childrenPaths );
238  }
239  else
240  {
241  paths.append( model()->data( childIndex, QgsBrowserGuiModel::PathRole ).toString() );
242  }
243  }
244  }
245  return paths;
246 }
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:52
virtual Capabilities capabilities2() const
Returns the capabilities for the data item.
Definition: qgsdataitem.h:323
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
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