28#include "moc_qgslocatormodel.cpp"
30using namespace Qt::StringLiterals;
37 : QAbstractTableModel( parent )
39 mDeferredClearTimer.setInterval( 100 );
40 mDeferredClearTimer.setSingleShot(
true );
46 mDeferredClearTimer.stop();
47 mDeferredClear =
false;
51 mFoundResultsFromFilterNames.clear();
52 mFoundResultsFilterGroups.clear();
58 mDeferredClear =
true;
59 mDeferredClearTimer.start();
64 return mResults.count();
74 if ( !index.isValid() || index.row() < 0 || index.column() < 0 ||
75 index.row() >=
rowCount( QModelIndex() ) || index.column() >=
columnCount( QModelIndex() ) )
78 const Entry &entry = mResults.at( index.row() );
84 switch (
static_cast<Column
>( index.column() ) )
91 case EntryType::Filter:
93 v = entry.filterTitle;
97 case EntryType::Group:
99 v = u
" "_s.append( entry.groupTitle );
103 case EntryType::Result:
114 if ( entry.type == EntryType::Result )
124 if ( index.column() == Name )
127 font.setBold( entry.type == EntryType::Filter );
128 font.setItalic( entry.type == EntryType::Group );
138 case Qt::BackgroundRole:
140 return entry.type == EntryType::Result ? QPalette().base() : QPalette().alternateBase();
143 case Qt::ForegroundRole:
145 return QPalette().text();
149 case Qt::DecorationRole:
150 switch (
static_cast<Column
>( index.column() ) )
153 if ( entry.type == EntryType::Result )
155 const QIcon &icon = entry.result.
icon;
156 if ( !icon.isNull() )
168 if ( entry.type == EntryType::Result )
169 return QVariant::fromValue( entry.result );
174 return static_cast<int>( entry.type );
180 return ( entry.result.
score );
186 return entry.filterTitle;
189 return entry.groupTitle;
192 return entry.groupScore;
195 return QVariant::fromValue( entry.result.
actions );
203 if ( !index.isValid() || index.row() < 0 || index.column() < 0 ||
204 index.row() >=
rowCount( QModelIndex() ) || index.column() >=
columnCount( QModelIndex() ) )
205 return QAbstractTableModel::flags( index );
207 Qt::ItemFlags
flags = QAbstractTableModel::flags( index );
208 if ( mResults.at( index.row() ).type != QgsLocatorModel::EntryType::Result )
210 flags =
flags & ~( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
217 QHash<int, QByteArray> roles;
227 roles[Qt::DisplayRole] =
"Text";
233 mDeferredClearTimer.stop();
234 if ( mDeferredClear )
236 mFoundResultsFromFilterNames.clear();
237 mFoundResultsFilterGroups.clear();
240 const int pos = mResults.size();
241 const bool addingFilter = !result.
filter->
displayName().isEmpty() && !mFoundResultsFromFilterNames.contains( result.
filter->
name() );
243 mFoundResultsFromFilterNames << result.
filter->
name();
245 const bool addingGroup = !result.
group.isEmpty() && ( !mFoundResultsFilterGroups.contains( result.
filter )
246 || !mFoundResultsFilterGroups.value( result.
filter ).contains( std::pair( result.
group, result.
groupScore ) ) );
249 if ( !mFoundResultsFilterGroups.contains( result.
filter ) )
250 mFoundResultsFilterGroups[result.
filter] = QList<std::pair<QString, double>>();
255 if ( mDeferredClear )
262 beginInsertRows( QModelIndex(), pos, pos + (
static_cast<int>( addingFilter ) +
static_cast<int>( addingGroup ) ) );
269 entry.type = EntryType::Filter;
271 entry.filter = result.
filter;
277 entry.type = EntryType::Group;
279 entry.groupTitle = result.
group;
280 entry.groupScore = groupScore;
281 entry.filter = result.
filter;
285 entry.type = EntryType::Result;
286 entry.filter = result.
filter;
288 entry.result = result;
289 entry.groupTitle = result.
group;
290 entry.groupScore = groupScore;
293 if ( mDeferredClear )
298 mDeferredClear =
false;
310 Q_ASSERT( mLocator );
322 if ( mLocator->isRunning() )
327 mLocator->cancelWithoutBlocking();
328 mNextRequestedString = string;
329 mHasQueuedRequest =
true;
344void QgsLocatorAutomaticModel::searchFinished()
346 if ( mHasQueuedRequest )
349 const QString nextSearch = mNextRequestedString;
350 mNextRequestedString.clear();
351 mHasQueuedRequest =
false;
365 : QSortFilterProxyModel( parent )
367 setDynamicSortFilter(
true );
368 setSortLocaleAware(
true );
369 setFilterCaseSensitivity( Qt::CaseInsensitive );
378 const QAbstractItemModel *lSourceModel = sourceModel();
379 const int leftFilterPriority = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultFilterPriority ) ).toInt();
380 const int rightFilterPriority = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultFilterPriority ) ).toInt();
381 if ( leftFilterPriority != rightFilterPriority )
382 return leftFilterPriority < rightFilterPriority;
385 QString leftFilter = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultFilterName ) ).toString();
386 QString rightFilter = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultFilterName ) ).toString();
387 if ( leftFilter != rightFilter )
388 return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;
391 const int leftTypeRole = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultType ) ).toInt();
392 const int rightTypeRole = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultType ) ).toInt();
393 if ( leftTypeRole != rightTypeRole && ( leftTypeRole == 0 || rightTypeRole == 0 ) )
394 return leftTypeRole < rightTypeRole;
397 const double leftGroupScoreRole = lSourceModel->data( left,
static_cast< double >( CustomRole::ResultFilterGroupScore ) ).toDouble();
398 const double rightGroupScoreRole = lSourceModel->data( right,
static_cast< double >( CustomRole::ResultFilterGroupScore ) ).toDouble();
399 if ( leftGroupScoreRole != rightGroupScoreRole )
400 return leftGroupScoreRole > rightGroupScoreRole;
403 QString leftGroupTitle = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultFilterGroupTitle ) ).toString();
404 QString rightGroupTitle = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultFilterGroupTitle ) ).toString();
405 if ( leftGroupTitle != rightGroupTitle )
406 return QString::localeAwareCompare( leftGroupTitle, rightGroupTitle ) < 0;
409 if ( leftTypeRole != rightTypeRole )
410 return leftTypeRole < rightTypeRole;
413 const double leftScore = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultScore ) ).toDouble();
414 const double rightScore = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultScore ) ).toDouble();
416 return leftScore > rightScore;
419 leftFilter = lSourceModel->data( left, Qt::DisplayRole ).toString();
420 rightFilter = lSourceModel->data( right, Qt::DisplayRole ).toString();
421 return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
QgsLocator * locator()
Returns a pointer to the locator utilized by this model.
QgsLocatorAutomaticModel(QgsLocator *locator)
Constructor for QgsLocatorAutomaticModel, linked with the specified locator.
void search(const QString &string)
Enqueues a search for a specified string within the model.
virtual QgsLocatorContext createContext()
Returns a new locator context for searches.
Encapsulates the properties relating to the context of a locator search.
virtual QString displayName() const =0
Returns a translated, user-friendly name for the filter.
virtual Priority priority() const
Returns the priority for the filter, which controls how results are ordered in the locator.
virtual QString name() const =0
Returns the unique name for the filter.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
void deferredClear()
Resets the model and clears all existing results after a short delay, or whenever the next result is ...
CustomRole
Custom model roles.
@ ResultFilterGroupTitle
Group title.
@ ResultScore
Result match score, used by QgsLocatorProxyModel for sorting roles.
@ ResultFilterPriority
Result priority, used by QgsLocatorProxyModel for sorting roles.
@ ResultFilterGroupScore
Group score.
@ ResultFilterName
Associated filter name which created the result.
@ ResultData
QgsLocatorResult data.
@ ResultFilterGroupSorting
Custom value for sorting.
@ ResultActions
The actions to be shown for the given result in a context menu.
Qt::ItemFlags flags(const QModelIndex &index) const override
QHash< int, QByteArray > roleNames() const override
void addResult(const QgsLocatorResult &result)
Adds a new result to the model.
QgsLocatorModel(QObject *parent=nullptr)
Constructor for QgsLocatorModel.
void clear()
Resets the model and clears all existing results.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
QgsLocatorProxyModel(QObject *parent=nullptr)
Constructor for QgsLocatorProxyModel, with the specified parent object.
Encapsulates properties of an individual matching result found by a QgsLocatorFilter.
QList< QgsLocatorResult::ResultAction > actions
Additional actions to be used in a locator widget for the given result.
QString description
Descriptive text for result.
double score
Match score, from 0 - 1, where 1 represents a perfect match.
double groupScore
Specifies the score of the group to allow ordering.
QString displayString
String displayed for result.
QString group
Group the results by categories If left as empty string, this means that results are all shown withou...
QgsLocatorFilter * filter
Filter from which the result was obtained.
QIcon icon
Icon for result.
Handles the management of QgsLocatorFilter objects and async collection of search results from them.
void finished()
Emitted when locator has finished a query, either as a result of successful completion or early cance...
void foundResult(const QgsLocatorResult &result)
Emitted whenever a filter encounters a matching result after the fetchResults() method is called.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).