Skip to content

Commit

Permalink
[QgsLocator] add the capability of adding group for elements within t…
Browse files Browse the repository at this point in the history
…he same filter
  • Loading branch information
3nids committed May 18, 2018
1 parent 56104bc commit c1e1696
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 12 deletions.
2 changes: 2 additions & 0 deletions python/core/auto_generated/locator/qgslocatorfilter.sip.in
Expand Up @@ -45,6 +45,8 @@ Constructor for QgsLocatorResult.

double score;

QString group;

};

class QgsLocatorFilter : QObject
Expand Down
3 changes: 3 additions & 0 deletions python/core/auto_generated/locator/qgslocatormodel.sip.in
Expand Up @@ -26,13 +26,16 @@ in order to ensure correct sorting of results by priority and match level.
%End
public:

static const int NoGroup;

enum Role
{
ResultDataRole,
ResultTypeRole,
ResultFilterPriorityRole,
ResultScoreRole,
ResultFilterNameRole,
ResultFilterGroupSortingRole,
};

QgsLocatorModel( QObject *parent /TransferThis/ = 0 );
Expand Down
4 changes: 2 additions & 2 deletions scripts/sipify.pl
Expand Up @@ -409,9 +409,9 @@ sub detect_comment_block{
}

# Detect if line is a non method member declaration
# https://regex101.com/r/gUBZUk/13
# https://regex101.com/r/gUBZUk/14
sub detect_non_method_member{
return 1 if $LINE =~ m/^\s*(?:template\s*<\w+>\s+)?(?:(const|mutable|static|friend|unsigned)\s+)*\w+(::\w+)?(<([\w<> *&,()]|::)+>)?(,?\s+\*?\w+( = (-?\d+(\.\d+)?|((QMap|QList)<[^()]+>\(\))|(\w+::)*\w+(\([^()]+\))?)|\[\d+\])?)+;/;
return 1 if $LINE =~ m/^\s*(?:template\s*<\w+>\s+)?(?:(const|mutable|static|friend|unsigned)\s+)*\w+(::\w+)?(<([\w<> *&,()]|::)+>)?(,?\s+\*?\w+( = (-?\d+(\.\d+)?|((QMap|QList)<[^()]+>\(\))|(\w+::)*\w+(\([^()]?\))?)|\[\d+\])?)+;/;
return 0;
}

Expand Down
9 changes: 9 additions & 0 deletions src/core/locator/qgslocatorfilter.h
Expand Up @@ -82,6 +82,15 @@ class CORE_EXPORT QgsLocatorResult
*/
double score = 0.5;

/**
* Group the results by categories
* If left as empty string, this means that results are all shown without being grouped.
* If a group is given, the results will be grouped by \a group under a header.
* \note This should be translated.
* \since 3.2
*/
QString group = QString();

};

/**
Expand Down
70 changes: 62 additions & 8 deletions src/core/locator/qgslocatormodel.cpp
Expand Up @@ -15,12 +15,14 @@
* *
***************************************************************************/

#include <QFont>

#include "qgslocatormodel.h"
#include "qgslocator.h"
#include "qgsapplication.h"
#include "qgslogger.h"


//
// QgsLocatorModel
//
Expand All @@ -41,6 +43,7 @@ void QgsLocatorModel::clear()
beginResetModel();
mResults.clear();
mFoundResultsFromFilterNames.clear();
mFoundResultsFilterGroups.clear();
endResetModel();
}

Expand Down Expand Up @@ -76,8 +79,14 @@ QVariant QgsLocatorModel::data( const QModelIndex &index, int role ) const
case Name:
if ( !mResults.at( index.row() ).filter )
return mResults.at( index.row() ).result.displayString;
else
else if ( mResults.at( index.row() ).filter && mResults.at( index.row() ).groupSorting == 0 )
return mResults.at( index.row() ).filterTitle;
else
{
QString groupTitle = mResults.at( index.row() ).groupTitle;
groupTitle.prepend( " " );
return groupTitle;
}
case Description:
if ( !mResults.at( index.row() ).filter )
return mResults.at( index.row() ).result.description;
Expand All @@ -87,6 +96,19 @@ QVariant QgsLocatorModel::data( const QModelIndex &index, int role ) const
break;
}

case Qt::FontRole:
if ( index.column() == Name && !mResults.at( index.row() ).groupTitle.isEmpty() )
{
QFont font;
font.setItalic( true );
return font;
}
else
{
return QVariant();
}
break;

case Qt::DecorationRole:
switch ( index.column() )
{
Expand All @@ -112,10 +134,8 @@ QVariant QgsLocatorModel::data( const QModelIndex &index, int role ) const
return QVariant();

case ResultTypeRole:
if ( mResults.at( index.row() ).filter )
return 0;
else
return 1;
// 0 for filter title, the group otherwise, 9999 if no group
return mResults.at( index.row() ).groupSorting;

case ResultScoreRole:
if ( mResults.at( index.row() ).filter )
Expand All @@ -134,6 +154,12 @@ QVariant QgsLocatorModel::data( const QModelIndex &index, int role ) const
return mResults.at( index.row() ).result.filter->displayName();
else
return mResults.at( index.row() ).filterTitle;

case ResultFilterGroupSortingRole:
if ( mResults.at( index.row() ).groupTitle.isEmpty() )
return 1;
else
return 0;
}

return QVariant();
Expand All @@ -146,7 +172,7 @@ Qt::ItemFlags QgsLocatorModel::flags( const QModelIndex &index ) const
return QAbstractTableModel::flags( index );

