Skip to content
Permalink
Browse files

Merge pull request #6951 from 3nids/locator_prefix

allow customizing prefix of locator filters
  • Loading branch information
3nids committed May 14, 2018
2 parents e0b86be + 395c13f commit 272f9ef8747efe9c22ae1571228b1d033a7172da
@@ -9,6 +9,8 @@





class QgsLocator : QObject
{
%Docstring
@@ -38,6 +40,8 @@ call to fetchResults().
%End
public:

static const QList<QString> CORE_FILTERS;

QgsLocator( QObject *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsLocator.
@@ -69,19 +73,23 @@ deregisterFilter() to deregister their filters upon plugin unload to avoid crash
.. seealso:: :py:func:`registerFilter`
%End

QList< QgsLocatorFilter *> filters();
QList< QgsLocatorFilter *> filters( const QString &prefix = QString() );
%Docstring
Returns the list of filters registered in the locator.

:param prefix: If prefix is not empty, the list returned corresponds to the filter with the given active prefix

.. seealso:: :py:func:`prefixedFilters`
%End

QMap< QString, QgsLocatorFilter *> prefixedFilters() const;
QMap<QString, QgsLocatorFilter *> prefixedFilters() const;
%Docstring
Returns a map of prefix to filter, for all registered filters
with valid prefixes.

.. seealso:: :py:func:`filters`

.. deprecated:: since QGIS 3.2 use filters() instead
%End

void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback = 0 );
@@ -124,6 +124,12 @@ results from this filter.
as these are reserved for core QGIS functions. If a plugin registers
a filter with a prefix shorter than 3 characters then the prefix will
be ignored.

.. note::

Prefixes might be overridden by user preferences.

.. seealso:: :py:func:`activePrefix`
%End

virtual void prepare( const QString &string, const QgsLocatorContext &context );
@@ -177,6 +183,17 @@ is entered.
.. seealso:: :py:func:`useWithoutPrefix`
%End

QString activePrefix() const;
%Docstring
Returns the prefix in use in the locator
is entered.

.. seealso:: :py:func:`setActivePrefix`

.. versionadded:: 3.2
%End


static bool stringMatches( const QString &candidate, const QString &search );
%Docstring
Tests a ``candidate`` string to see if it should be considered a match for
@@ -180,13 +180,13 @@ for I in $(seq -f '%02g' 0 $(($SPLIT-1)) ) ; do
# also make error small case and escape special chars: () |
ERRORSMALLCASE=$(echo ${ERRORNOCOLOR,,} |${GP}sed -r 's/\(/\\(/g' | ${GP}sed -r 's/\)/\\)/g' | ${GP}sed -r 's/\|/\\|/g' )
if [[ ! "${ERRORSMALLCASE}" =~ $IGNORECASE_INWORD ]]; then
if [[ -n $(ag --nonumbers --case-sensitive "^${ERRORSMALLCASE:1:-1}${ERRORSMALLCASE: -1}?:" scripts/spell_check/spelling.dat) ]]; then
if [[ -n $(ag --noaffinity --nonumbers --case-sensitive "^${ERRORSMALLCASE:1:-1}${ERRORSMALLCASE: -1}?:" scripts/spell_check/spelling.dat) ]]; then
PREVCHAR=${ERROR::1}
# remove first character
ERRORSMALLCASE=${ERRORSMALLCASE#?}
ERROR=${ERROR#?}
fi
if [[ -n $(ag --nonumbers --case-sensitive "^${ERRORSMALLCASE::-1}:" scripts/spell_check/spelling.dat) ]]; then
if [[ -n $(ag --noaffinity --nonumbers --case-sensitive "^${ERRORSMALLCASE::-1}:" scripts/spell_check/spelling.dat) ]]; then
NEXTCHAR=${ERROR:${#ERROR}-1:1}
# remove last character
ERRORSMALLCASE=${ERRORSMALLCASE::-1}
@@ -196,9 +196,9 @@ for I in $(seq -f '%02g' 0 $(($SPLIT-1)) ) ; do
ERRORSMALLCASE=$(${GP}sed -r 's/\./\\./g' <<< $ERRORSMALLCASE)

# get correction from spelling.dat
CORRECTION=$(ag --nonumbers --case-sensitive "^${ERRORSMALLCASE}:" ${DIR}/spelling.dat | cut -d: -f2)
CORRECTION=$(ag --noaffinity --nonumbers --case-sensitive "^${ERRORSMALLCASE}:" ${DIR}/spelling.dat | cut -d: -f2)
# exclude script files
if [[ "$(ag --nonumbers --case-sensitive "^${ERRORSMALLCASE}:" ${DIR}/spelling.dat | cut -d: -f3)" =~ "%" ]]; then
if [[ "$(ag --noaffinity --nonumbers --case-sensitive "^${ERRORSMALLCASE}:" ${DIR}/spelling.dat | cut -d: -f3)" =~ "%" ]]; then
if [[ "$FILE" =~ $EXCLUDE_SCRIPT_LIST ]]; then
echo "skipping script file for $(${GP}sed -r 's/\\//g' <<< $ERRORSMALLCASE)"
continue
@@ -208,7 +208,7 @@ for I in $(seq -f '%02g' 0 $(($SPLIT-1)) ) ; do
if [[ -z "$CORRECTION" ]]; then
CORRECTION=$(perl -e "use strict; use warnings; while(<>) { chop; my(\$a,\$b) = split /:/; \$a = qr(\$a); if( my @matches = '${ERRORSMALLCASE}' =~ /^\$a\$/i ) { print sprintf(\$b, @matches); last; }}" ${DIR}/spelling.dat )
# exclude script files
if [[ "$(ag --nonumbers --case-sensitive ":${CORRECTION}" ${DIR}/spelling.dat | cut -d: -f3)" =~ "%" ]]; then
if [[ "$(ag --noaffinity --nonumbers --case-sensitive ":${CORRECTION}" ${DIR}/spelling.dat | cut -d: -f3)" =~ "%" ]]; then
if [[ "$FILE" =~ $EXCLUDE_SCRIPT_LIST ]]; then
echo "skipping script file for $(${GP}sed -r 's/\\//g' <<< $ERRORSMALLCASE)"
continue
@@ -16,6 +16,7 @@
***************************************************************************/

#include "qgslocatoroptionswidget.h"

#include "qgslocatorwidget.h"
#include "qgssettings.h"

@@ -119,7 +120,7 @@ QVariant QgsLocatorFiltersModel::data( const QModelIndex &index, int role ) cons
return filterForIndex( index )->displayName();

case Prefix:
return filterForIndex( index )->prefix();
return mPrefixes.value( filterForIndex( index ), filterForIndex( index )->activePrefix() );

case Active:
case Default:
@@ -165,6 +166,34 @@ bool QgsLocatorFiltersModel::setData( const QModelIndex &index, const QVariant &

switch ( role )
{
case Qt::EditRole:
{
switch ( index.column() )
{
case Name:
case Active:
case Default:
return false;

case Prefix:
{
QString prefix = value.toString();
if ( !prefix.isEmpty() )
{
mPrefixes.insert( filterForIndex( index ), prefix );
}
else
{
// reset to the native prefix
mPrefixes.insert( filterForIndex( index ), filterForIndex( index )->prefix() );
}
emit dataChanged( index, index );
return true;
}
}
}


case Qt::CheckStateRole:
{
bool checked = static_cast< Qt::CheckState >( value.toInt() ) == Qt::Checked;
@@ -203,7 +232,10 @@ Qt::ItemFlags QgsLocatorFiltersModel::flags( const QModelIndex &index ) const
switch ( index.column() )
{
case Name:
break;

case Prefix:
flags = flags | Qt::ItemIsEditable;
break;

case Active:
@@ -242,6 +274,22 @@ void QgsLocatorFiltersModel::commitChanges()
{
QgsSettings settings;

QHash< QgsLocatorFilter *, QString >::const_iterator itp = mPrefixes.constBegin();
for ( ; itp != mPrefixes.constEnd(); ++itp )
{
QgsLocatorFilter *filter = itp.key();
QString activePrefix = itp.value();
if ( !activePrefix.isEmpty() && activePrefix != filter->prefix() )
{
filter->setActivePrefix( activePrefix );
settings.setValue( QStringLiteral( "locator_filters/prefix_%1" ).arg( filter->name() ), activePrefix, QgsSettings::Section::Gui );
}
else
{
filter->setActivePrefix( QString() );
settings.remove( QStringLiteral( "locator_filters/prefix_%1" ).arg( filter->name() ), QgsSettings::Section::Gui );
}
}
QHash< QgsLocatorFilter *, bool >::const_iterator it = mEnabledChanges.constBegin();
for ( ; it != mEnabledChanges.constEnd(); ++it )
{
@@ -39,7 +39,6 @@ class QgsLocatorOptionsWidget : public QWidget, private Ui::QgsLocatorOptionsWid
void configureCurrentFilter();

private:

QgsLocatorWidget *mLocatorWidget = nullptr;
QgsLocator *mLocator = nullptr;
QgsLocatorFiltersModel *mModel = nullptr;
@@ -97,6 +96,7 @@ class QgsLocatorFiltersModel : public QAbstractTableModel
QgsLocator *mLocator = nullptr;

// changes are deferred to support cancelation
QHash< QgsLocatorFilter *, QString > mPrefixes;
QHash< QgsLocatorFilter *, bool > mEnabledChanges;
QHash< QgsLocatorFilter *, bool > mDefaultChanges;

@@ -20,6 +20,14 @@
#include <QtConcurrent>
#include <functional>

const QList<QString> QgsLocator::CORE_FILTERS = QList<QString>() << QStringLiteral( "actions" )
<< QStringLiteral( "processing_alg" )
<< QStringLiteral( "layertree" )
<< QStringLiteral( "layouts" )
<< QStringLiteral( "features" )
<< QStringLiteral( "calculator" )
<< QStringLiteral( "bookmarks" );

QgsLocator::QgsLocator( QObject *parent )
: QObject( parent )
{
@@ -36,48 +44,76 @@ void QgsLocator::deregisterFilter( QgsLocatorFilter *filter )
{
cancelRunningQuery();
mFilters.removeAll( filter );
QString key = mPrefixedFilters.key( filter );
if ( !key.isEmpty() )
mPrefixedFilters.remove( key );
delete filter;
}

QList<QgsLocatorFilter *> QgsLocator::filters()
QList<QgsLocatorFilter *> QgsLocator::filters( const QString &prefix )
{
return mFilters;
if ( !prefix.isEmpty() )
{
QList<QgsLocatorFilter *> filters = QList<QgsLocatorFilter *>();
for ( QgsLocatorFilter *filter : mFilters )
{
if ( !filter->activePrefix().isEmpty() && filter->activePrefix() == prefix )
{
filters << filter;
}
}
return filters;
}
else
{
return mFilters;
}
}

QMap<QString, QgsLocatorFilter *> QgsLocator::prefixedFilters() const
{
return mPrefixedFilters;
QMap<QString, QgsLocatorFilter *> filters = QMap<QString, QgsLocatorFilter *>();
for ( QgsLocatorFilter *filter : mFilters )
{
if ( !filter->activePrefix().isEmpty() && filter->enabled() )
{
filters.insertMulti( filter->activePrefix(), filter );
}
}
return filters;
}

void QgsLocator::registerFilter( QgsLocatorFilter *filter )
{
mFilters.append( filter );
filter->setParent( this );

if ( !filter->prefix().isEmpty() )
// restore settings
QgsSettings settings;
bool enabled = settings.value( QStringLiteral( "locator_filters/enabled_%1" ).arg( filter->name() ), true, QgsSettings::Section::Gui ).toBool();
bool byDefault = settings.value( QStringLiteral( "locator_filters/default_%1" ).arg( filter->name() ), filter->useWithoutPrefix(), QgsSettings::Section::Gui ).toBool();
QString prefix = settings.value( QStringLiteral( "locator_filters/prefix_%1" ).arg( filter->name() ), filter->prefix(), QgsSettings::Section::Gui ).toString();
if ( prefix.isEmpty() )
{
prefix = filter->prefix();
}

if ( !prefix.isEmpty() )
{
if ( filter->name() == QStringLiteral( "actions" ) || filter->name() == QStringLiteral( "processing_alg" )
|| filter->name() == QStringLiteral( "layertree" ) || filter->name() == QStringLiteral( "layouts" )
|| filter->name() == QStringLiteral( "features" ) || filter->name() == QStringLiteral( "calculator" )
|| filter->name() == QStringLiteral( "bookmarks" ) )
if ( CORE_FILTERS.contains( filter->name() ) )
{
//inbuilt filter, no prefix check
mPrefixedFilters.insert( filter->prefix(), filter );
filter->setActivePrefix( prefix );
}
else if ( prefix.length() >= 3 || prefix != filter->prefix() )
{
// for plugins either the native prefix is >3 char or it has been customized by user
filter->setActivePrefix( prefix );
}
else if ( filter->prefix().length() >= 3 )
else
{
mPrefixedFilters.insert( filter->prefix(), filter );
// otherwise set it to empty string (not NULL)
filter->setActivePrefix( QString( "" ) );
}
}

// restore settings
QgsSettings settings;
bool enabled = settings.value( QStringLiteral( "locator_filters/enabled_%1" ).arg( filter->name() ), true, QgsSettings::Section::Gui ).toBool();
bool byDefault = settings.value( QStringLiteral( "locator_filters/default_%1" ).arg( filter->name() ), filter->useWithoutPrefix(), QgsSettings::Section::Gui ).toBool();

filter->setEnabled( enabled );
filter->setUseWithoutPrefix( byDefault );
}
@@ -105,22 +141,30 @@ void QgsLocator::fetchResults( const QString &string, const QgsLocatorContext &c

QList< QgsLocatorFilter * > activeFilters;
QString searchString = string;
if ( searchString.indexOf( ' ' ) > 0 )
QString prefix = searchString.left( std::max( searchString.indexOf( ' ' ), 0 ) );
if ( !prefix.isEmpty() )
{
QString prefix = searchString.left( searchString.indexOf( ' ' ) );
if ( mPrefixedFilters.contains( prefix ) && mPrefixedFilters.value( prefix )->enabled() )
for ( QgsLocatorFilter *filter : qgis::as_const( mFilters ) )
{
activeFilters << mPrefixedFilters.value( prefix );
searchString = searchString.mid( prefix.length() + 1 );
if ( filter->activePrefix() == prefix && filter->enabled() )
{
activeFilters << filter;
}
}
context.usingPrefix = !activeFilters.empty();
}
if ( activeFilters.isEmpty() )
if ( !activeFilters.isEmpty() )
{
searchString = searchString.mid( prefix.length() + 1 );
}
else
{
for ( QgsLocatorFilter *filter : qgis::as_const( mFilters ) )
{
if ( filter->useWithoutPrefix() && filter->enabled() )
{
activeFilters << filter;
}
}
}

0 comments on commit 272f9ef

Please sign in to comment.
You can’t perform that action at this time.