QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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  Q_FOREACH ( const QString &path, mExpandPaths )
78  {
79  QModelIndex expandIndex = QgsBrowserModel::findPath( model(), path, Qt::MatchStartsWith );
80  if ( expandIndex.isValid() )
81  {
82  QModelIndex modelIndex = browserModel()->findPath( path, Qt::MatchExactly );
83  if ( modelIndex.isValid() )
84  {
85  QgsDataItem *ptr = browserModel()->dataItem( modelIndex );
86  if ( ptr && ( ptr->capabilities2() & QgsDataItem::Capability::Collapse ) )
87  {
88  QgsDebugMsgLevel( "do not expand index for path " + path, 4 );
89  QModelIndex parentIndex = model()->parent( expandIndex );
90  // Still we need to store the parent in order to expand it
91  if ( parentIndex.isValid() )
92  expandIndexSet.insert( parentIndex );
93  }
94  else
95  {
96  expandIndexSet.insert( expandIndex );
97  }
98  }
99  }
100  else
101  {
102  QgsDebugMsgLevel( "index for path " + path + " not found", 4 );
103  }
104  }
105  Q_FOREACH ( const QModelIndex &expandIndex, expandIndexSet )
106  {
107  expandTree( expandIndex );
108  }
109  }
110 
111  // expand root favorites item
112  QModelIndex index = QgsBrowserModel::findPath( model(), QStringLiteral( "favorites:" ) );
113  expand( index );
114 }
115 
116 void QgsBrowserTreeView::expandTree( const QModelIndex &index )
117 {
118  if ( !model() )
119  return;
120 
121  QgsDebugMsgLevel( "itemPath = " + model()->data( index, QgsBrowserModel::PathRole ).toString(), 4 );
122 
123  expand( index );
124  QModelIndex parentIndex = model()->parent( index );
125  if ( parentIndex.isValid() )
126  expandTree( parentIndex );
127 }
128 
129 bool QgsBrowserTreeView::treeExpanded( const QModelIndex &index )
130 {
131  if ( !model() )
132  return false;
133  if ( !isExpanded( index ) )
134  return false;
135  QModelIndex parentIndex = model()->parent( index );
136  if ( parentIndex.isValid() )
137  return treeExpanded( parentIndex );
138 
139  return true; // root
140 }
141 
142 bool QgsBrowserTreeView::hasExpandedDescendant( const QModelIndex &index ) const
143 {
144  if ( !model() || !index.isValid() )
145  return false;
146 
147  for ( int i = 0; i < model()->rowCount( index ); i++ )
148  {
149  QModelIndex childIndex = model()->index( i, 0, index );
150  if ( isExpanded( childIndex ) )
151  return true;
152 
153  if ( hasExpandedDescendant( childIndex ) )
154  return true;
155  }
156  return false;
157 }
158 
159 // rowsInserted signal is used to continue in state restoring
160 void QgsBrowserTreeView::rowsInserted( const QModelIndex &parentIndex, int start, int end )
161 {
162  QTreeView::rowsInserted( parentIndex, start, end );
163 
164  if ( !model() )
165  return;
166 
167  if ( mExpandPaths.isEmpty() )
168  return;
169 
170  QgsDebugMsgLevel( "mExpandPaths = " + mExpandPaths.join( ',' ), 2 );
171 
172  QString parentPath = model()->data( parentIndex, QgsBrowserModel::PathRole ).toString();
173  QgsDebugMsgLevel( "parentPath = " + parentPath, 2 );
174 
175  // remove parentPath from paths to be expanded
176  mExpandPaths.removeOne( parentPath );
177 
178  // Remove the subtree from mExpandPaths if user collapsed the item in the meantime
179  if ( !treeExpanded( parentIndex ) )
180  {
181  Q_FOREACH ( const QString &path, mExpandPaths )
182  {
183  if ( path.startsWith( parentPath + '/' ) )
184  mExpandPaths.removeOne( path );
185  }
186  return;
187  }
188 
189  for ( int i = start; i <= end; i++ )
190  {
191  QModelIndex childIndex = model()->index( i, 0, parentIndex );
192  QString childPath = model()->data( childIndex, QgsBrowserModel::PathRole ).toString();
193  QString escapedChildPath = childPath;
194  escapedChildPath.replace( '|', QLatin1String( "\\|" ) );
195 
196  QgsDebugMsgLevel( "childPath = " + childPath + " escapedChildPath = " + escapedChildPath, 2 );
197  if ( mExpandPaths.contains( childPath ) || mExpandPaths.indexOf( QRegExp( "^" + escapedChildPath + "/.*" ) ) != -1 )
198  {
199  QgsDebugMsgLevel( QStringLiteral( "-> expand" ), 2 );
200  QModelIndex modelIndex = browserModel()->findPath( childPath, Qt::MatchExactly );
201  if ( modelIndex.isValid() )
202  {
203  QgsDataItem *ptr = browserModel()->dataItem( modelIndex );
204  if ( !ptr || !( ptr->capabilities2() & QgsDataItem::Capability::Collapse ) )
205  {
206  expand( childIndex );
207  }
208  }
209  }
210  }
211 }
212 
213 QString QgsBrowserTreeView::expandedPathsKey() const
214 {
215  return '/' + mSettingsSection + "/expandedPaths";
216 }
217 
218 QStringList QgsBrowserTreeView::expandedPathsList( const QModelIndex &index )
219 {
220  QStringList paths;
221 
222  if ( !model() )
223  return paths;
224 
225  for ( int i = 0; i < model()->rowCount( index ); i++ )
226  {
227  QModelIndex childIndex = model()->index( i, 0, index );
228  if ( isExpanded( childIndex ) )
229  {
230  QStringList childrenPaths = expandedPathsList( childIndex );
231  if ( !childrenPaths.isEmpty() )
232  {
233  paths.append( childrenPaths );
234  }
235  else
236  {
237  paths.append( model()->data( childIndex, QgsBrowserModel::PathRole ).toString() );
238  }
239  }
240  }
241  return paths;
242 }
void setModel(QAbstractItemModel *model) override
void setBrowserModel(QgsBrowserModel *model)
Sets the browser model.
virtual Capabilities capabilities2() const
Returns the capabilities for the data item.
Definition: qgsdataitem.h:248
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
QModelIndex findPath(const QString &path, Qt::MatchFlag matchFlag=Qt::MatchExactly)
Returns index of item with given path.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
QgsBrowserTreeView(QWidget *parent=nullptr)
Constructor for QgsBrowserTreeView.
Item path used to access path in the tree, see QgsDataItem::mPath.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsDataItem * dataItem(const QModelIndex &idx) const
Returns the data item at the specified index, or a 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
bool hasExpandedDescendant(const QModelIndex &index) const
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.