Qt::ItemFlags flags = QAbstractTableModel::flags( index );
if ( !mResults.at( index.row() ).filterTitle.isEmpty() )
if ( mResults.at( index.row() ).filter )
{
flags = flags & ~( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
}
Expand All @@ -159,20 +185,29 @@ void QgsLocatorModel::addResult( const QgsLocatorResult &result )
if ( mDeferredClear )
{
mFoundResultsFromFilterNames.clear();
mFoundResultsFilterGroups.clear();
}

int pos = mResults.size();
bool addingFilter = !result.filter->displayName().isEmpty() && !mFoundResultsFromFilterNames.contains( result.filter->name() );
if ( addingFilter )
mFoundResultsFromFilterNames << result.filter->name();

bool addingGroup = !result.group.isEmpty() && ( !mFoundResultsFilterGroups.contains( result.filter )
|| !mFoundResultsFilterGroups.value( result.filter ).contains( result.group ) );
if ( addingGroup )
{
if ( !mFoundResultsFilterGroups.contains( result.filter ) )
mFoundResultsFilterGroups[result.filter] = QStringList();
mFoundResultsFilterGroups[result.filter] << result.group ;
}
if ( mDeferredClear )
{
beginResetModel();
mResults.clear();
}
else
beginInsertRows( QModelIndex(), pos, pos + ( addingFilter ? 1 : 0 ) );
beginInsertRows( QModelIndex(), pos, pos + ( static_cast<int>( addingFilter ) + static_cast<int>( addingGroup ) ) );

if ( addingFilter )
{
Expand All @@ -181,8 +216,21 @@ void QgsLocatorModel::addResult( const QgsLocatorResult &result )
entry.filter = result.filter;
mResults << entry;
}
if ( addingGroup )
{
Entry entry;
entry.filterTitle = result.filter->displayName();
entry.groupTitle = result.group;
// the sorting of groups will be achieved by order of adding groups
// this could be customized by adding the extra info to QgsLocatorResult
entry.groupSorting = mFoundResultsFilterGroups[result.filter].count();
entry.filter = result.filter;
mResults << entry;
}
Entry entry;
entry.result = result;
// keep the group title empty to allow differecing group title from results
entry.groupSorting = result.group.isEmpty() ? NoGroup : mFoundResultsFilterGroups[result.filter].count();
mResults << entry;

if ( mDeferredClear )
Expand Down Expand Up @@ -279,12 +327,18 @@ bool QgsLocatorProxyModel::lessThan( const QModelIndex &left, const QModelIndex
if ( leftFilter != rightFilter )
return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;

// then make sure filter title appears before filter's results
// then make sure filter title or group appears before filter's results
int leftTypeRole = sourceModel()->data( left, QgsLocatorModel::ResultTypeRole ).toInt();
int rightTypeRole = sourceModel()->data( right, QgsLocatorModel::ResultTypeRole ).toInt();
if ( leftTypeRole != rightTypeRole )
return leftTypeRole < rightTypeRole;

// make sure group title are above
int leftGroupRole = sourceModel()->data( left, QgsLocatorModel::ResultFilterGroupSortingRole ).toInt();
int rightGroupRole = sourceModel()->data( right, QgsLocatorModel::ResultFilterGroupSortingRole ).toInt();
if ( leftGroupRole != rightGroupRole )
return leftGroupRole < rightGroupRole;

// sort filter's results by score
double leftScore = sourceModel()->data( left, QgsLocatorModel::ResultScoreRole ).toDouble();
double rightScore = sourceModel()->data( right, QgsLocatorModel::ResultScoreRole ).toDouble();
Expand Down
6 changes: 6 additions & 0 deletions src/core/locator/qgslocatormodel.h
Expand Up @@ -45,6 +45,8 @@ class CORE_EXPORT QgsLocatorModel : public QAbstractTableModel

public:

static const int NoGroup = 9999;

//! Custom model roles
enum Role
{
Expand All @@ -53,6 +55,7 @@ class CORE_EXPORT QgsLocatorModel : public QAbstractTableModel
ResultFilterPriorityRole, //!< Result priority, used by QgsLocatorProxyModel for sorting roles.
ResultScoreRole, //!< Result match score, used by QgsLocatorProxyModel for sorting roles.
ResultFilterNameRole, //!< Associated filter name which created the result
ResultFilterGroupSortingRole, //!< Group results within the same filter results
};

/**
Expand Down Expand Up @@ -99,10 +102,13 @@ class CORE_EXPORT QgsLocatorModel : public QAbstractTableModel
QgsLocatorResult result;
QString filterTitle;
QgsLocatorFilter *filter = nullptr;
QString groupTitle = QString();
int groupSorting = 0;
};

QList<Entry> mResults;
QSet<QString> mFoundResultsFromFilterNames;
QMap<QgsLocatorFilter *, QStringList> mFoundResultsFilterGroups;
bool mDeferredClear = false;
QTimer mDeferredClearTimer;
};
Expand Down
11 changes: 9 additions & 2 deletions src/gui/locator/qgslocatorwidget.cpp
Expand Up @@ -252,8 +252,15 @@ void QgsLocatorWidget::addResult( const QgsLocatorResult &result )
mLocatorModel->addResult( result );
if ( selectFirst )
{
int row = mProxyModel->flags( mProxyModel->index( 0, 0 ) ) & Qt::ItemIsSelectable ? 0 : 1;
mResultsView->setCurrentIndex( mProxyModel->index( row, 0 ) );
int row = -1;
bool selectable = false;
while ( !selectable && row < mProxyModel->rowCount() )
{
row++;
selectable = mProxyModel->flags( mProxyModel->index( row, 0 ) ).testFlag( Qt::ItemIsSelectable );
}
if ( selectable )
mResultsView->setCurrentIndex( mProxyModel->index( row, 0 ) );
}
}

Expand Down

0 comments on commit c1e1696

Please sign in to comment.