QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 
20 #include "qgis.h"
21 #include "qgsbrowsermodel.h"
22 #include "qgsgui.h"
23 #include "qgsguiutils.h"
24 #include "qgssettings.h"
25 
26 #include <QPushButton>
27 #include <QMenu>
28 
30  QgsBrowserModel *browserModel,
31  bool setFilterByLayerType,
32  QgsMapLayerType layerType,
33  QWidget *parent )
34  : QDialog( parent )
35 {
36  if ( ! browserModel )
37  {
38  mBrowserModel = qgis::make_unique<QgsBrowserModel>();
39  mBrowserModel->initialize();
40  mOwnModel = true;
41  }
42  else
43  {
44  mBrowserModel.reset( browserModel );
45  mOwnModel = false;
46  }
47 
48  setupUi( this );
49  setWindowTitle( tr( "Select a Data Source" ) );
51 
52  mBrowserProxyModel.setBrowserModel( mBrowserModel.get() );
53  mBrowserTreeView->setHeaderHidden( true );
54 
55  if ( setFilterByLayerType )
56  {
57  // This will also set the (proxy) model
58  setLayerTypeFilter( layerType );
59  }
60  else
61  {
62  mBrowserTreeView->setModel( &mBrowserProxyModel );
63  buttonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( false );
64  }
65 
66  mBrowserTreeView->setBrowserModel( mBrowserModel.get() );
67 
68  mWidgetFilter->hide();
69  mLeFilter->setPlaceholderText( tr( "Type here to filter visible items…" ) );
70  // icons from http://www.fatcow.com/free-icons License: CC Attribution 3.0
71 
72  QMenu *menu = new QMenu( this );
73  menu->setSeparatorsCollapsible( false );
74  mBtnFilterOptions->setMenu( menu );
75  QAction *action = new QAction( tr( "Case Sensitive" ), menu );
76  action->setData( "case" );
77  action->setCheckable( true );
78  action->setChecked( false );
79  connect( action, &QAction::toggled, this, &QgsDataSourceSelectDialog::setCaseSensitive );
80  menu->addAction( action );
81  QActionGroup *group = new QActionGroup( menu );
82  action = new QAction( tr( "Filter Pattern Syntax" ), group );
83  action->setSeparator( true );
84  menu->addAction( action );
85  action = new QAction( tr( "Normal" ), group );
86  action->setData( QgsBrowserProxyModel::Normal );
87  action->setCheckable( true );
88  action->setChecked( true );
89  menu->addAction( action );
90  action = new QAction( tr( "Wildcard(s)" ), group );
91  action->setData( QgsBrowserProxyModel::Wildcards );
92  action->setCheckable( true );
93  menu->addAction( action );
94  action = new QAction( tr( "Regular Expression" ), group );
95  action->setData( QgsBrowserProxyModel::RegularExpression );
96  action->setCheckable( true );
97  menu->addAction( action );
98 
99  mBrowserTreeView->setExpandsOnDoubleClick( false );
100 
101  connect( mActionRefresh, &QAction::triggered, this, [ = ] { refreshModel( QModelIndex() ); } );
102  connect( mBrowserTreeView, &QgsBrowserTreeView::clicked, this, &QgsDataSourceSelectDialog::onLayerSelected );
103  connect( mBrowserTreeView, &QgsBrowserTreeView::doubleClicked, this, &QgsDataSourceSelectDialog::itemDoubleClicked );
104  connect( mActionCollapse, &QAction::triggered, mBrowserTreeView, &QgsBrowserTreeView::collapseAll );
105  connect( mActionShowFilter, &QAction::triggered, this, &QgsDataSourceSelectDialog::showFilterWidget );
106  connect( mLeFilter, &QgsFilterLineEdit::returnPressed, this, &QgsDataSourceSelectDialog::setFilter );
108  connect( mLeFilter, &QgsFilterLineEdit::textChanged, this, &QgsDataSourceSelectDialog::setFilter );
109  connect( group, &QActionGroup::triggered, this, &QgsDataSourceSelectDialog::setFilterSyntax );
110 
111  mBrowserToolbar->setIconSize( QgsGuiUtils::iconSize( true ) );
112 
113  if ( QgsSettings().value( QStringLiteral( "datasourceSelectFilterVisible" ), false, QgsSettings::Section::Gui ).toBool() )
114  {
115  mActionShowFilter->trigger();
116  }
117 }
118 
120 {
121  if ( ! mOwnModel )
122  mBrowserModel.release();
123 }
124 
125 
127 {
128  QDialog::showEvent( e );
129  QString lastSelectedPath( QgsSettings().value( QStringLiteral( "datasourceSelectLastSelectedItem" ),
130  QString(), QgsSettings::Section::Gui ).toString() );
131  if ( ! lastSelectedPath.isEmpty() )
132  {
133  QModelIndexList items = mBrowserProxyModel.match(
134  mBrowserProxyModel.index( 0, 0 ),
136  QVariant::fromValue( lastSelectedPath ),
137  1,
138  Qt::MatchRecursive );
139  if ( items.count( ) > 0 )
140  {
141  QModelIndex expandIndex = items.at( 0 );
142  if ( expandIndex.isValid() )
143  {
144  mBrowserTreeView->scrollTo( expandIndex, QgsBrowserTreeView::ScrollHint::PositionAtTop );
145  mBrowserTreeView->expand( expandIndex );
146  }
147  }
148  }
149 }
150 
152 {
153  QgsSettings().setValue( QStringLiteral( "datasourceSelectFilterVisible" ), visible, QgsSettings::Section::Gui );
154  mWidgetFilter->setVisible( visible );
155  if ( ! visible )
156  {
157  mLeFilter->setText( QString() );
158  setFilter();
159  }
160  else
161  {
162  mLeFilter->setFocus();
163  }
164 }
165 
166 void QgsDataSourceSelectDialog::setDescription( const QString &description )
167 {
168  if ( !description.isEmpty() )
169  {
170  if ( !mDescriptionLabel )
171  {
172  mDescriptionLabel = new QLabel();
173  mDescriptionLabel->setWordWrap( true );
174  mDescriptionLabel->setMargin( 4 );
175  verticalLayout->insertWidget( 1, mDescriptionLabel );
176  }
177  mDescriptionLabel->setText( description );
178  }
179  else
180  {
181  if ( mDescriptionLabel )
182  {
183  verticalLayout->removeWidget( mDescriptionLabel );
184  delete mDescriptionLabel;
185  mDescriptionLabel = nullptr;
186  }
187  }
188 }
189 
191 {
192  QString filter = mLeFilter->text();
193  mBrowserProxyModel.setFilterString( filter );
194 }
195 
196 
197 void QgsDataSourceSelectDialog::refreshModel( const QModelIndex &index )
198 {
199 
200  QgsDataItem *item = mBrowserModel->dataItem( index );
201  if ( item )
202  {
203  QgsDebugMsg( "path = " + item->path() );
204  }
205  else
206  {
207  QgsDebugMsg( QStringLiteral( "invalid item" ) );
208  }
209 
210  if ( item && ( item->capabilities2() & QgsDataItem::Fertile ) )
211  {
212  mBrowserModel->refresh( index );
213  }
214 
215  for ( int i = 0; i < mBrowserModel->rowCount( index ); i++ )
216  {
217  QModelIndex idx = mBrowserModel->index( i, 0, index );
218  QModelIndex proxyIdx = mBrowserProxyModel.mapFromSource( idx );
219  QgsDataItem *child = mBrowserModel->dataItem( idx );
220 
221  // Check also expanded descendants so that the whole expanded path does not get collapsed if one item is collapsed.
222  // Fast items (usually root items) are refreshed so that when collapsed, it is obvious they are if empty (no expand symbol).
223  if ( mBrowserTreeView->isExpanded( proxyIdx ) || mBrowserTreeView->hasExpandedDescendant( proxyIdx ) || ( child && child->capabilities2() & QgsDataItem::Fast ) )
224  {
225  refreshModel( idx );
226  }
227  else
228  {
229  if ( child && ( child->capabilities2() & QgsDataItem::Fertile ) )
230  {
231  child->depopulate();
232  }
233  }
234  }
235 }
236 
237 
239 {
240  if ( !action )
241  return;
242  mBrowserProxyModel.setFilterSyntax( static_cast< QgsBrowserProxyModel::FilterSyntax >( action->data().toInt() ) );
243 }
244 
246 {
247  mBrowserProxyModel.setFilterCaseSensitivity( caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
248 }
249 
251 {
252  mBrowserProxyModel.setFilterByLayerType( true );
253  mBrowserProxyModel.setLayerType( layerType );
254  // reset model and button
255  mBrowserTreeView->setModel( &mBrowserProxyModel );
256  buttonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( false );
257 }
258 
260 {
261  return mUri;
262 }
263 
264 void QgsDataSourceSelectDialog::onLayerSelected( const QModelIndex &index )
265 {
266  bool isLayerCompatible = false;
267  mUri = QgsMimeDataUtils::Uri();
268  if ( index.isValid() )
269  {
270  const QgsDataItem *dataItem( mBrowserProxyModel.dataItem( index ) );
271  if ( dataItem )
272  {
273  const QgsLayerItem *layerItem = qobject_cast<const QgsLayerItem *>( dataItem );
274  if ( layerItem && ( ! mBrowserProxyModel.filterByLayerType() ||
275  ( layerItem->mapLayerType() == mBrowserProxyModel.layerType() ) ) )
276  {
277  isLayerCompatible = true;
278  mUri = layerItem->mimeUri();
279  // Store last viewed item
280  QgsSettings().setValue( QStringLiteral( "datasourceSelectLastSelectedItem" ), mBrowserProxyModel.data( index, QgsBrowserModel::PathRole ).toString(), QgsSettings::Section::Gui );
281  }
282  }
283  }
284  buttonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( isLayerCompatible );
285 }
286 
287 void QgsDataSourceSelectDialog::itemDoubleClicked( const QModelIndex &index )
288 {
289  onLayerSelected( index );
290  if ( buttonBox->button( QDialogButtonBox::StandardButton::Ok )->isEnabled() )
291  accept();
292 }
293 
void setDescription(const QString &description)
Sets a description label.
QgsMimeDataUtils::Uri uri() const
Returns the (possibly invalid) uri of the selected data source.
QString path() const
Definition: qgsdataitem.h:293
void setLayerTypeFilter(QgsMapLayerType layerType)
Sets layer type filter to layerType and activates the filtering.
QgsDataSourceSelectDialog(QgsBrowserModel *browserModel=nullptr, bool setFilterByLayerType=false, QgsMapLayerType layerType=QgsMapLayerType::VectorLayer, QWidget *parent=nullptr)
Constructs a QgsDataSourceSelectDialog, optionally filtering by layer type.
void setFilterSyntax(QAction *)
Sets filter syntax.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
void setLayerType(QgsMapLayerType type)
Sets the layer type to filter the model by.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
void setFilter()
Apply filter to the model.
QgsMapLayerType mapLayerType() const
Returns QgsMapLayerType.
void setBrowserModel(QgsBrowserModel *model)
Sets the underlying browser model.
QgsMapLayerType layerType() const
Returns the layer type to filter the model by.
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.
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.
void setFilterString(const QString &filter)
Sets the filter string to use when filtering items in the model.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window&#39;s toolbar icons.
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.
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:65
QgsDataItem * dataItem(const QModelIndex &index) const
Returns the data item at the specified proxy index, or 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