diff --git a/python/gui/auto_generated/qgsdatasourceselectdialog.sip.in b/python/gui/auto_generated/qgsdatasourceselectdialog.sip.in index b478fa2d421..247a4a8e328 100644 --- a/python/gui/auto_generated/qgsdatasourceselectdialog.sip.in +++ b/python/gui/auto_generated/qgsdatasourceselectdialog.sip.in @@ -55,6 +55,28 @@ Sets layer type filter to ``layerType`` and activates the filtering QgsMimeDataUtils::Uri uri() const; %Docstring Returns the (possibly invalid) uri of the selected data source +%End + + void showFilterWidget( bool visible ); +%Docstring +Show/hide filter widget +%End + void setFilterSyntax( QAction * ); +%Docstring +Sets filter syntax +%End + void setCaseSensitive( bool caseSensitive ); +%Docstring +Sets filter case sensitivity +%End + void setFilter(); +%Docstring +Apply filter to the model +%End + virtual void showEvent( QShowEvent *e ); + +%Docstring +Scroll to last selected index and expand it's children %End }; diff --git a/src/gui/qgsdatasourceselectdialog.cpp b/src/gui/qgsdatasourceselectdialog.cpp index e81ef35b627..2ec9c6acf5b 100644 --- a/src/gui/qgsdatasourceselectdialog.cpp +++ b/src/gui/qgsdatasourceselectdialog.cpp @@ -19,8 +19,10 @@ #include "qgssettings.h" #include "qgsgui.h" #include "qgis.h" +#include "qgsbrowsermodel.h" #include +#include QgsDataSourceSelectDialog::QgsDataSourceSelectDialog( QgsBrowserModel *browserModel, @@ -32,6 +34,7 @@ QgsDataSourceSelectDialog::QgsDataSourceSelectDialog( if ( ! browserModel ) { mBrowserModel = qgis::make_unique(); + mBrowserModel->initialize(); mOwnModel = true; } else @@ -44,12 +47,12 @@ QgsDataSourceSelectDialog::QgsDataSourceSelectDialog( setWindowTitle( tr( "Select a Data Source" ) ); QgsGui::enableAutoGeometryRestore( this ); - mBrowserModel->initialize(); mBrowserProxyModel.setBrowserModel( mBrowserModel.get() ); mBrowserTreeView->setHeaderHidden( true ); if ( setFilterByLayerType ) { + // This will also set the (proxy) model setLayerTypeFilter( layerType ); } else @@ -57,7 +60,55 @@ QgsDataSourceSelectDialog::QgsDataSourceSelectDialog( mBrowserTreeView->setModel( &mBrowserProxyModel ); buttonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( false ); } + + mBrowserTreeView->setBrowserModel( mBrowserModel.get() ); + + mWidgetFilter->hide(); + mLeFilter->setPlaceholderText( tr( "Type here to filter visible items…" ) ); + // icons from http://www.fatcow.com/free-icons License: CC Attribution 3.0 + + QMenu *menu = new QMenu( this ); + menu->setSeparatorsCollapsible( false ); + mBtnFilterOptions->setMenu( menu ); + QAction *action = new QAction( tr( "Case Sensitive" ), menu ); + action->setData( "case" ); + action->setCheckable( true ); + action->setChecked( false ); + connect( action, &QAction::toggled, this, &QgsDataSourceSelectDialog::setCaseSensitive ); + menu->addAction( action ); + QActionGroup *group = new QActionGroup( menu ); + action = new QAction( tr( "Filter Pattern Syntax" ), group ); + action->setSeparator( true ); + menu->addAction( action ); + action = new QAction( tr( "Normal" ), group ); + action->setData( QgsBrowserProxyModel::Normal ); + action->setCheckable( true ); + action->setChecked( true ); + menu->addAction( action ); + action = new QAction( tr( "Wildcard(s)" ), group ); + action->setData( QgsBrowserProxyModel::Wildcards ); + action->setCheckable( true ); + menu->addAction( action ); + action = new QAction( tr( "Regular Expression" ), group ); + action->setData( QgsBrowserProxyModel::RegularExpression ); + action->setCheckable( true ); + menu->addAction( action ); + + mBrowserTreeView->setExpandsOnDoubleClick( false ); + + connect( mActionRefresh, &QAction::triggered, [ = ] { refreshModel( QModelIndex() ); } ); connect( mBrowserTreeView, &QgsBrowserTreeView::clicked, this, &QgsDataSourceSelectDialog::onLayerSelected ); + connect( mActionCollapse, &QAction::triggered, mBrowserTreeView, &QgsBrowserTreeView::collapseAll ); + connect( mActionShowFilter, &QAction::triggered, this, &QgsDataSourceSelectDialog::showFilterWidget ); + connect( mLeFilter, &QgsFilterLineEdit::returnPressed, this, &QgsDataSourceSelectDialog::setFilter ); + connect( mLeFilter, &QgsFilterLineEdit::cleared, this, &QgsDataSourceSelectDialog::setFilter ); + connect( mLeFilter, &QgsFilterLineEdit::textChanged, this, &QgsDataSourceSelectDialog::setFilter ); + connect( group, &QActionGroup::triggered, this, &QgsDataSourceSelectDialog::setFilterSyntax ); + + if ( QgsSettings().value( QStringLiteral( "datasourceSelectFilterVisible" ), false, QgsSettings::Section::Gui ).toBool() ) + { + mActionShowFilter->trigger(); + } } QgsDataSourceSelectDialog::~QgsDataSourceSelectDialog() @@ -66,6 +117,107 @@ QgsDataSourceSelectDialog::~QgsDataSourceSelectDialog() mBrowserModel.release(); } + +void QgsDataSourceSelectDialog::showEvent( QShowEvent *e ) +{ + QDialog::showEvent( e ); + QString lastSelectedPath( QgsSettings().value( QStringLiteral( "datasourceSelectLastSelectedItem" ), + QString(), QgsSettings::Section::Gui ).toString() ); + if ( ! lastSelectedPath.isEmpty() ) + { + QModelIndexList items = mBrowserProxyModel.match( + mBrowserProxyModel.index( 0, 0 ), + QgsBrowserModel::PathRole, + QVariant::fromValue( lastSelectedPath ), + 1, + Qt::MatchRecursive ); + if ( items.count( ) > 0 ) + { + QModelIndex expandIndex = items.at( 0 ); + if ( expandIndex.isValid() ) + { + mBrowserTreeView->scrollTo( expandIndex, QgsBrowserTreeView::QgsBrowserTreeView::ScrollHint::PositionAtTop ); + mBrowserTreeView->expand( expandIndex ); + } + } + } +} + +void QgsDataSourceSelectDialog::showFilterWidget( bool visible ) +{ + QgsSettings().setValue( QStringLiteral( "datasourceSelectFilterVisible" ), visible, QgsSettings::Section::Gui ); + mWidgetFilter->setVisible( visible ); + if ( ! visible ) + { + mLeFilter->setText( QString() ); + setFilter(); + } + else + { + mLeFilter->setFocus(); + } +} + +void QgsDataSourceSelectDialog::setFilter() +{ + QString filter = mLeFilter->text(); + mBrowserProxyModel.setFilterString( filter ); +} + + +void QgsDataSourceSelectDialog::refreshModel( const QModelIndex &index ) +{ + + QgsDataItem *item = mBrowserModel->dataItem( index ); + if ( item ) + { + QgsDebugMsg( "path = " + item->path() ); + } + else + { + QgsDebugMsg( QStringLiteral( "invalid item" ) ); + } + + if ( item && ( item->capabilities2() & QgsDataItem::Fertile ) ) + { + mBrowserModel->refresh( index ); + } + + for ( int i = 0; i < mBrowserModel->rowCount( index ); i++ ) + { + QModelIndex idx = mBrowserModel->index( i, 0, index ); + QModelIndex proxyIdx = mBrowserProxyModel.mapFromSource( idx ); + QgsDataItem *child = mBrowserModel->dataItem( idx ); + + // Check also expanded descendants so that the whole expanded path does not get collapsed if one item is collapsed. + // Fast items (usually root items) are refreshed so that when collapsed, it is obvious they are if empty (no expand symbol). + if ( mBrowserTreeView->isExpanded( proxyIdx ) || mBrowserTreeView->hasExpandedDescendant( proxyIdx ) || ( child && child->capabilities2() & QgsDataItem::Fast ) ) + { + refreshModel( idx ); + } + else + { + if ( child && ( child->capabilities2() & QgsDataItem::Fertile ) ) + { + child->depopulate(); + } + } + } +} + + +void QgsDataSourceSelectDialog::setFilterSyntax( QAction *action ) +{ + if ( !action ) + return; + mBrowserProxyModel.setFilterSyntax( static_cast< QgsBrowserProxyModel::FilterSyntax >( action->data().toInt() ) ); +} + +void QgsDataSourceSelectDialog::setCaseSensitive( bool caseSensitive ) +{ + mBrowserProxyModel.setFilterCaseSensitivity( caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive ); +} + void QgsDataSourceSelectDialog::setLayerTypeFilter( QgsMapLayer::LayerType layerType ) { mBrowserProxyModel.setFilterByLayerType( true ); @@ -95,6 +247,8 @@ void QgsDataSourceSelectDialog::onLayerSelected( const QModelIndex &index ) { isLayerCompatible = true; mUri = layerItem->mimeUri(); + // Store last viewed item + QgsSettings().setValue( QStringLiteral( "datasourceSelectLastSelectedItem" ), mBrowserProxyModel.data( index, QgsBrowserModel::PathRole ).toString(), QgsSettings::Section::Gui ); } } } diff --git a/src/gui/qgsdatasourceselectdialog.h b/src/gui/qgsdatasourceselectdialog.h index 956b12614d0..7bb8b0dec22 100644 --- a/src/gui/qgsdatasourceselectdialog.h +++ b/src/gui/qgsdatasourceselectdialog.h @@ -73,6 +73,17 @@ class GUI_EXPORT QgsDataSourceSelectDialog: public QDialog, private Ui::QgsDataS */ QgsMimeDataUtils::Uri uri() const; + //! Show/hide filter widget + void showFilterWidget( bool visible ); + //! Sets filter syntax + void setFilterSyntax( QAction * ); + //! Sets filter case sensitivity + void setCaseSensitive( bool caseSensitive ); + //! Apply filter to the model + void setFilter(); + //! Scroll to last selected index and expand it's children + void showEvent( QShowEvent *e ) override; + private slots: //! Triggered when a layer is selected in the browser @@ -80,6 +91,9 @@ class GUI_EXPORT QgsDataSourceSelectDialog: public QDialog, private Ui::QgsDataS private: + //! Refresh the model + void refreshModel( const QModelIndex &index ); + QgsBrowserProxyModel mBrowserProxyModel; std::unique_ptr mBrowserModel; bool mOwnModel = true; diff --git a/src/ui/qgsdatasourceselectdialog.ui b/src/ui/qgsdatasourceselectdialog.ui index 795498eb7a8..5a55f8c163c 100644 --- a/src/ui/qgsdatasourceselectdialog.ui +++ b/src/ui/qgsdatasourceselectdialog.ui @@ -6,8 +6,8 @@ 0 0 - 400 - 300 + 700 + 629 @@ -15,7 +15,143 @@ - + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 24 + 24 + + + + false + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 2 + + + 2 + + + 0 + + + 2 + + + 0 + + + + + Options + + + + + + + :/images/themes/default/mActionOptions.svg:/images/themes/default/mActionOptions.svg + + + QToolButton::InstantPopup + + + Qt::ToolButtonIconOnly + + + true + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + + + + + + + + @@ -28,15 +164,64 @@ + + + + + :/images/themes/default/mActionRefresh.svg:/images/themes/default/mActionRefresh.svg + + + Refresh + + + + + true + + + + :/images/themes/default/mActionFilter2.svg:/images/themes/default/mActionFilter2.svg + + + Filter Browser + + + Filter Browser + + + Filter Browser + + + + + + :/images/themes/default/mActionCollapseTree.svg:/images/themes/default/mActionCollapseTree.svg + + + Collapse All + + + Collapse All + + + + + QgsFilterLineEdit + QLineEdit +
qgsfilterlineedit.h
+
QgsBrowserTreeView QTreeView
qgsbrowsertreeview.h
- + + + + buttonBox