QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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 
19 #include "qgis.h"
20 #include "qgsbrowsermodel.h"
21 #include "qgsgui.h"
22 #include "qgsguiutils.h"
23 #include "qgssettings.h"
24 #include "qgsnative.h"
25 
26 #include <QPushButton>
27 #include <QMenu>
28 #include <QDesktopServices>
29 #include <QDialogButtonBox>
30 
32  QgsBrowserGuiModel *browserModel,
33  bool setFilterByLayerType,
34  QgsMapLayerType layerType,
35  QWidget *parent )
36  : QgsPanelWidget( parent )
37 {
38  if ( ! browserModel )
39  {
40  mBrowserModel = new QgsBrowserGuiModel( this );
41  mBrowserModel->initialize();
42  }
43  else
44  {
45  mBrowserModel = browserModel;
46  mBrowserModel->initialize();
47  }
48 
49  setupUi( this );
50 
51  mBrowserProxyModel.setBrowserModel( mBrowserModel );
52  mBrowserTreeView->setHeaderHidden( true );
53 
54  if ( setFilterByLayerType )
55  {
56  // This will also set the (proxy) model
57  setLayerTypeFilter( layerType );
58  }
59  else
60  {
61  mBrowserTreeView->setModel( &mBrowserProxyModel );
62  setValid( false );
63  }
64 
65  mBrowserTreeView->setBrowserModel( mBrowserModel );
66 
67  mWidgetFilter->hide();
68  mLeFilter->setPlaceholderText( tr( "Type here to filter visible items…" ) );
69  // icons from http://www.fatcow.com/free-icons License: CC Attribution 3.0
70 
71  QMenu *menu = new QMenu( this );
72  menu->setSeparatorsCollapsible( false );
73  mBtnFilterOptions->setMenu( menu );
74  QAction *action = new QAction( tr( "Case Sensitive" ), menu );
75  action->setData( "case" );
76  action->setCheckable( true );
77  action->setChecked( false );
78  connect( action, &QAction::toggled, this, &QgsDataSourceSelectWidget::setCaseSensitive );
79  menu->addAction( action );
80  QActionGroup *group = new QActionGroup( menu );
81  action = new QAction( tr( "Filter Pattern Syntax" ), group );
82  action->setSeparator( true );
83  menu->addAction( action );
84  action = new QAction( tr( "Normal" ), group );
85  action->setData( QgsBrowserProxyModel::Normal );
86  action->setCheckable( true );
87  action->setChecked( true );
88  menu->addAction( action );
89  action = new QAction( tr( "Wildcard(s)" ), group );
90  action->setData( QgsBrowserProxyModel::Wildcards );
91  action->setCheckable( true );
92  menu->addAction( action );
93  action = new QAction( tr( "Regular Expression" ), group );
94  action->setData( QgsBrowserProxyModel::RegularExpression );
95  action->setCheckable( true );
96  menu->addAction( action );
97 
98  connect( mActionRefresh, &QAction::triggered, this, [ = ] { refreshModel( QModelIndex() ); } );
99  connect( mBrowserTreeView, &QgsBrowserTreeView::clicked, this, &QgsDataSourceSelectWidget::onLayerSelected );
100  connect( mBrowserTreeView, &QgsBrowserTreeView::doubleClicked, this, &QgsDataSourceSelectWidget::itemDoubleClicked );
101  connect( mActionCollapse, &QAction::triggered, mBrowserTreeView, &QgsBrowserTreeView::collapseAll );
102  connect( mActionShowFilter, &QAction::triggered, this, &QgsDataSourceSelectWidget::showFilterWidget );
103  connect( mLeFilter, &QgsFilterLineEdit::returnPressed, this, &QgsDataSourceSelectWidget::setFilter );
105  connect( mLeFilter, &QgsFilterLineEdit::textChanged, this, &QgsDataSourceSelectWidget::setFilter );
106  connect( group, &QActionGroup::triggered, this, &QgsDataSourceSelectWidget::setFilterSyntax );
107 
108  mBrowserToolbar->setIconSize( QgsGuiUtils::iconSize( true ) );
109 
110  if ( QgsSettings().value( QStringLiteral( "datasourceSelectFilterVisible" ), false, QgsSettings::Section::Gui ).toBool() )
111  {
112  mActionShowFilter->trigger();
113  }
114 }
115 
117 
119 {
120  QgsPanelWidget::showEvent( e );
121  QString lastSelectedPath( QgsSettings().value( QStringLiteral( "datasourceSelectLastSelectedItem" ),
122  QString(), QgsSettings::Section::Gui ).toString() );
123  if ( ! lastSelectedPath.isEmpty() )
124  {
125  QModelIndexList items = mBrowserProxyModel.match(
126  mBrowserProxyModel.index( 0, 0 ),
128  QVariant::fromValue( lastSelectedPath ),
129  1,
130  Qt::MatchRecursive );
131  if ( items.count( ) > 0 )
132  {
133  QModelIndex expandIndex = items.at( 0 );
134  if ( expandIndex.isValid() )
135  {
136  mBrowserTreeView->scrollTo( expandIndex, QgsBrowserTreeView::ScrollHint::PositionAtTop );
137  mBrowserTreeView->expand( expandIndex );
138  }
139  }
140  }
141 }
142 
144 {
145  QgsSettings().setValue( QStringLiteral( "datasourceSelectFilterVisible" ), visible, QgsSettings::Section::Gui );
146  mWidgetFilter->setVisible( visible );
147  if ( ! visible )
148  {
149  mLeFilter->setText( QString() );
150  setFilter();
151  }
152  else
153  {
154  mLeFilter->setFocus();
155  }
156 }
157 
158 void QgsDataSourceSelectWidget::setDescription( const QString &description )
159 {
160  if ( !description.isEmpty() )
161  {
162  if ( !mDescriptionLabel )
163  {
164  mDescriptionLabel = new QLabel();
165  mDescriptionLabel->setWordWrap( true );
166  mDescriptionLabel->setMargin( 4 );
167  mDescriptionLabel->setTextInteractionFlags( Qt::TextBrowserInteraction );
168  connect( mDescriptionLabel, &QLabel::linkActivated, this, [ = ]( const QString & link )
169  {
170  QUrl url( link );
171  QFileInfo file( url.toLocalFile() );
172  if ( file.exists() && !file.isDir() )
173  QgsGui::instance()->nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
174  else
175  QDesktopServices::openUrl( url );
176  } );
177  verticalLayout->insertWidget( 1, mDescriptionLabel );
178  }
179  mDescriptionLabel->setText( description );
180  }
181  else
182  {
183  if ( mDescriptionLabel )
184  {
185  verticalLayout->removeWidget( mDescriptionLabel );
186  delete mDescriptionLabel;
187  mDescriptionLabel = nullptr;
188  }
189  }
190 }
191 
193 {
194  QString filter = mLeFilter->text();
195  mBrowserProxyModel.setFilterString( filter );
196 }
197 
198 
199 void QgsDataSourceSelectWidget::refreshModel( const QModelIndex &index )
200 {
201 
202  QgsDataItem *item = mBrowserModel->dataItem( index );
203  if ( item )
204  {
205  QgsDebugMsgLevel( "path = " + item->path(), 2 );
206  }
207  else
208  {
209  QgsDebugMsg( QStringLiteral( "invalid item" ) );
210  }
211 
212  if ( item && ( item->capabilities2() & QgsDataItem::Fertile ) )
213  {
214  mBrowserModel->refresh( index );
215  }
216 
217  for ( int i = 0; i < mBrowserModel->rowCount( index ); i++ )
218  {
219  QModelIndex idx = mBrowserModel->index( i, 0, index );
220  QModelIndex proxyIdx = mBrowserProxyModel.mapFromSource( idx );
221  QgsDataItem *child = mBrowserModel->dataItem( idx );
222 
223  // Check also expanded descendants so that the whole expanded path does not get collapsed if one item is collapsed.
224  // Fast items (usually root items) are refreshed so that when collapsed, it is obvious they are if empty (no expand symbol).
225  if ( mBrowserTreeView->isExpanded( proxyIdx ) || mBrowserTreeView->hasExpandedDescendant( proxyIdx ) || ( child && child->capabilities2() & QgsDataItem::Fast ) )
226  {
227  refreshModel( idx );
228  }
229  else
230  {
231  if ( child && ( child->capabilities2() & QgsDataItem::Fertile ) )
232  {
233  child->depopulate();
234  }
235  }
236  }
237 }
238 
239 void QgsDataSourceSelectWidget::setValid( bool valid )
240 {
241  const bool prev = mIsValid;
242  mIsValid = valid;
243  if ( prev != mIsValid )
244  emit validationChanged( mIsValid );
245 
246 }
247 
248 
250 {
251  if ( !action )
252  return;
253  mBrowserProxyModel.setFilterSyntax( static_cast< QgsBrowserProxyModel::FilterSyntax >( action->data().toInt() ) );
254 }
255 
257 {
258  mBrowserProxyModel.setFilterCaseSensitivity( caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
259 }
260 
262 {
263  mBrowserProxyModel.setFilterByLayerType( true );
264  mBrowserProxyModel.setLayerType( layerType );
265  // reset model and button
266  mBrowserTreeView->setModel( &mBrowserProxyModel );
267  setValid( false );
268 }
269 
271 {
272  return mUri;
273 }
274 
275 void QgsDataSourceSelectWidget::onLayerSelected( const QModelIndex &index )
276 {
277  bool isLayerCompatible = false;
278  mUri = QgsMimeDataUtils::Uri();
279  if ( index.isValid() )
280  {
281  const QgsDataItem *dataItem( mBrowserProxyModel.dataItem( index ) );
282  if ( dataItem )
283  {
284  const QgsLayerItem *layerItem = qobject_cast<const QgsLayerItem *>( dataItem );
285  if ( layerItem && ( ! mBrowserProxyModel.filterByLayerType() ||
286  ( layerItem->mapLayerType() == mBrowserProxyModel.layerType() ) ) )
287  {
288  isLayerCompatible = true;
289  mUri = layerItem->mimeUri();
290  // Store last viewed item
291  QgsSettings().setValue( QStringLiteral( "datasourceSelectLastSelectedItem" ), mBrowserProxyModel.data( index, QgsBrowserGuiModel::PathRole ).toString(), QgsSettings::Section::Gui );
292  }
293  }
294  }
295  setValid( isLayerCompatible );
296  emit selectionChanged();
297 }
298 
299 void QgsDataSourceSelectWidget::itemDoubleClicked( const QModelIndex &index )
300 {
301  onLayerSelected( index );
302  if ( mIsValid )
303  emit itemTriggered( uri() );
304 }
305 
306 //
307 // QgsDataSourceSelectDialog
308 //
309 
310 QgsDataSourceSelectDialog::QgsDataSourceSelectDialog( QgsBrowserGuiModel *browserModel, bool setFilterByLayerType, QgsMapLayerType layerType, QWidget *parent )
311  : QDialog( parent )
312 {
313  setWindowTitle( tr( "Select a Data Source" ) );
314  setObjectName( QStringLiteral( "QgsDataSourceSelectDialog" ) );
316 
317  mWidget = new QgsDataSourceSelectWidget( browserModel, setFilterByLayerType, layerType );
318 
319  QVBoxLayout *vl = new QVBoxLayout();
320  vl->addWidget( mWidget, 1 );
321  vl->setContentsMargins( 4, 4, 4, 4 );
322  QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
323  connect( buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
324  connect( buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
325  buttonBox->button( QDialogButtonBox::Ok )->setEnabled( false );
326  connect( mWidget, &QgsDataSourceSelectWidget::validationChanged, buttonBox->button( QDialogButtonBox::Ok ), &QWidget::setEnabled );
327  connect( mWidget, &QgsDataSourceSelectWidget::itemTriggered, this, &QDialog::accept );
328  vl->addWidget( buttonBox );
329  setLayout( vl );
330 }
331 
333 {
334  mWidget->setLayerTypeFilter( layerType );
335 }
336 
337 void QgsDataSourceSelectDialog::setDescription( const QString &description )
338 {
339  mWidget->setDescription( description );
340 }
341 
343 {
344  return mWidget->uri();
345 }
346 
348 {
349  mWidget->showFilterWidget( visible );
350 }
351 
353 {
354  mWidget->setFilterSyntax( syntax );
355 }
356 
358 {
359  mWidget->setCaseSensitive( caseSensitive );
360 }
361 
363 {
364  mWidget->setFilter();
365 
366 }
QgsLayerItem::mapLayerType
QgsMapLayerType mapLayerType() const
Returns QgsMapLayerType.
Definition: qgsdataitem.cpp:810
QgsMimeDataUtils::Uri::uri
QString uri
Identifier of the data source recognized by its providerKey.
Definition: qgsmimedatautils.h:123
QgsBrowserModel::refresh
void refresh(const QString &path)
Refresh item specified by path.
Definition: qgsbrowsermodel.cpp:687
QgsBrowserModel::initialize
void initialize()
Delayed initialization, needed because the provider registry must be already populated.
Definition: qgsbrowsermodel.cpp:223
QgsDataSourceSelectWidget::setDescription
void setDescription(const QString &description)
Sets a description label.
Definition: qgsdatasourceselectdialog.cpp:158
QgsDataItem::path
QString path() const
Definition: qgsdataitem.h:333
QgsDataSourceSelectWidget::validationChanged
void validationChanged(bool isValid)
This signal is emitted whenever the validation status of the widget changes.
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsDataItem::capabilities2
virtual Capabilities capabilities2() const
Returns the capabilities for the data item.
Definition: qgsdataitem.h:287
qgsgui.h
QgsMapLayerType
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:68
qgis.h
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsDataSourceSelectWidget::~QgsDataSourceSelectWidget
~QgsDataSourceSelectWidget() override
QgsDataItem::Fertile
@ Fertile
Can create children. Even items without this capability may have children, but cannot create them,...
Definition: qgsdataitem.h:246
QgsDataItem::depopulate
virtual void depopulate()
Remove children recursively and set as not populated. This is used when refreshing collapsed items.
Definition: qgsdataitem.cpp:518
QgsDataSourceSelectWidget::showFilterWidget
void showFilterWidget(bool visible)
Show/hide filter widget.
Definition: qgsdatasourceselectdialog.cpp:143
QgsBrowserProxyModel::setBrowserModel
void setBrowserModel(QgsBrowserModel *model)
Sets the underlying browser model.
Definition: qgsbrowserproxymodel.cpp:28
QgsDataSourceSelectWidget::setFilter
void setFilter()
Apply filter to the model.
Definition: qgsdatasourceselectdialog.cpp:192
QgsGuiUtils::iconSize
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
Definition: qgsguiutils.cpp:250
QgsDataSourceSelectWidget::itemTriggered
void itemTriggered(const QgsMimeDataUtils::Uri &uri)
Emitted when an item is triggered, e.g.
QgsGui::enableAutoGeometryRestore
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:139
QgsBrowserProxyModel::setFilterCaseSensitivity
void setFilterCaseSensitivity(Qt::CaseSensitivity sensitivity)
Sets whether item filtering should be case sensitive.
Definition: qgsbrowserproxymodel.cpp:66
QgsBrowserProxyModel::setFilterByLayerType
void setFilterByLayerType(bool enabled)
Sets whether the model is filtered by map layer type.
Definition: qgsbrowserproxymodel.cpp:189
QgsBrowserProxyModel::RegularExpression
@ RegularExpression
Regular expression filtering.
Definition: qgsbrowserproxymodel.h:42
QgsPanelWidget
Base class for any widget that can be shown as a inline panel.
Definition: qgspanelwidget.h:30
QgsDataSourceSelectWidget::uri
QgsMimeDataUtils::Uri uri() const
Returns the (possibly invalid) uri of the selected data source.
Definition: qgsdatasourceselectdialog.cpp:270
QgsDataSourceSelectWidget::setFilterSyntax
void setFilterSyntax(QAction *)
Sets filter syntax.
Definition: qgsdatasourceselectdialog.cpp:249
QgsDataSourceSelectWidget
The QgsDataSourceSelectWidget class embeds the browser view to select an existing data source.
Definition: qgsdatasourceselectdialog.h:47
QgsBrowserProxyModel::Wildcards
@ Wildcards
Wildcard filtering.
Definition: qgsbrowserproxymodel.h:41
QgsDataSourceSelectDialog::setDescription
void setDescription(const QString &description)
Sets a description label.
Definition: qgsdatasourceselectdialog.cpp:337
QgsBrowserProxyModel::filterByLayerType
bool filterByLayerType() const
Returns true if the model is filtered by map layer type.
Definition: qgsbrowserproxymodel.h:118
QgsBrowserProxyModel::layerType
QgsMapLayerType layerType() const
Returns the layer type to filter the model by.
Definition: qgsbrowserproxymodel.cpp:178
QgsDataSourceSelectWidget::QgsDataSourceSelectWidget
QgsDataSourceSelectWidget(QgsBrowserGuiModel *browserModel=nullptr, bool setFilterByLayerType=false, QgsMapLayerType layerType=QgsMapLayerType::VectorLayer, QWidget *parent=nullptr)
Constructs a QgsDataSourceSelectWidget, optionally filtering by layer type.
Definition: qgsdatasourceselectdialog.cpp:31
QgsSettings::setValue
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Definition: qgssettings.cpp:289
QgsBrowserModel::PathRole
@ PathRole
Item path used to access path in the tree, see QgsDataItem::mPath.
Definition: qgsbrowsermodel.h:92
QgsDataSourceSelectDialog::setFilterSyntax
void setFilterSyntax(QAction *)
Sets filter syntax.
Definition: qgsdatasourceselectdialog.cpp:352
QgsMimeDataUtils::Uri
Definition: qgsmimedatautils.h:41
QgsGui::nativePlatformInterface
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition: qgsgui.cpp:69
QgsBrowserProxyModel::setFilterSyntax
void setFilterSyntax(FilterSyntax syntax)
Sets the filter syntax.
Definition: qgsbrowserproxymodel.cpp:40
QgsBrowserProxyModel::Normal
@ Normal
Standard string filtering.
Definition: qgsbrowserproxymodel.h:40
QgsDataSourceSelectDialog::setFilter
void setFilter()
Apply filter to the model.
Definition: qgsdatasourceselectdialog.cpp:362
qgsbrowsermodel.h
QgsDataSourceSelectDialog::showFilterWidget
void showFilterWidget(bool visible)
Show/hide filter widget.
Definition: qgsdatasourceselectdialog.cpp:347
QgsGui::instance
static QgsGui * instance()
Returns a pointer to the singleton instance.
Definition: qgsgui.cpp:63
QgsBrowserModel::rowCount
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Definition: qgsbrowsermodel.cpp:350
QgsBrowserProxyModel::dataItem
QgsDataItem * dataItem(const QModelIndex &index) const
Returns the data item at the specified proxy index, or nullptr if no item exists at the index.
Definition: qgsbrowserproxymodel.cpp:34
QgsBrowserModel::index
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Definition: qgsbrowsermodel.cpp:514
qgssettings.h
QgsLayerItem
Item that represents a layer that can be opened with one of the providers.
Definition: qgsdataitem.h:507
QgsFilterLineEdit::cleared
void cleared()
Emitted when the widget is cleared.
QgsDataItem::Fast
@ Fast
CreateChildren() is fast enough to be run in main thread when refreshing items, most root items (wms,...
Definition: qgsdataitem.h:247
QgsDataSourceSelectWidget::setCaseSensitive
void setCaseSensitive(bool caseSensitive)
Sets filter case sensitivity.
Definition: qgsdatasourceselectdialog.cpp:256
qgsdatasourceselectdialog.h
QgsDataSourceSelectWidget::setLayerTypeFilter
void setLayerTypeFilter(QgsMapLayerType layerType)
Sets layer type filter to layerType and activates the filtering.
Definition: qgsdatasourceselectdialog.cpp:261
QgsDataSourceSelectDialog::setCaseSensitive
void setCaseSensitive(bool caseSensitive)
Sets filter case sensitivity.
Definition: qgsdatasourceselectdialog.cpp:357
qgsguiutils.h
QgsDataSourceSelectDialog::uri
QgsMimeDataUtils::Uri uri() const
Returns the (possibly invalid) uri of the selected data source.
Definition: qgsdatasourceselectdialog.cpp:342
QgsDataItem
Base class for all items in the model.
Definition: qgsdataitem.h:51
QgsDataSourceSelectWidget::selectionChanged
void selectionChanged()
Emitted when the current selection changes in the widget.
QgsBrowserModel::dataItem
QgsDataItem * dataItem(const QModelIndex &idx) const
Returns the data item at the specified index, or nullptr if no item exists at the index.
Definition: qgsbrowsermodel.cpp:658
QgsBrowserProxyModel::FilterSyntax
FilterSyntax
Filter syntax options.
Definition: qgsbrowserproxymodel.h:39
QgsDataSourceSelectDialog::setLayerTypeFilter
void setLayerTypeFilter(QgsMapLayerType layerType)
Sets layer type filter to layerType and activates the filtering.
Definition: qgsdatasourceselectdialog.cpp:332
QgsBrowserProxyModel::setLayerType
void setLayerType(QgsMapLayerType type)
Sets the layer type to filter the model by.
Definition: qgsbrowserproxymodel.cpp:183
QgsDataSourceSelectDialog::QgsDataSourceSelectDialog
QgsDataSourceSelectDialog(QgsBrowserGuiModel *browserModel=nullptr, bool setFilterByLayerType=false, QgsMapLayerType layerType=QgsMapLayerType::VectorLayer, QWidget *parent=nullptr)
Constructs a QgsDataSourceSelectDialog, optionally filtering by layer type.
Definition: qgsdatasourceselectdialog.cpp:310
QgsBrowserGuiModel
A model for showing available data sources and other items in a structured tree.
Definition: qgsbrowserguimodel.h:38
QgsBrowserProxyModel::setFilterString
void setFilterString(const QString &filter)
Sets the filter string to use when filtering items in the model.
Definition: qgsbrowserproxymodel.cpp:53
QgsLayerItem::mimeUri
QgsMimeDataUtils::Uri mimeUri() const override
Returns mime URI for the data item.
Definition: qgsdataitem.cpp:932
QgsDataSourceSelectWidget::showEvent
void showEvent(QShowEvent *e) override
Scroll to last selected index and expand it's children.
Definition: qgsdatasourceselectdialog.cpp:118