20
20
#include < QSettings>
21
21
#include < QToolButton>
22
22
#include < QFileDialog>
23
+ #include < QSortFilterProxyModel>
23
24
24
25
#include " qgsbrowsermodel.h"
25
- #include " qgsdataitem.h"
26
26
#include " qgslogger.h"
27
27
#include " qgsmaplayerregistry.h"
28
28
#include " qgsrasterlayer.h"
@@ -81,8 +81,141 @@ class QgsBrowserTreeView : public QTreeView
81
81
}
82
82
};
83
83
84
+ class QgsBrowserTreeFilterProxyModel : public QSortFilterProxyModel
85
+ {
86
+ public:
87
+
88
+ QgsBrowserTreeFilterProxyModel ( QObject *parent )
89
+ : QSortFilterProxyModel( parent ), mModel ( 0 ),
90
+ mFilter ( " " ), mPatternSyntax( QRegExp::Wildcard )
91
+ {
92
+ setDynamicSortFilter ( true );
93
+ }
94
+
95
+ void setBrowserModel ( QgsBrowserModel* model )
96
+ {
97
+ mModel = model;
98
+ setSourceModel ( model );
99
+ }
100
+
101
+ void setFilterSyntax ( const QRegExp::PatternSyntax & syntax )
102
+ {
103
+ QgsDebugMsg ( QString ( " syntax = %1" ).arg (( int ) mPatternSyntax ) );
104
+ if ( mPatternSyntax == syntax )
105
+ return ;
106
+ mPatternSyntax = syntax;
107
+ updateFilter ();
108
+ }
109
+
110
+ void setFilter ( const QString & filter )
111
+ {
112
+ QgsDebugMsg ( QString ( " filter = %1" ).arg ( mFilter ) );
113
+ if ( mFilter == filter )
114
+ return ;
115
+ mFilter = filter;
116
+ updateFilter ();
117
+ }
118
+
119
+ void updateFilter ( )
120
+ {
121
+ QgsDebugMsg ( QString ( " filter = %1 syntax = %2" ).arg ( mFilter ).arg (( int ) mPatternSyntax ) );
122
+ mREList .clear ();
123
+ if ( mPatternSyntax == QRegExp::Wildcard ||
124
+ mPatternSyntax == QRegExp::WildcardUnix )
125
+ {
126
+ foreach ( QString f, mFilter .split ( " |" ) )
127
+ {
128
+ QRegExp rx ( f.trimmed () );
129
+ rx.setPatternSyntax ( mPatternSyntax );
130
+ mREList .append ( rx );
131
+ }
132
+ }
133
+ else
134
+ {
135
+ QRegExp rx ( mFilter .trimmed () );
136
+ rx.setPatternSyntax ( mPatternSyntax );
137
+ mREList .append ( rx );
138
+ }
139
+ invalidateFilter ();
140
+ }
141
+
142
+ protected:
143
+
144
+ QgsBrowserModel* mModel ;
145
+ QString mFilter ; // filter string provided
146
+ QVector<QRegExp> mREList ; // list of filters, seperated by "|"
147
+ QRegExp::PatternSyntax mPatternSyntax ;
148
+
149
+ bool filterAcceptsString ( const QString & value ) const
150
+ {
151
+ // return ( filterRegExp().exactMatch( fileInfo.fileName() ) );
152
+ if ( mPatternSyntax == QRegExp::Wildcard ||
153
+ mPatternSyntax == QRegExp::WildcardUnix )
154
+ {
155
+ foreach ( QRegExp rx, mREList )
156
+ {
157
+ QgsDebugMsg ( QString ( " value: [%1] rx: [%2] match: %3" ).arg ( value ).arg ( rx.pattern () ).arg ( rx.exactMatch ( value ) ) );
158
+ if ( rx.exactMatch ( value ) )
159
+ return true ;
160
+ }
161
+ }
162
+ else
163
+ {
164
+ foreach ( QRegExp rx, mREList )
165
+ {
166
+ QgsDebugMsg ( QString ( " value: [%1] rx: [%2] match: %3" ).arg ( value ).arg ( rx.pattern () ).arg ( rx.indexIn ( value ) ) );
167
+ QRegExp rx2 ( " \\ b(mail|letter|correspondence)\\ b" );
168
+ QgsDebugMsg ( QString ( " value: [%1] rx2: [%2] match: %3" ).arg ( value ).arg ( rx2.pattern () ).arg ( rx2.indexIn ( value ) ) );
169
+ QgsDebugMsg ( QString ( " T1 %1" ).arg ( rx2.indexIn ( " I sent you an email" ) ) ); // returns -1 (no match)
170
+ QgsDebugMsg ( QString ( " T2 %2" ).arg ( rx2.indexIn ( " Please write the letter" ) ) ); // returns -1 (no match)
171
+ QgsDebugMsg ( QString ( " T3 %2" ).arg ( rx.indexIn ( " Please write the letter" ) ) ); // returns -1 (no match)
172
+
173
+ if ( rx.indexIn ( value ) != -1 )
174
+ return true ;
175
+ }
176
+ }
177
+ return false ;
178
+ }
179
+
180
+ bool filterAcceptsRow ( int sourceRow,
181
+ const QModelIndex &sourceParent ) const
182
+ {
183
+ // if ( filterRegExp().pattern() == QString( "" ) ) return true;
184
+ if ( mFilter == " " ) return true ;
185
+
186
+ QModelIndex index = sourceModel ()->index ( sourceRow, 0 , sourceParent );
187
+ QgsDataItem* item = mModel ->dataItem ( index );
188
+ QgsDataItem* parentItem = mModel ->dataItem ( sourceParent );
189
+
190
+ // accept "invalid" items and data collections
191
+ if ( ! item )
192
+ return true ;
193
+ if ( qobject_cast<QgsDataCollectionItem*>( item ) )
194
+ return true ;
195
+
196
+ // filter layer items - this could be delegated to the providers but a little overkill
197
+ if ( parentItem && qobject_cast<QgsLayerItem*>( item ) )
198
+ {
199
+ // filter normal files by extension
200
+ if ( qobject_cast<QgsDirectoryItem*>( parentItem ) )
201
+ {
202
+ QFileInfo fileInfo ( item->path () );
203
+ return filterAcceptsString ( fileInfo.fileName () );
204
+ }
205
+ // filter other items (postgis, etc.) by name
206
+ else if ( qobject_cast<QgsDataCollectionItem*>( parentItem ) )
207
+ {
208
+ return filterAcceptsString ( item->name () );
209
+ }
210
+ }
211
+
212
+ // accept anything else
213
+ return true ;
214
+ }
215
+
216
+ };
84
217
QgsBrowserDockWidget::QgsBrowserDockWidget ( QWidget * parent ) :
85
- QDockWidget( parent ), mModel( NULL )
218
+ QDockWidget( parent ), mModel( NULL ), mProxyModel( NULL )
86
219
{
87
220
setupUi ( this );
88
221
@@ -95,11 +228,44 @@ QgsBrowserDockWidget::QgsBrowserDockWidget( QWidget * parent ) :
95
228
mBtnAddLayers ->setIcon ( QgisApp::instance ()->getThemeIcon ( " mActionAdd.png" ) );
96
229
mBtnCollapse ->setIcon ( QgisApp::instance ()->getThemeIcon ( " mActionCollapseTree.png" ) );
97
230
98
- connect ( mBrowserView , SIGNAL ( customContextMenuRequested ( const QPoint & ) ), this , SLOT ( showContextMenu ( const QPoint & ) ) );
99
- connect ( mBrowserView , SIGNAL ( doubleClicked ( const QModelIndex& ) ), this , SLOT ( addLayerAtIndex ( const QModelIndex& ) ) );
231
+ mWidgetFilter ->hide ();
232
+ // icons from http://www.fatcow.com/free-icons License: CC Attribution 3.0
233
+ mBtnFilterShow ->setIcon ( QgisApp::instance ()->getThemeIcon ( " mActionFilter.png" ) );
234
+ mBtnFilter ->setIcon ( QgisApp::instance ()->getThemeIcon ( " mActionFilter.png" ) );
235
+ mBtnFilterClear ->setIcon ( QgisApp::instance ()->getThemeIcon ( " mActionFilterDelete.png" ) );
236
+
237
+ QMenu* menu = new QMenu ( this );
238
+ menu->setSeparatorsCollapsible ( false );
239
+ mBtnFilterOptions ->setMenu ( menu );
240
+ QActionGroup* group = new QActionGroup ( menu );
241
+ QAction* action = new QAction ( tr ( " Filter Pattern Syntax" ), group );
242
+ action->setSeparator ( true );
243
+ menu->addAction ( action );
244
+ // group->addAction( action );
245
+ action = new QAction ( tr ( " Wildcard(s)" ), group );
246
+ action->setData ( QVariant (( int ) QRegExp::Wildcard ) );
247
+ action->setCheckable ( true );
248
+ action->setChecked ( true );
249
+ menu->addAction ( action );
250
+ // group->addAction( action );
251
+ // menu->addSeparator()->setText( tr( "Pattern Syntax" ) );
252
+ action = new QAction ( tr ( " Regular Expression" ), group );
253
+ action->setData ( QVariant (( int ) QRegExp::RegExp ) );
254
+ action->setCheckable ( true );
255
+ menu->addAction ( action );
256
+ // group->addAction( action );
257
+
100
258
connect ( mBtnRefresh , SIGNAL ( clicked () ), this , SLOT ( refresh () ) );
101
259
connect ( mBtnAddLayers , SIGNAL ( clicked () ), this , SLOT ( addSelectedLayers () ) );
102
260
connect ( mBtnCollapse , SIGNAL ( clicked () ), mBrowserView , SLOT ( collapseAll () ) );
261
+ connect ( mBtnFilterShow , SIGNAL ( toggled ( bool ) ), this , SLOT ( showFilterWidget ( bool ) ) );
262
+ connect ( mBtnFilter , SIGNAL ( clicked () ), this , SLOT ( setFilter () ) );
263
+ connect ( mLeFilter , SIGNAL ( returnPressed () ), this , SLOT ( setFilter () ) );
264
+ connect ( mBtnFilterClear , SIGNAL ( clicked () ), this , SLOT ( clearFilter () ) );
265
+ connect ( group, SIGNAL ( triggered ( QAction * ) ), this , SLOT ( setFilterSyntax ( QAction * ) ) );
266
+
267
+ connect ( mBrowserView , SIGNAL ( customContextMenuRequested ( const QPoint & ) ), this , SLOT ( showContextMenu ( const QPoint & ) ) );
268
+ connect ( mBrowserView , SIGNAL ( doubleClicked ( const QModelIndex& ) ), this , SLOT ( addLayerAtIndex ( const QModelIndex& ) ) );
103
269
}
104
270
105
271
void QgsBrowserDockWidget::showEvent ( QShowEvent * e )
@@ -108,8 +274,19 @@ void QgsBrowserDockWidget::showEvent( QShowEvent * e )
108
274
if ( mModel == NULL )
109
275
{
110
276
mModel = new QgsBrowserModel ( mBrowserView );
111
- mBrowserView ->setModel ( mModel );
112
277
278
+ bool useFilter = true ;
279
+ if ( useFilter ) // enable proxy model
280
+ {
281
+ // mBrowserView->setModel( mModel );
282
+ mProxyModel = new QgsBrowserTreeFilterProxyModel ( this );
283
+ mProxyModel ->setBrowserModel ( mModel );
284
+ mBrowserView ->setModel ( mProxyModel );
285
+ }
286
+ else
287
+ {
288
+ mBrowserView ->setModel ( mModel );
289
+ }
113
290
// provide a horizontal scroll bar instead of using ellipse (...) for longer items
114
291
mBrowserView ->setTextElideMode ( Qt::ElideNone );
115
292
mBrowserView ->header ()->setResizeMode ( 0 , QHeaderView::ResizeToContents );
@@ -131,7 +308,7 @@ void QgsBrowserDockWidget::showEvent( QShowEvent * e )
131
308
void QgsBrowserDockWidget::showContextMenu ( const QPoint & pt )
132
309
{
133
310
QModelIndex idx = mBrowserView ->indexAt ( pt );
134
- QgsDataItem* item = mModel -> dataItem ( idx );
311
+ QgsDataItem* item = dataItem ( idx );
135
312
if ( !item )
136
313
return ;
137
314
@@ -188,7 +365,7 @@ void QgsBrowserDockWidget::showContextMenu( const QPoint & pt )
188
365
189
366
void QgsBrowserDockWidget::addFavourite ()
190
367
{
191
- QgsDataItem* item = mModel -> dataItem ( mBrowserView ->currentIndex () );
368
+ QgsDataItem* item = dataItem ( mBrowserView ->currentIndex () );
192
369
if ( !item )
193
370
return ;
194
371
@@ -220,7 +397,8 @@ void QgsBrowserDockWidget::addFavouriteDirectory( QString favDir )
220
397
221
398
void QgsBrowserDockWidget::removeFavourite ()
222
399
{
223
- QgsDataItem* item = mModel ->dataItem ( mBrowserView ->currentIndex () );
400
+ QgsDataItem* item = dataItem ( mBrowserView ->currentIndex () );
401
+
224
402
if ( !item )
225
403
return ;
226
404
if ( item->type () != QgsDataItem::Directory )
@@ -249,7 +427,7 @@ void QgsBrowserDockWidget::refreshModel( const QModelIndex& index )
249
427
QgsDebugMsg ( " Entered" );
250
428
if ( index.isValid () )
251
429
{
252
- QgsDataItem *item = mModel -> dataItem ( index );
430
+ QgsDataItem *item = dataItem ( index );
253
431
if ( item )
254
432
{
255
433
QgsDebugMsg ( " path = " + item->path () );
@@ -297,11 +475,11 @@ void QgsBrowserDockWidget::addLayer( QgsLayerItem *layerItem )
297
475
298
476
void QgsBrowserDockWidget::addLayerAtIndex ( const QModelIndex& index )
299
477
{
300
- QgsDataItem *dataItem = mModel -> dataItem ( index );
478
+ QgsDataItem *item = dataItem ( index );
301
479
302
- if ( dataItem != NULL && dataItem ->type () == QgsDataItem::Layer )
480
+ if ( item != NULL && item ->type () == QgsDataItem::Layer )
303
481
{
304
- QgsLayerItem *layerItem = qobject_cast<QgsLayerItem*>( dataItem );
482
+ QgsLayerItem *layerItem = qobject_cast<QgsLayerItem*>( item );
305
483
if ( layerItem != NULL )
306
484
{
307
485
QApplication::setOverrideCursor ( Qt::WaitCursor );
@@ -328,10 +506,10 @@ void QgsBrowserDockWidget::addSelectedLayers()
328
506
for ( int i = list.size () - 1 ; i >= 0 ; i-- )
329
507
{
330
508
QModelIndex index = list[i];
331
- QgsDataItem *dataItem = mModel -> dataItem ( index );
332
- if ( dataItem && dataItem ->type () == QgsDataItem::Layer )
509
+ QgsDataItem *item = dataItem ( index );
510
+ if ( item && item ->type () == QgsDataItem::Layer )
333
511
{
334
- QgsLayerItem *layerItem = qobject_cast<QgsLayerItem*>( dataItem );
512
+ QgsLayerItem *layerItem = qobject_cast<QgsLayerItem*>( item );
335
513
if ( layerItem )
336
514
addLayer ( layerItem );
337
515
}
@@ -343,11 +521,12 @@ void QgsBrowserDockWidget::addSelectedLayers()
343
521
void QgsBrowserDockWidget::showProperties ( )
344
522
{
345
523
QgsDebugMsg ( " Entered" );
346
- QgsDataItem* dataItem = mModel ->dataItem ( mBrowserView ->currentIndex () );
524
+ QModelIndex index = mBrowserView ->currentIndex ();
525
+ QgsDataItem* item = dataItem ( index );
347
526
348
- if ( dataItem != NULL && dataItem ->type () == QgsDataItem::Layer )
527
+ if ( item != NULL && item ->type () == QgsDataItem::Layer )
349
528
{
350
- QgsLayerItem *layerItem = qobject_cast<QgsLayerItem*>( dataItem );
529
+ QgsLayerItem *layerItem = qobject_cast<QgsLayerItem*>( item );
351
530
if ( layerItem != NULL )
352
531
{
353
532
QgsMapLayer::LayerType type = layerItem->mapLayerType ();
@@ -424,3 +603,38 @@ void QgsBrowserDockWidget::showProperties( )
424
603
}
425
604
}
426
605
606
+ void QgsBrowserDockWidget::showFilterWidget ( bool visible )
607
+ {
608
+ mWidgetFilter ->setVisible ( visible );
609
+ if ( ! visible )
610
+ clearFilter ();
611
+ }
612
+
613
+ void QgsBrowserDockWidget::setFilter ( )
614
+ {
615
+ QString filter = mLeFilter ->text ();
616
+ if ( mProxyModel )
617
+ mProxyModel ->setFilter ( filter );
618
+ }
619
+
620
+ void QgsBrowserDockWidget::setFilterSyntax ( QAction * action )
621
+ {
622
+ if ( !action || ! mProxyModel )
623
+ return ;
624
+ mProxyModel ->setFilterSyntax (( QRegExp::PatternSyntax ) action->data ().toInt () );
625
+ }
626
+
627
+ void QgsBrowserDockWidget::clearFilter ( )
628
+ {
629
+ mLeFilter ->setText ( " " );
630
+ setFilter ();
631
+ }
632
+
633
+ QgsDataItem* QgsBrowserDockWidget::dataItem ( const QModelIndex& index )
634
+ {
635
+ if ( ! mProxyModel )
636
+ return mModel ->dataItem ( index );
637
+ else
638
+ return mModel ->dataItem ( mProxyModel ->mapToSource ( index ) );
639
+ }
640
+
0 commit comments