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 || index.row() >=
rowCount( QModelIndex() ) || index.column() >=
columnCount( QModelIndex() ) )
77 const Entry &entry = mResults.at( index.row() );
83 switch (
static_cast<Column
>( index.column() ) )
90 case EntryType::Filter:
92 v = entry.filterTitle;
96 case EntryType::Group:
98 v = u
" "_s.append( entry.groupTitle );
102 case EntryType::Result:
113 if ( entry.type == EntryType::Result )
123 if ( index.column() == Name )
126 font.setBold( entry.type == EntryType::Filter );
127 font.setItalic( entry.type == EntryType::Group );
137 case Qt::BackgroundRole:
139 return entry.type == EntryType::Result ? QPalette().base() : QPalette().alternateBase();
142 case Qt::ForegroundRole:
144 return QPalette().text();
148 case Qt::DecorationRole:
149 switch (
static_cast<Column
>( index.column() ) )
152 if ( entry.type == EntryType::Result )
154 const QIcon &icon = entry.result.
icon;
155 if ( !icon.isNull() )
167 if ( entry.type == EntryType::Result )
168 return QVariant::fromValue( entry.result );
173 return static_cast<int>( entry.type );
179 return ( entry.result.
score );
185 return entry.filterTitle;
188 return entry.groupTitle;
191 return entry.groupScore;
194 return QVariant::fromValue( entry.result.
actions );
202 if ( !index.isValid() || index.row() < 0 || index.column() < 0 || index.row() >=
rowCount( QModelIndex() ) || index.column() >=
columnCount( QModelIndex() ) )
203 return QAbstractTableModel::flags( index );
205 Qt::ItemFlags
flags = QAbstractTableModel::flags( index );
206 if ( mResults.at( index.row() ).type != QgsLocatorModel::EntryType::Result )
208 flags =
flags & ~( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
215 QHash<int, QByteArray> roles;
225 roles[Qt::DisplayRole] =
"Text";
231 mDeferredClearTimer.stop();
232 if ( mDeferredClear )
234 mFoundResultsFromFilterNames.clear();
235 mFoundResultsFilterGroups.clear();
238 const int pos = mResults.size();
239 const bool addingFilter = !result.
filter->
displayName().isEmpty() && !mFoundResultsFromFilterNames.contains( result.
filter->
name() );
241 mFoundResultsFromFilterNames << result.
filter->
name();
243 const bool addingGroup = !result.
group.isEmpty()
244 && ( !mFoundResultsFilterGroups.contains( result.
filter ) || !mFoundResultsFilterGroups.value( result.
filter ).contains( std::pair( result.
group, result.
groupScore ) ) );
247 if ( !mFoundResultsFilterGroups.contains( result.
filter ) )
248 mFoundResultsFilterGroups[result.
filter] = QList<std::pair<QString, double>>();
253 if ( mDeferredClear )
260 beginInsertRows( QModelIndex(), pos, pos + (
static_cast<int>( addingFilter ) +
static_cast<int>( addingGroup ) ) );
267 entry.type = EntryType::Filter;
269 entry.filter = result.
filter;
275 entry.type = EntryType::Group;
277 entry.groupTitle = result.
group;
278 entry.groupScore = groupScore;
279 entry.filter = result.
filter;
283 entry.type = EntryType::Result;
284 entry.filter = result.
filter;
286 entry.result = result;
287 entry.groupTitle = result.
group;
288 entry.groupScore = groupScore;
291 if ( mDeferredClear )
296 mDeferredClear =
false;
308 Q_ASSERT( mLocator );
320 if ( mLocator->isRunning() )
325 mLocator->cancelWithoutBlocking();
326 mNextRequestedString = string;
327 mHasQueuedRequest =
true;
342void QgsLocatorAutomaticModel::searchFinished()
344 if ( mHasQueuedRequest )
347 const QString nextSearch = mNextRequestedString;
348 mNextRequestedString.clear();
349 mHasQueuedRequest =
false;
360 : QSortFilterProxyModel( parent )
362 setDynamicSortFilter(
true );
363 setSortLocaleAware(
true );
364 setFilterCaseSensitivity( Qt::CaseInsensitive );
373 const QAbstractItemModel *lSourceModel = sourceModel();
374 const int leftFilterPriority = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultFilterPriority ) ).toInt();
375 const int rightFilterPriority = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultFilterPriority ) ).toInt();
376 if ( leftFilterPriority != rightFilterPriority )
377 return leftFilterPriority < rightFilterPriority;
380 QString leftFilter = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultFilterName ) ).toString();
381 QString rightFilter = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultFilterName ) ).toString();
382 if ( leftFilter != rightFilter )
383 return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;
386 const int leftTypeRole = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultType ) ).toInt();
387 const int rightTypeRole = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultType ) ).toInt();
388 if ( leftTypeRole != rightTypeRole && ( leftTypeRole == 0 || rightTypeRole == 0 ) )
389 return leftTypeRole < rightTypeRole;
392 const double leftGroupScoreRole = lSourceModel->data( left,
static_cast< double >( CustomRole::ResultFilterGroupScore ) ).toDouble();
393 const double rightGroupScoreRole = lSourceModel->data( right,
static_cast< double >( CustomRole::ResultFilterGroupScore ) ).toDouble();
394 if ( leftGroupScoreRole != rightGroupScoreRole )
395 return leftGroupScoreRole > rightGroupScoreRole;
398 QString leftGroupTitle = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultFilterGroupTitle ) ).toString();
399 QString rightGroupTitle = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultFilterGroupTitle ) ).toString();
400 if ( leftGroupTitle != rightGroupTitle )
401 return QString::localeAwareCompare( leftGroupTitle, rightGroupTitle ) < 0;
404 if ( leftTypeRole != rightTypeRole )
405 return leftTypeRole < rightTypeRole;
408 const double leftScore = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultScore ) ).toDouble();
409 const double rightScore = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultScore ) ).toDouble();
411 return leftScore > rightScore;
414 leftFilter = lSourceModel->data( left, Qt::DisplayRole ).toString();
415 rightFilter = lSourceModel->data( right, Qt::DisplayRole ).toString();
416 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).