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