Skip to content

Commit

Permalink
Show locator filter names in results, sort results and group by filter
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed May 17, 2017
1 parent 0dd3fcb commit 0f80df0
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 10 deletions.
14 changes: 14 additions & 0 deletions python/gui/locator/qgslocatorfilter.sip
Expand Up @@ -71,6 +71,20 @@ class QgsLocatorFilter : QObject
Constructor for QgsLocatorFilter.
%End

virtual QString name() const = 0;
%Docstring
Returns the unique name for the filter. This should be an untranslated string identifying the filter.
.. seealso:: displayName()
:rtype: str
%End

virtual QString displayName() const = 0;
%Docstring
Returns a translated, user-friendly name for the filter.
.. seealso:: name()
:rtype: str
%End

virtual void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) = 0;
%Docstring
Retrieves the filter results for a specified search ``string``. The ``context``
Expand Down
6 changes: 6 additions & 0 deletions python/plugins/processing/gui/AlgorithmLocatorFilter.py
Expand Up @@ -39,6 +39,12 @@ class AlgorithmLocatorFilter(QgsLocatorFilter):
def __init__(self, parent=None):
super(AlgorithmLocatorFilter, self).__init__(parent)

def name(self):
return 'processing_alg'

def displayName(self):
return self.tr('Processing Algorithms')

def fetchResults(self,string,context,feedback):
for a in QgsApplication.processingRegistry().algorithms():
if feedback.isCanceled():
Expand Down
9 changes: 9 additions & 0 deletions src/app/locator/qgsinbuiltlocatorfilters.h
Expand Up @@ -28,6 +28,9 @@ class QgsLayerTreeLocatorFilter : public QgsLocatorFilter
public:

QgsLayerTreeLocatorFilter( QObject *parent = nullptr );
virtual QString name() const override { return QStringLiteral( "layertree" ); }
virtual QString displayName() const override { return tr( "Project layers" ); }

void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
void triggerResult( const QgsLocatorResult &result ) override;

Expand All @@ -40,6 +43,9 @@ class QgsLayoutLocatorFilter : public QgsLocatorFilter
public:

QgsLayoutLocatorFilter( QObject *parent = nullptr );
virtual QString name() const override { return QStringLiteral( "layouts" ); }
virtual QString displayName() const override { return tr( "Project layouts" ); }

void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
void triggerResult( const QgsLocatorResult &result ) override;

Expand All @@ -52,6 +58,9 @@ class QgsActionLocatorFilter : public QgsLocatorFilter
public:

QgsActionLocatorFilter( const QList<QWidget *> &parentObjectsForActions, QObject *parent = nullptr );
virtual QString name() const override { return QStringLiteral( "actions" ); }
virtual QString displayName() const override { return tr( "Actions" ); }

void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
void triggerResult( const QgsLocatorResult &result ) override;
private:
Expand Down
12 changes: 12 additions & 0 deletions src/gui/locator/qgslocatorfilter.h
Expand Up @@ -91,6 +91,18 @@ class GUI_EXPORT QgsLocatorFilter : public QObject
*/
QgsLocatorFilter( QObject *parent = nullptr );

/**
* Returns the unique name for the filter. This should be an untranslated string identifying the filter.
* \see displayName()
*/
virtual QString name() const = 0;

/**
* Returns a translated, user-friendly name for the filter.
* \see name()
*/
virtual QString displayName() const = 0;

