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