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