QGIS API Documentation  3.6.0-Noosa (5873452)
qgsdatasourceselectdialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdatasourceselectdialog.cpp - QgsDataSourceSelectDialog
3 
4  ---------------------
5  begin : 1.11.2018
6  copyright : (C) 2018 by Alessandro Pasotti
7  email : [email protected]
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
18 #include "ui_qgsdatasourceselectdialog.h"
19 #include "qgssettings.h"
20 #include "qgsgui.h"
21 #include "qgis.h"
22 #include "qgsbrowsermodel.h"
23 
24 #include <QPushButton>
25 #include <QMenu>
26 
28  QgsBrowserModel *browserModel,
29  bool setFilterByLayerType,
30  const QgsMapLayer::LayerType &layerType,
31  QWidget *parent )
32  : QDialog( parent )
33 {
34  if ( ! browserModel )
35  {
36  mBrowserModel = qgis::make_unique<QgsBrowserModel>();
37  mBrowserModel->initialize();
38  mOwnModel = true;
39  }
40  else
41  {
42  mBrowserModel.reset( browserModel );
43  mOwnModel = false;
44  }
45 
46  setupUi( this );
47  setWindowTitle( tr( "Select a Data Source" ) );
49 
50  mBrowserProxyModel.setBrowserModel( mBrowserModel.get() );
51  mBrowserTreeView->setHeaderHidden( true );
52 
53  if ( setFilterByLayerType )
54  {
55  // This will also set the (proxy) model
56  setLayerTypeFilter( layerType );
57  }
58  else
59  {
60  mBrowserTreeView->setModel( &mBrowserProxyModel );
61  buttonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( false );
62  }
63 
64  mBrowserTreeView->setBrowserModel( mBrowserModel.get() );
65 
66  mWidgetFilter->hide();
67  mLeFilter->setPlaceholderText( tr( "Type here to filter visible items…" ) );
68  // icons from http://www.fatcow.com/free-icons License: CC Attribution 3.0
69 
70  QMenu *menu = new QMenu( this );
71  menu->setSeparatorsCollapsible( false );
72  mBtnFilterOptions->setMenu( menu );
73  QAction *action = new QAction( tr( "Case Sensitive" ), menu );
74  action->setData( "case" );
75  action->setCheckable( true );
76  action->setChecked( false );
77  connect( action, &QAction::toggled, this, &QgsDataSourceSelectDialog::setCaseSensitive );
78  menu->addAction( action );
79  QActionGroup *group = new QActionGroup( menu );
80  action = new QAction( tr( "Filter Pattern Syntax" ), group );
81  action->setSeparator( true );
82  menu->addAction( action );
83  action = new QAction( tr( "Normal" ), group );
84  action->setData( QgsBrowserProxyModel::Normal );
85  action->setCheckable( true );
86  action->setChecked( true );
87  menu->addAction( action );
88  action = new QAction( tr( "Wildcard(s)" ), group );
89  action->setData( QgsBrowserProxyModel::Wildcards );
90  action->setCheckable( true );
91  menu->addAction( action );
92  action = new QAction( tr( "Regular Expression" ), group );
93  action->setData( QgsBrowserProxyModel::RegularExpression );
94  action->setCheckable( true );
95  menu->addAction( action );
96 
97  mBrowserTreeView->setExpandsOnDoubleClick( false );
98 
99  connect( mActionRefresh, &QAction::triggered, this, [ = ] { refreshModel( QModelIndex() ); } );
100  connect( mBrowserTreeView, &QgsBrowserTreeView::clicked, this, &QgsDataSourceSelectDialog::onLayerSelected );
101  connect( mActionCollapse, &QAction::triggered, mBrowserTreeView, &QgsBrowserTreeView::collapseAll );
102  connect( mActionShowFilter, &QAction::triggered, this, &QgsDataSourceSelectDialog::showFilterWidget );
103  connect( mLeFilter, &QgsFilterLineEdit::returnPressed, this, &QgsDataSourceSelectDialog::setFilter );
105  connect( mLeFilter, &QgsFilterLineEdit::textChanged, this, &QgsDataSourceSelectDialog::setFilter );
106  connect( group, &QActionGroup::triggered, this, &QgsDataSourceSelectDialog::setFilterSyntax );
107 
108  if ( QgsSettings().value( QStringLiteral( "datasourceSelectFilterVisible" ), false, QgsSettings::Section::Gui ).toBool() )
109  {
110  mActionShowFilter->trigger();
111  }
112 }
113 
115 {
116  if ( ! mOwnModel )
117  mBrowserModel.release();
118 }
119 
120 
122 {
123  QDialog::showEvent( e );
124  QString lastSelectedPath( QgsSettings().value( QStringLiteral( "datasourceSelectLastSelectedItem" ),
125  QString(), QgsSettings::Section::Gui ).toString() );
126  if ( ! lastSelectedPath.isEmpty() )
127  {
128  QModelIndexList items = mBrowserProxyModel.match(
129  mBrowserProxyModel.index( 0, 0 ),
131  QVariant::fromValue( lastSelectedPath ),
132  1,
133  Qt::MatchRecursive );
134  if ( items.count( ) > 0 )
135  {
136  QModelIndex expandIndex = items.at( 0 );
137  if ( expandIndex.isValid() )
138  {
139  mBrowserTreeView->scrollTo( expandIndex, QgsBrowserTreeView::ScrollHint::PositionAtTop );
140  mBrowserTreeView->expand( expandIndex );
141  }
142  }
143  }
144 }
145 
147 {
148  QgsSettings().setValue( QStringLiteral( "datasourceSelectFilterVisible" ), visible, QgsSettings::Section::Gui );
149  mWidgetFilter->setVisible( visible );
150  if ( ! visible )
151  {
152  mLeFilter->setText( QString() );
153  setFilter();
154  }
155  else
156  {
157  mLeFilter->setFocus();
158  }
159 }
160 
162 {
163  QString filter = mLeFilter->text();
164  mBrowserProxyModel.setFilterString( filter );
165 }
166 
167 
168 void QgsDataSourceSelectDialog::refreshModel( const QModelIndex &index )
169 {
170 
171  QgsDataItem *item = mBrowserModel->dataItem( index );
172  if ( item )
173  {
174  QgsDebugMsg( "path = " + item->path() );
175  }
176  else
177  {
178  QgsDebugMsg( QStringLiteral( "invalid item" ) );
179  }
180 
181  if ( item && ( item->capabilities2() & QgsDataItem::Fertile ) )
182  {
183  mBrowserModel->refresh( index );
184  }
185 
186  for ( int i = 0; i < mBrowserModel->rowCount( index ); i++ )
187  {
188  QModelIndex idx = mBrowserModel->index( i, 0, index );
189  QModelIndex proxyIdx = mBrowserProxyModel.mapFromSource( idx );
190  QgsDataItem *child = mBrowserModel->dataItem( idx );
191 
192  // Check also expanded descendants so that the whole expanded path does not get collapsed if one item is collapsed.
193  // Fast items (usually root items) are refreshed so that when collapsed, it is obvious they are if empty (no expand symbol).
194  if ( mBrowserTreeView->isExpanded( proxyIdx ) || mBrowserTreeView->hasExpandedDescendant( proxyIdx ) || ( child && child->capabilities2() & QgsDataItem::Fast ) )
195  {
196  refreshModel( idx );
197  }
198  else
199  {
200  if ( child && ( child->capabilities2() & QgsDataItem::Fertile ) )
201  {
202  child->depopulate();
203  }
204  }
205  }
206 }
207 
208 
210 {
211  if ( !action )
212  return;
213  mBrowserProxyModel.setFilterSyntax( static_cast< QgsBrowserProxyModel::FilterSyntax >( action->data().toInt() ) );
214 }
215 
217 {
218  mBrowserProxyModel.setFilterCaseSensitivity( caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
219 }
220 
222 {
223  mBrowserProxyModel.setFilterByLayerType( true );
224  mBrowserProxyModel.setLayerType( layerType );
225  // reset model and button
226  mBrowserTreeView->setModel( &mBrowserProxyModel );
227  buttonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( false );
228 }
229 
231 {
232  return mUri;
233 }
234 
235 void QgsDataSourceSelectDialog::onLayerSelected( const QModelIndex &index )
236 {
237  bool isLayerCompatible = false;
238  mUri = QgsMimeDataUtils::Uri();
239  if ( index.isValid() )
240  {
241  const QgsDataItem *dataItem( mBrowserProxyModel.dataItem( index ) );
242  if ( dataItem )
243  {
244  const QgsLayerItem *layerItem = qobject_cast<const QgsLayerItem *>( dataItem );
245  if ( layerItem && ( ! mBrowserProxyModel.filterByLayerType() ||
246  ( layerItem->mapLayerType() == mBrowserProxyModel.layerType() ) ) )
247  {
248  isLayerCompatible = true;
249  mUri = layerItem->mimeUri();
250  // Store last viewed item
251  QgsSettings().setValue( QStringLiteral( "datasourceSelectLastSelectedItem" ), mBrowserProxyModel.data( index, QgsBrowserModel::PathRole ).toString(), QgsSettings::Section::Gui );
252  }
253  }
254  }
255  buttonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( isLayerCompatible );
256 }
257 
QgsMimeDataUtils::Uri uri() const
Returns the (possibly invalid) uri of the selected data source.
QString path() const
Definition: qgsdataitem.h:293
void setFilterSyntax(QAction *)
Sets filter syntax.
void setLayerType(QgsMapLayer::LayerType type)
Sets the layer type to filter the model by.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
QgsMapLayer::LayerType mapLayerType() const
Returns QgsMapLayer::LayerType.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
void setFilter()
Apply filter to the model.
void setLayerTypeFilter(QgsMapLayer::LayerType layerType)
Sets layer type filter to layerType and activates the filtering.
void setBrowserModel(QgsBrowserModel *model)
Sets the underlying browser model.
virtual void depopulate()
Remove children recursively and set as not populated. This is used when refreshing collapsed items...
void setFilterSyntax(FilterSyntax syntax)
Sets the filter syntax.
QgsDataSourceSelectDialog(QgsBrowserModel *browserModel=nullptr, bool setFilterByLayerType=false, const QgsMapLayer::LayerType &layerType=QgsMapLayer::LayerType::VectorLayer, QWidget *parent=nullptr)
Constructs a QgsDataSourceSelectDialog, optionally filtering by layer type.
Item path used to access path in the tree, see QgsDataItem::mPath.
void setCaseSensitive(bool caseSensitive)
Sets filter case sensitivity.
void showEvent(QShowEvent *e) override
Scroll to last selected index and expand it&#39;s children.
LayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:106
void setFilterString(const QString &filter)
Sets the filter string to use when filtering items in the model.
QgsMapLayer::LayerType layerType() const
Returns the layer type to filter the model by.
void setFilterCaseSensitivity(Qt::CaseSensitivity sensitivity)
Sets whether item filtering should be case sensitive.
bool filterByLayerType() const
Returns true if the model is filtered by map layer type.
Base class for all items in the model.
Definition: qgsdataitem.h:49
Can create children. Even items without this capability may have children, but cannot create them...
Definition: qgsdataitem.h:211
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
QgsMimeDataUtils::Uri mimeUri() const override
Returns mime URI for the data item.
void cleared()
Emitted when the widget is cleared.
Standard string filtering.
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition: qgsgui.cpp:104
void showFilterWidget(bool visible)
Show/hide filter widget.
A model for showing available data sources and other items in a structured tree.
Item that represents a layer that can be opened with one of the providers.
Definition: qgsdataitem.h:436
void setFilterByLayerType(bool enabled)
Sets whether the model is filtered by map layer type.
QgsDataItem * dataItem(const QModelIndex &index) const
Returns the data item at the specified proxy index, or a nullptr if no item exists at the index...
CreateChildren() is fast enough to be run in main thread when refreshing items, most root items (wms...
Definition: qgsdataitem.h:212
virtual Capabilities capabilities2() const
Returns the capabilities for the data item.
Definition: qgsdataitem.h:249