Skip to content

Commit 0f80df0

Browse files
committedMay 17, 2017
Show locator filter names in results, sort results and group by filter
1 parent 0dd3fcb commit 0f80df0

File tree

6 files changed

+152
-10
lines changed

6 files changed

+152
-10
lines changed
 

‎python/gui/locator/qgslocatorfilter.sip

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,20 @@ class QgsLocatorFilter : QObject
7171
Constructor for QgsLocatorFilter.
7272
%End
7373

74+
virtual QString name() const = 0;
75+
%Docstring
76+
Returns the unique name for the filter. This should be an untranslated string identifying the filter.
77+
.. seealso:: displayName()
78+
:rtype: str
79+
%End
80+
81+
virtual QString displayName() const = 0;
82+
%Docstring
83+
Returns a translated, user-friendly name for the filter.
84+
.. seealso:: name()
85+
:rtype: str
86+
%End
87+
7488
virtual void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) = 0;
7589
%Docstring
7690
Retrieves the filter results for a specified search ``string``. The ``context``

‎python/plugins/processing/gui/AlgorithmLocatorFilter.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ class AlgorithmLocatorFilter(QgsLocatorFilter):
3939
def __init__(self, parent=None):
4040
super(AlgorithmLocatorFilter, self).__init__(parent)
4141

42+
def name(self):
43+
return 'processing_alg'
44+
45+
def displayName(self):
46+
return self.tr('Processing Algorithms')
47+
4248
def fetchResults(self,string,context,feedback):
4349
for a in QgsApplication.processingRegistry().algorithms():
4450
if feedback.isCanceled():

‎src/app/locator/qgsinbuiltlocatorfilters.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ class QgsLayerTreeLocatorFilter : public QgsLocatorFilter
2828
public:
2929

3030
QgsLayerTreeLocatorFilter( QObject *parent = nullptr );
31+
virtual QString name() const override { return QStringLiteral( "layertree" ); }
32+
virtual QString displayName() const override { return tr( "Project layers" ); }
33+
3134
void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
3235
void triggerResult( const QgsLocatorResult &result ) override;
3336

@@ -40,6 +43,9 @@ class QgsLayoutLocatorFilter : public QgsLocatorFilter
4043
public:
4144

4245
QgsLayoutLocatorFilter( QObject *parent = nullptr );
46+
virtual QString name() const override { return QStringLiteral( "layouts" ); }
47+
virtual QString displayName() const override { return tr( "Project layouts" ); }
48+
4349
void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
4450
void triggerResult( const QgsLocatorResult &result ) override;
4551

@@ -52,6 +58,9 @@ class QgsActionLocatorFilter : public QgsLocatorFilter
5258
public:
5359

5460
QgsActionLocatorFilter( const QList<QWidget *> &parentObjectsForActions, QObject *parent = nullptr );
61+
virtual QString name() const override { return QStringLiteral( "actions" ); }
62+
virtual QString displayName() const override { return tr( "Actions" ); }
63+
5564
void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
5665
void triggerResult( const QgsLocatorResult &result ) override;
5766
private:

‎src/gui/locator/qgslocatorfilter.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,18 @@ class GUI_EXPORT QgsLocatorFilter : public QObject
9191
*/
9292
QgsLocatorFilter( QObject *parent = nullptr );
9393

