22#include "moc_qgslocatormodel.cpp"
33 : QAbstractTableModel( parent )
35 mDeferredClearTimer.setInterval( 100 );
36 mDeferredClearTimer.setSingleShot(
true );
42 mDeferredClearTimer.stop();
43 mDeferredClear =
false;
47 mFoundResultsFromFilterNames.clear();
48 mFoundResultsFilterGroups.clear();
54 mDeferredClear =
true;
55 mDeferredClearTimer.start();
60 return mResults.count();
70 if ( !index.isValid() || index.row() < 0 || index.column() < 0 ||
71 index.row() >=
rowCount( QModelIndex() ) || index.column() >=
columnCount( QModelIndex() ) )
74 const Entry &entry = mResults.at( index.row() );
80 switch (
static_cast<Column
>( index.column() ) )
87 case EntryType::Filter:
89 v = entry.filterTitle;
93 case EntryType::Group:
95 v = QStringLiteral(
" " ).append( entry.groupTitle );
99 case EntryType::Result:
101 v = entry.result.displayString;
110 if ( entry.type == EntryType::Result )
111 return entry.result.description;
120 if ( index.column() == Name )
123 font.setBold( entry.type == EntryType::Filter );
124 font.setItalic( entry.type == EntryType::Group );
134 case Qt::BackgroundRole:
136 return entry.type == EntryType::Result ? QPalette().base() : QPalette().alternateBase();
139 case Qt::ForegroundRole:
141 return QPalette().text();
145 case Qt::DecorationRole:
146 switch (
static_cast<Column
>( index.column() ) )
149 if ( entry.type == EntryType::Result )
151 const QIcon &icon = entry.result.icon;
152 if ( !icon.isNull() )
164 if ( entry.type == EntryType::Result )
165 return QVariant::fromValue( entry.result );
170 return static_cast<int>( entry.type );
176 return ( entry.result.score );
179 return entry.filter->priority();
182 return entry.filterTitle;
185 return entry.groupTitle;
188 return entry.groupScore;
191 return QVariant::fromValue( entry.result.actions );
199 if ( !index.isValid() || index.row() < 0 || index.column() < 0 ||
200 index.row() >=
rowCount( QModelIndex() ) || index.column() >=
columnCount( QModelIndex() ) )
201 return QAbstractTableModel::flags( index );
203 Qt::ItemFlags
flags = QAbstractTableModel::flags( index );
204 if ( mResults.at( index.row() ).type != QgsLocatorModel::EntryType::Result )
206 flags =
flags & ~( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
213 QHash<int, QByteArray> roles;
223 roles[Qt::DisplayRole] =
"Text";
229 mDeferredClearTimer.stop();
230 if ( mDeferredClear )
232 mFoundResultsFromFilterNames.clear();
233 mFoundResultsFilterGroups.clear();
236 const int pos = mResults.size();
237 const bool addingFilter = !result.
filter->
displayName().isEmpty() && !mFoundResultsFromFilterNames.contains( result.
filter->
name() );
239 mFoundResultsFromFilterNames << result.
filter->
name();
241 const bool addingGroup = !result.
group.isEmpty() && ( !mFoundResultsFilterGroups.contains( result.
filter )
242 || !mFoundResultsFilterGroups.value( result.
filter ).contains( std::pair( result.
group, result.
groupScore ) ) );
245 if ( !mFoundResultsFilterGroups.contains( result.
filter ) )
246 mFoundResultsFilterGroups[result.
filter] = QList<std::pair<QString, double>>();
251 if ( mDeferredClear )
258 beginInsertRows( QModelIndex(), pos, pos + (
static_cast<int>( addingFilter ) +
static_cast<int>( addingGroup ) ) );
265 entry.type = EntryType::Filter;
267 entry.filter = result.
filter;
273 entry.type = EntryType::Group;
275 entry.groupTitle = result.
group;
276 entry.groupScore = groupScore;
277 entry.filter = result.
filter;
281 entry.type = EntryType::Result;
282 entry.filter = result.
filter;
284 entry.result = result;
285 entry.groupTitle = result.
group;
286 entry.groupScore = groupScore;
289 if ( mDeferredClear )
294 mDeferredClear =
false;
304 , mLocator( locator )
306 Q_ASSERT( mLocator );
324 mNextRequestedString = string;
325 mHasQueuedRequest =
true;
340void QgsLocatorAutomaticModel::searchFinished()
342 if ( mHasQueuedRequest )
345 const QString nextSearch = mNextRequestedString;
346 mNextRequestedString.clear();
347 mHasQueuedRequest =
false;
361 : QSortFilterProxyModel( parent )
363 setDynamicSortFilter(
true );
364 setSortLocaleAware(
true );
365 setFilterCaseSensitivity( Qt::CaseInsensitive );
374 const QAbstractItemModel *lSourceModel = sourceModel();
375 const int leftFilterPriority = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultFilterPriority ) ).toInt();
376 const int rightFilterPriority = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultFilterPriority ) ).toInt();
377 if ( leftFilterPriority != rightFilterPriority )
378 return leftFilterPriority < rightFilterPriority;
381 QString leftFilter = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultFilterName ) ).toString();
382 QString rightFilter = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultFilterName ) ).toString();
383 if ( leftFilter != rightFilter )
384 return QString::localeAwareCompare( leftFilter, rightFilter ) < 0;
387 const int leftTypeRole = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultType ) ).toInt();
388 const int rightTypeRole = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultType ) ).toInt();
389 if ( leftTypeRole != rightTypeRole && ( leftTypeRole == 0 || rightTypeRole == 0 ) )
390 return leftTypeRole < rightTypeRole;
393 const double leftGroupScoreRole = lSourceModel->data( left,
static_cast< double >( CustomRole::ResultFilterGroupScore ) ).toDouble();
394 const double rightGroupScoreRole = lSourceModel->data( right,
static_cast< double >( CustomRole::ResultFilterGroupScore ) ).toDouble();
395 if ( leftGroupScoreRole != rightGroupScoreRole )
396 return leftGroupScoreRole > rightGroupScoreRole;
399 QString leftGroupTitle = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultFilterGroupTitle ) ).toString();
400 QString rightGroupTitle = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultFilterGroupTitle ) ).toString();
401 if ( leftGroupTitle != rightGroupTitle )
402 return QString::localeAwareCompare( leftGroupTitle, rightGroupTitle ) < 0;
405 if ( leftTypeRole != rightTypeRole )
406 return leftTypeRole < rightTypeRole;
409 const double leftScore = lSourceModel->data( left,
static_cast< int >( CustomRole::ResultScore ) ).toDouble();
410 const double rightScore = lSourceModel->data( right,
static_cast< int >( CustomRole::ResultScore ) ).toDouble();
412 return leftScore > rightScore;
415 leftFilter = lSourceModel->data( left, Qt::DisplayRole ).toString();
416 rightFilter = lSourceModel->data( right, Qt::DisplayRole ).toString();
417 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 QString name() const =0
Returns the unique name for the filter.
An abstract list model for displaying the results of locator searches.
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.
double groupScore
Specifies the score of the group to allow ordering.
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.
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.
void fetchResults(const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback=nullptr)
Triggers the background fetching of filter results for a specified search string.
bool isRunning() const
Returns true if a query is currently being executed by the locator.
void cancelWithoutBlocking()
Triggers cancellation of any current running query without blocking.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)