/**
* Retrieves the filter results for a specified search \a string. The \a context
* argument encapsulates the context relating to the search (such as a map
Expand Down
98 changes: 89 additions & 9 deletions src/gui/locator/qgslocatorwidget.cpp
Expand Up @@ -63,7 +63,9 @@ QgsLocatorWidget::QgsLocatorWidget( QWidget *parent )
mResultsContainer->setLayout( containerLayout );
mResultsContainer->hide();

mResultsView->setModel( mLocatorModel );
mProxyModel = new QgsLocatorProxyModel( mLocatorModel );
mProxyModel->setSourceModel( mLocatorModel );
mResultsView->setModel( mProxyModel );
mResultsView->recalculateSize();

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

void QgsLocatorWidget::addResult( const QgsLocatorResult &result )
{
bool selectFirst = mLocatorModel->rowCount() == 0;
bool selectFirst = mProxyModel->rowCount() == 0;
mLocatorModel->addResult( result );
if ( selectFirst )
mResultsView->setCurrentIndex( mLocatorModel->index( 0, 0 ) );
mResultsView->setCurrentIndex( mProxyModel->index( 1, 0 ) );
}

void QgsLocatorWidget::updateResults( const QString &text )
Expand Down Expand Up @@ -234,7 +236,7 @@ void QgsLocatorWidget::acceptCurrentEntry()
if ( !index.isValid() )
return;

QgsLocatorResult result = mLocatorModel->data( index, QgsLocatorModel::ResultDataRole ).value< QgsLocatorResult >();
QgsLocatorResult result = mProxyModel->data( index, QgsLocatorModel::ResultDataRole ).value< QgsLocatorResult >();
mResultsContainer->hide();
mLineEdit->clearFocus();
result.filter->triggerResult( result );
Expand Down Expand Up @@ -266,6 +268,7 @@ void QgsLocatorModel::clear()
{
beginResetModel();
mResults.clear();
mFoundResultsFromFilterNames.clear();
endResetModel();
}

Expand All @@ -289,22 +292,73 @@ QVariant QgsLocatorModel::data( const QModelIndex &index, int role ) const
{
case Qt::DisplayRole:
case Qt::EditRole:
return mResults.at( index.row() ).displayString;
{
if ( mResults.at( index.row() ).filterTitle.isEmpty() )
return mResults.at( index.row() ).result.displayString;
else
return mResults.at( index.row() ).filterTitle;
}

case Qt::DecorationRole:
return mResults.at( index.row() ).icon;
if ( mResults.at( index.row() ).filterTitle.isEmpty() )
return mResults.at( index.row() ).result.icon;
else
return QVariant();

case ResultDataRole:
return QVariant::fromValue( mResults.at( index.row() ) );
if ( mResults.at( index.row() ).filterTitle.isEmpty() )
return QVariant::fromValue( mResults.at( index.row() ).result );
else
return QVariant();

case ResultTypeRole:
if ( mResults.at( index.row() ).filterTitle.isEmpty() )
return 1;
else
return 0;

case ResultFilterNameRole:
if ( mResults.at( index.row() ).filterTitle.isEmpty() )
return mResults.at( index.row() ).result.filter->displayName();
else
return mResults.at( index.row() ).filterTitle;
}

return QVariant();
}

Qt::ItemFlags QgsLocatorModel::flags( const QModelIndex &index ) const
{
if ( !index.isValid() || index.row() < 0 || index.column() < 0 ||
index.row() >= rowCount( QModelIndex() ) || index.column() >= columnCount( QModelIndex() ) )
return QAbstractListModel::flags( index );

Qt::ItemFlags flags = QAbstractListModel::flags( index );
if ( !mResults.at( index.row() ).filterTitle.isEmpty() )
{
flags = flags & ~( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
}
return flags;

}

void QgsLocatorModel::addResult( const QgsLocatorResult &result )
{
beginInsertRows( QModelIndex(), mResults.size(), mResults.size() );
mResults << result;
int pos = mResults.size();
bool addingFilter = !mFoundResultsFromFilterNames.contains( result.filter->name() );
if ( addingFilter )
mFoundResultsFromFilterNames << result.filter->name();

beginInsertRows( QModelIndex(), pos, pos + ( addingFilter ? 1 : 0 ) );
if ( addingFilter )
{
Entry entry;
entry.filterTitle = result.filter->displayName();
mResults << entry;
}
Entry entry;
entry.result = result;
mResults << entry;
endInsertRows();
}

Expand Down Expand Up @@ -352,3 +406,29 @@ void QgsLocatorResultsView::selectPreviousResult()

///@endcond


QgsLocatorProxyModel::QgsLocatorProxyModel( QObject *parent )
: QSortFilterProxyModel( parent )
{
setDynamicSortFilter( true );
setSortLocaleAware( true );
setFilterCaseSensitivity( Qt::CaseInsensitive );
sort( 0 );
}

bool QgsLocatorProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
{
QString leftFilter = sourceModel()->data( left, QgsLocatorModel::ResultFilterNameRole ).toString();
QString rightFilter = sourceModel()->data( right, QgsLocatorModel::ResultFilterNameRole ).toString();
if ( leftFilter != rightFilter )
return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;

int leftTypeRole = sourceModel()->data( left, QgsLocatorModel::ResultTypeRole ).toInt();
int rightTypeRole = sourceModel()->data( right, QgsLocatorModel::ResultTypeRole ).toInt();
if ( leftTypeRole != rightTypeRole )
return leftTypeRole < rightTypeRole;

leftFilter = sourceModel()->data( left, Qt::DisplayRole ).toString();
rightFilter = sourceModel()->data( right, Qt::DisplayRole ).toString();
return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;
}
23 changes: 22 additions & 1 deletion src/gui/locator/qgslocatorwidget.h
Expand Up @@ -27,12 +27,14 @@
#include <QFocusEvent>
#include <QHeaderView>
#include <QTimer>
#include <QSortFilterProxyModel>

class QgsLocator;
class QgsFilterLineEdit;
class QgsLocatorModel;
class QgsLocatorResultsView;
class QgsMapCanvas;
class QgsLocatorProxyModel;

/**
* \class QgsLocatorWidget
Expand Down Expand Up @@ -89,6 +91,7 @@ class GUI_EXPORT QgsLocatorWidget : public QWidget
QgsLocator *mLocator = nullptr;
QgsFilterLineEdit *mLineEdit = nullptr;
QgsLocatorModel *mLocatorModel = nullptr;
QgsLocatorProxyModel *mProxyModel = nullptr;
QgsFloatingWidget *mResultsContainer = nullptr;
QgsLocatorResultsView *mResultsView = nullptr;
QgsMapCanvas *mMapCanvas = nullptr;
Expand Down Expand Up @@ -123,6 +126,8 @@ class QgsLocatorModel : public QAbstractListModel
enum Role
{
ResultDataRole = Qt::UserRole + 1, //!< QgsLocatorResult data
ResultTypeRole,
ResultFilterNameRole,
};

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

public slots:

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

private:

QList<QgsLocatorResult> mResults;
struct Entry
{
QgsLocatorResult result;
QString filterTitle;
};

QList<Entry> mResults;
QSet<QString> mFoundResultsFromFilterNames;
};

class QgsLocatorProxyModel : public QSortFilterProxyModel
{
public:

explicit QgsLocatorProxyModel( QObject *parent = nullptr );
bool lessThan( const QModelIndex &left, const QModelIndex &right ) const override;
};

/**
Expand Down

0 comments on commit 0f80df0

Please sign in to comment.