94+
/**
95+
* Returns the unique name for the filter. This should be an untranslated string identifying the filter.
96+
* \see displayName()
97+
*/
98+
virtual QString name() const = 0;
99+
100+
/**
101+
* Returns a translated, user-friendly name for the filter.
102+
* \see name()
103+
*/
104+
virtual QString displayName() const = 0;
105+
94106
/**
95107
* Retrieves the filter results for a specified search \a string. The \a context
96108
* argument encapsulates the context relating to the search (such as a map

‎src/gui/locator/qgslocatorwidget.cpp

Lines changed: 89 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ QgsLocatorWidget::QgsLocatorWidget( QWidget *parent )
6363
mResultsContainer->setLayout( containerLayout );
6464
mResultsContainer->hide();
6565

66-
mResultsView->setModel( mLocatorModel );
66+
mProxyModel = new QgsLocatorProxyModel( mLocatorModel );
67+
mProxyModel->setSourceModel( mLocatorModel );
68+
mResultsView->setModel( mProxyModel );
6769
mResultsView->recalculateSize();
6870

6971
connect( mLocator, &QgsLocator::foundResult, this, &QgsLocatorWidget::addResult );
@@ -191,10 +193,10 @@ bool QgsLocatorWidget::eventFilter( QObject *obj, QEvent *event )
191193

192194
void QgsLocatorWidget::addResult( const QgsLocatorResult &result )
193195
{
194-
bool selectFirst = mLocatorModel->rowCount() == 0;
196+
bool selectFirst = mProxyModel->rowCount() == 0;
195197
mLocatorModel->addResult( result );
196198
if ( selectFirst )
197-
mResultsView->setCurrentIndex( mLocatorModel->index( 0, 0 ) );
199+
mResultsView->setCurrentIndex( mProxyModel->index( 1, 0 ) );
198200
}
199201

200202
void QgsLocatorWidget::updateResults( const QString &text )
@@ -234,7 +236,7 @@ void QgsLocatorWidget::acceptCurrentEntry()
234236
if ( !index.isValid() )
235237
return;
236238

237-
QgsLocatorResult result = mLocatorModel->data( index, QgsLocatorModel::ResultDataRole ).value< QgsLocatorResult >();
239+
QgsLocatorResult result = mProxyModel->data( index, QgsLocatorModel::ResultDataRole ).value< QgsLocatorResult >();
238240
mResultsContainer->hide();
239241
mLineEdit->clearFocus();
240242
result.filter->triggerResult( result );
@@ -266,6 +268,7 @@ void QgsLocatorModel::clear()
266268
{
267269
beginResetModel();
268270
mResults.clear();
271+
mFoundResultsFromFilterNames.clear();
269272
endResetModel();
270273
}
271274

@@ -289,22 +292,73 @@ QVariant QgsLocatorModel::data( const QModelIndex &index, int role ) const
289292
{
290293
case Qt::DisplayRole:
291294
case Qt::EditRole:
292-
return mResults.at( index.row() ).displayString;
295+
{
296+
if ( mResults.at( index.row() ).filterTitle.isEmpty() )
297+
return mResults.at( index.row() ).result.displayString;
298+
else
299+
return mResults.at( index.row() ).filterTitle;
300+
}
293301

294302
case Qt::DecorationRole:
295-
return mResults.at( index.row() ).icon;
303+
if ( mResults.at( index.row() ).filterTitle.isEmpty() )
304+
return mResults.at( index.row() ).result.icon;
305+
else
306+
return QVariant();
296307

297308
case ResultDataRole:
298-
return QVariant::fromValue( mResults.at( index.row() ) );
309+
if ( mResults.at( index.row() ).filterTitle.isEmpty() )
310+
return QVariant::fromValue( mResults.at( index.row() ).result );
311+
else
312+
return QVariant();
313+
314+
case ResultTypeRole:
315+
if ( mResults.at( index.row() ).filterTitle.isEmpty() )
316+
return 1;
317+
else
318+
return 0;
319+
320+
case ResultFilterNameRole:
321+
if ( mResults.at( index.row() ).filterTitle.isEmpty() )
322+
return mResults.at( index.row() ).result.filter->displayName();
323+
else
324+
return mResults.at( index.row() ).filterTitle;
299325
}
300326

301327
return QVariant();
302328
}
303329

330+
Qt::ItemFlags QgsLocatorModel::flags( const QModelIndex &index ) const
331+
{
332+
if ( !index.isValid() || index.row() < 0 || index.column() < 0 ||
333+
index.row() >= rowCount( QModelIndex() ) || index.column() >= columnCount( QModelIndex() ) )
334+
return QAbstractListModel::flags( index );
335+
336+
Qt::ItemFlags flags = QAbstractListModel::flags( index );
337+
if ( !mResults.at( index.row() ).filterTitle.isEmpty() )
338+
{
339+
flags = flags & ~( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
340+
}
341+
return flags;
342+
343+
}
344+
304345
void QgsLocatorModel::addResult( const QgsLocatorResult &result )
305346
{
306-
beginInsertRows( QModelIndex(), mResults.size(), mResults.size() );
307-
mResults << result;
347+
int pos = mResults.size();
348+
bool addingFilter = !mFoundResultsFromFilterNames.contains( result.filter->name() );
349+
if ( addingFilter )
350+
mFoundResultsFromFilterNames << result.filter->name();
351+
352+
beginInsertRows( QModelIndex(), pos, pos + ( addingFilter ? 1 : 0 ) );
353+
if ( addingFilter )
354+
{
355+
Entry entry;
356+
entry.filterTitle = result.filter->displayName();
357+
mResults << entry;
358+
}
359+
Entry entry;
360+
entry.result = result;
361+
mResults << entry;
308362
endInsertRows();
309363
}
310364

@@ -352,3 +406,29 @@ void QgsLocatorResultsView::selectPreviousResult()
352406

353407
///@endcond
354408

409+
410+
QgsLocatorProxyModel::QgsLocatorProxyModel( QObject *parent )
411+
: QSortFilterProxyModel( parent )
412+
{
413+
setDynamicSortFilter( true );
414+
setSortLocaleAware( true );
415+
setFilterCaseSensitivity( Qt::CaseInsensitive );
416+
sort( 0 );
417+
}
418+
419+
bool QgsLocatorProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
420+
{
421+
QString leftFilter = sourceModel()->data( left, QgsLocatorModel::ResultFilterNameRole ).toString();
422+
QString rightFilter = sourceModel()->data( right, QgsLocatorModel::ResultFilterNameRole ).toString();
423+
if ( leftFilter != rightFilter )
424+
return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;
425+
426+
int leftTypeRole = sourceModel()->data( left, QgsLocatorModel::ResultTypeRole ).toInt();
427+
int rightTypeRole = sourceModel()->data( right, QgsLocatorModel::ResultTypeRole ).toInt();
428+
if ( leftTypeRole != rightTypeRole )
429+
return leftTypeRole < rightTypeRole;
430+
431+
leftFilter = sourceModel()->data( left, Qt::DisplayRole ).toString();
432+
rightFilter = sourceModel()->data( right, Qt::DisplayRole ).toString();
433+
return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;
434+
}

‎src/gui/locator/qgslocatorwidget.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@
2727
#include <QFocusEvent>
2828
#include <QHeaderView>
2929
#include <QTimer>
30+
#include <QSortFilterProxyModel>
3031

3132
class QgsLocator;
3233
class QgsFilterLineEdit;
3334
class QgsLocatorModel;
3435
class QgsLocatorResultsView;
3536
class QgsMapCanvas;
37+
class QgsLocatorProxyModel;
3638

3739
/**
3840
* \class QgsLocatorWidget
@@ -89,6 +91,7 @@ class GUI_EXPORT QgsLocatorWidget : public QWidget
8991
QgsLocator *mLocator = nullptr;
9092
QgsFilterLineEdit *mLineEdit = nullptr;
9193
QgsLocatorModel *mLocatorModel = nullptr;
94+
QgsLocatorProxyModel *mProxyModel = nullptr;
9295
QgsFloatingWidget *mResultsContainer = nullptr;
9396
QgsLocatorResultsView *mResultsView = nullptr;
9497
QgsMapCanvas *mMapCanvas = nullptr;
@@ -123,6 +126,8 @@ class QgsLocatorModel : public QAbstractListModel
123126
enum Role
124127
{
125128
ResultDataRole = Qt::UserRole + 1, //!< QgsLocatorResult data
129+
ResultTypeRole,
130+
ResultFilterNameRole,
126131
};
127132

128133
/**
@@ -138,6 +143,7 @@ class QgsLocatorModel : public QAbstractListModel
138143
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
139144
int columnCount( const QModelIndex &parent = QModelIndex() ) const override;
140145
QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
146+
Qt::ItemFlags flags( const QModelIndex &index ) const override;
141147

142148
public slots:
143149

@@ -148,7 +154,22 @@ class QgsLocatorModel : public QAbstractListModel
148154

149155
private:
150156

151-
QList<QgsLocatorResult> mResults;
157+
struct Entry
158+
{
159+
QgsLocatorResult result;
160+
QString filterTitle;
161+
};
162+
163+
QList<Entry> mResults;
164+
QSet<QString> mFoundResultsFromFilterNames;
165+
};
166+
167+
class QgsLocatorProxyModel : public QSortFilterProxyModel
168+
{
169+
public:
170+
171+
explicit QgsLocatorProxyModel( QObject *parent = nullptr );
172+
bool lessThan( const QModelIndex &left, const QModelIndex &right ) const override;
152173
};
153174

154175
/**

0 commit comments

Comments
 (0)
Please sign in to comment.