27#include "moc_qgslocatormodel.cpp"
34 : QAbstractTableModel( parent )
36 mDeferredClearTimer.setInterval( 100 );
37 mDeferredClearTimer.setSingleShot(
true );
43 mDeferredClearTimer.stop();
44 mDeferredClear =
false;
48 mFoundResultsFromFilterNames.clear();
49 mFoundResultsFilterGroups.clear();
55 mDeferredClear =
true;
56 mDeferredClearTimer.start();
61 return mResults.count();
71 if ( !index.isValid() || index.row() < 0 || index.column() < 0 ||
72 index.row() >=
rowCount( QModelIndex() ) || index.column() >=
columnCount( QModelIndex() ) )
75 const Entry &entry = mResults.at( index.row() );
81 switch (
static_cast<Column
>( index.column() ) )
88 case EntryType::Filter:
90 v = entry.filterTitle;
94 case EntryType::Group:
96 v = QStringLiteral(
" " ).append( entry.groupTitle );
100 case EntryType::Result:
111 if ( entry.type == EntryType::Result )
121 if ( index.column() == Name )
124 font.setBold( entry.type == EntryType::Filter );
125 font.setItalic( entry.type == EntryType::Group );
135 case Qt::BackgroundRole:
137 return entry.type == EntryType::Result ? QPalette().base() : QPalette().alternateBase();
140 case Qt::ForegroundRole:
142 return QPalette().text();
146 case Qt::DecorationRole:
147 switch (
static_cast<Column
>( index.column() ) )
150 if ( entry.type == EntryType::Result )
152 const QIcon &icon = entry.result.
icon;
153 if ( !icon.isNull() )
165 if ( entry.type == EntryType::Result )
166 return QVariant::fromValue( entry.result );
171 return static_cast<int>( entry.type );
177 return ( entry.result.
score );
183 return entry.filterTitle;
186 return entry.groupTitle;
189 return entry.groupScore;
192 return QVariant::fromValue( entry.result.
actions );
200 if ( !index.isValid() || index.row() < 0 || index.column() < 0 ||
201 index.row() >=
rowCount( QModelIndex() ) || index.column() >=
columnCount( QModelIndex() ) )
202 return QAbstractTableModel::flags( index );
204 Qt::ItemFlags
flags = QAbstractTableModel::flags( index );
205 if ( mResults.at( index.row() ).type != QgsLocatorModel::EntryType::Result )
207 flags =
flags & ~( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
214 QHash<int, QByteArray> roles;
224 roles[Qt::DisplayRole] =
"Text";
230 mDeferredClearTimer.stop();
231 if ( mDeferredClear )
233 mFoundResultsFromFilterNames.clear();
234 mFoundResultsFilterGroups.clear();
237 const int pos = mResults.size();
238 const bool addingFilter = !result.
filter->
displayName().isEmpty() && !mFoundResultsFromFilterNames.contains( result.
filter->
name() );
240 mFoundResultsFromFilterNames << result.
filter->
name();
242 const bool addingGroup = !result.
group.isEmpty() && ( !mFoundResultsFilterGroups.contains( result.
filter )
243 || !mFoundResultsFilterGroups.value( result.
filter ).contains( std::pair( result.
group, result.
groupScore ) ) );
246 if ( !mFoundResultsFilterGroups.contains( result.
filter ) )
247 mFoundResultsFilterGroups[result.
filter] = QList<std::pair<QString, double>>();
252 if ( mDeferredClear )
259 beginInsertRows( QModelIndex(), pos, pos + (
static_cast<int>( addingFilter ) +
static_cast<int>( addingGroup ) ) );
266 entry.type = EntryType::Filter;
268 entry.filter = result.
filter;
274 entry.type = EntryType::Group;
276 entry.groupTitle = result.
group;
277 entry.groupScore = groupScore;
278 entry.filter = result.
filter;
282 entry.type = EntryType::Result;
283 entry.filter = result.
filter;
285 entry.result = result;
286 entry.groupTitle = result.
group;
287 entry.groupScore = groupScore;
290 if ( mDeferredClear )
295 mDeferredClear =
false;
307 Q_ASSERT( mLocator );
319 if ( mLocator->isRunning() )
324 mLocator->cancelWithoutBlocking();
325 mNextRequestedString = string;
326 mHasQueuedRequest =
true;
341void QgsLocatorAutomaticModel::searchFinished()
343 if ( mHasQueuedRequest )
346 const QString nextSearch = mNextRequestedString;
347 mNextRequestedString.clear();
348 mHasQueuedRequest =
false;
362 : QSortFilterProxyModel( parent )
364 setDynamicSortFilter(
true );
365 setSortLocaleAware(
true );
366 setFilterCaseSensitivity( Qt::CaseInsensitive );
375 const QAbstractItemModel *lSourceModel = sourceModel();
376 const int leftFilterPriority = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultFilterPriority ) ).toInt();
377 const int rightFilterPriority = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultFilterPriority ) ).toInt();
378 if ( leftFilterPriority != rightFilterPriority )
379 return leftFilterPriority < rightFilterPriority;
382 QString leftFilter = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultFilterName ) ).toString();
383 QString rightFilter = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultFilterName ) ).toString();
384 if ( leftFilter != rightFilter )
385 return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;
388 const int leftTypeRole = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultType ) ).toInt();
389 const int rightTypeRole = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultType ) ).toInt();
390 if ( leftTypeRole != rightTypeRole && ( leftTypeRole == 0 || rightTypeRole == 0 ) )
391 return leftTypeRole < rightTypeRole;
394 const double leftGroupScoreRole = lSourceModel->data( left,
static_cast< double >( CustomRole::ResultFilterGroupScore ) ).toDouble();
395 const double rightGroupScoreRole = lSourceModel->data( right,
static_cast< double >( CustomRole::ResultFilterGroupScore ) ).toDouble();
396 if ( leftGroupScoreRole != rightGroupScoreRole )
397 return leftGroupScoreRole > rightGroupScoreRole;
400 QString leftGroupTitle = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultFilterGroupTitle ) ).toString();
401 QString rightGroupTitle = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultFilterGroupTitle ) ).toString();
402 if ( leftGroupTitle != rightGroupTitle )
403 return QString::localeAwareCompare( leftGroupTitle, rightGroupTitle ) < 0;
406 if ( leftTypeRole != rightTypeRole )
407 return leftTypeRole < rightTypeRole;
410 const double leftScore = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultScore ) ).toDouble();
411 const double rightScore = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultScore ) ).toDouble();
413 return leftScore > rightScore;
416 leftFilter = lSourceModel->data( left, Qt::DisplayRole ).toString();
417 rightFilter = lSourceModel->data( right, Qt::DisplayRole ).toString();
418 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).