Skip to content

Commit 02ecb56

Browse files
committedNov 7, 2018
QgsDataSourceSelectDialog: filter, refresh and scroll to last selected item
plus: - expand children of last selected item - save/restore status
1 parent 4cdde31 commit 02ecb56

File tree

4 files changed

+380
-5
lines changed

4 files changed

+380
-5
lines changed
 

‎python/gui/auto_generated/qgsdatasourceselectdialog.sip.in

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,28 @@ Sets layer type filter to ``layerType`` and activates the filtering
5555
QgsMimeDataUtils::Uri uri() const;
5656
%Docstring
5757
Returns the (possibly invalid) uri of the selected data source
58+
%End
59+
60+
void showFilterWidget( bool visible );
61+
%Docstring
62+
Show/hide filter widget
63+
%End
64+
void setFilterSyntax( QAction * );
65+
%Docstring
66+
Sets filter syntax
67+
%End
68+
void setCaseSensitive( bool caseSensitive );
69+
%Docstring
70+
Sets filter case sensitivity
71+
%End
72+
void setFilter();
73+
%Docstring
74+
Apply filter to the model
75+
%End
76+
virtual void showEvent( QShowEvent *e );
77+
78+
%Docstring
79+
Scroll to last selected index and expand it's children
5880
%End
5981

6082
};

‎src/gui/qgsdatasourceselectdialog.cpp

Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
#include "qgssettings.h"
2020
#include "qgsgui.h"
2121
#include "qgis.h"
22+
#include "qgsbrowsermodel.h"
2223

2324
#include <QPushButton>
25+
#include <QMenu>
2426

2527
QgsDataSourceSelectDialog::QgsDataSourceSelectDialog(
2628
QgsBrowserModel *browserModel,
@@ -32,6 +34,7 @@ QgsDataSourceSelectDialog::QgsDataSourceSelectDialog(
3234
if ( ! browserModel )
3335
{
3436
mBrowserModel = qgis::make_unique<QgsBrowserModel>();
37+
mBrowserModel->initialize();
3538
mOwnModel = true;
3639
}
3740
else
@@ -44,20 +47,68 @@ QgsDataSourceSelectDialog::QgsDataSourceSelectDialog(
4447
setWindowTitle( tr( "Select a Data Source" ) );
4548
QgsGui::enableAutoGeometryRestore( this );
4649

47-
mBrowserModel->initialize();
4850
mBrowserProxyModel.setBrowserModel( mBrowserModel.get() );
4951
mBrowserTreeView->setHeaderHidden( true );
5052

5153
if ( setFilterByLayerType )
5254
{
55+
// This will also set the (proxy) model
5356
setLayerTypeFilter( layerType );
5457
}
5558
else
5659
{
5760
mBrowserTreeView->setModel( &mBrowserProxyModel );
5861
buttonBox->button( QDialogButtonBox::StandardButton::Ok )->setEnabled( false );
5962
}
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, [ = ] { refreshModel( QModelIndex() ); } );
60100
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 );
104+
connect( mLeFilter, &QgsFilterLineEdit::cleared, 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+
}
61112
}
62113

63114
QgsDataSourceSelectDialog::~QgsDataSourceSelectDialog()
@@ -66,6 +117,107 @@ QgsDataSourceSelectDialog::~QgsDataSourceSelectDialog()
66117
mBrowserModel.release();
67118
}
68119

120+
121+
void QgsDataSourceSelectDialog::showEvent( QShowEvent *e )
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 ),
130+
QgsBrowserModel::PathRole,
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::QgsBrowserTreeView::ScrollHint::PositionAtTop );
140+
mBrowserTreeView->expand( expandIndex );
141+
}
142+
}
143+
}
144+
}
145+
146+
void QgsDataSourceSelectDialog::showFilterWidget( bool visible )
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+
161+
void QgsDataSourceSelectDialog::setFilter()
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+
209+
void QgsDataSourceSelectDialog::setFilterSyntax( QAction *action )
210+
{
211+
if ( !action )
212+
return;
213+
mBrowserProxyModel.setFilterSyntax( static_cast< QgsBrowserProxyModel::FilterSyntax >( action->data().toInt() ) );
214+
}
215+
216+
void QgsDataSourceSelectDialog::setCaseSensitive( bool caseSensitive )
217+
{
218+
mBrowserProxyModel.setFilterCaseSensitivity( caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
219+
}
220+
69221
void QgsDataSourceSelectDialog::setLayerTypeFilter( QgsMapLayer::LayerType layerType )
70222
{
71223
mBrowserProxyModel.setFilterByLayerType( true );
@@ -95,6 +247,8 @@ void QgsDataSourceSelectDialog::onLayerSelected( const QModelIndex &index )
95247
{
96248
isLayerCompatible = true;
97249
mUri = layerItem->mimeUri();
250+
// Store last viewed item
251+
QgsSettings().setValue( QStringLiteral( "datasourceSelectLastSelectedItem" ), mBrowserProxyModel.data( index, QgsBrowserModel::PathRole ).toString(), QgsSettings::Section::Gui );
98252
}
99253
}
100254
}

‎src/gui/qgsdatasourceselectdialog.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,27 @@ class GUI_EXPORT QgsDataSourceSelectDialog: public QDialog, private Ui::QgsDataS
7373
*/
7474
QgsMimeDataUtils::Uri uri() const;
7575

76+
//! Show/hide filter widget
77+
void showFilterWidget( bool visible );
78+
//! Sets filter syntax
79+
void setFilterSyntax( QAction * );
80+
//! Sets filter case sensitivity
81+
void setCaseSensitive( bool caseSensitive );
82+
//! Apply filter to the model
83+
void setFilter();
84+
//! Scroll to last selected index and expand it's children
85+
void showEvent( QShowEvent *e ) override;
86+
7687
private slots:
7788

7889
//! Triggered when a layer is selected in the browser
7990
void onLayerSelected( const QModelIndex &index );
8091

8192
private:
8293

94+
//! Refresh the model
95+
void refreshModel( const QModelIndex &index );
96+
8397
QgsBrowserProxyModel mBrowserProxyModel;
8498
std::unique_ptr<QgsBrowserModel> mBrowserModel;
8599
bool mOwnModel = true;

0 commit comments

Comments
 (0)