15#include <adtf_utils.h>
17#include <QActionGroup>
23#include <QSortFilterProxyModel>
25#include <QStandardItemModel>
30#include <QStringListModel>
46Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR
inline uint
qHash(const ::std::tuple<quintptr, int>& i, uint seed = 0) noexcept
48 return ::qHash(std::get<0>(i), seed) +
::qHash(std::get<1>(i), seed);
69class cSearchTextWidget;
73class IFilterModel :
public QSortFilterProxyModel
78 using QSortFilterProxyModel::QSortFilterProxyModel;
79 virtual void SetFilterColumn(int64_t nFilterColumn) = 0;
80 virtual void ClearMatchingData() = 0;
81 virtual void SetMatchingTexts(QSet<QString> oMatchingTexts) = 0;
84 virtual void ClearMappingCache() = 0;
87template<
template<
class,
class>
class MAP = QHash,
template<
class>
class SET = QSet>
88class filter_model final :
public IFilterModel
91 filter_model(QObject* parent =
nullptr): IFilterModel(parent)
93 setDynamicSortFilter(
false);
96 QVariant headerData(
int section, Qt::Orientation orientation,
int role = Qt::DisplayRole)
const override
98 if (role == Qt::DecorationRole)
100 if (section == m_nFilterColumn)
102 static const auto oFilterIcon = create_themed_icon(
":/Filter.svg");
106 return QSortFilterProxyModel::headerData(section, orientation, role);
108 void setSourceModel(QAbstractItemModel* pNewSourceModel)
override
110 filter_model::ClearMappingCache();
111 const auto pOldSourceModel = sourceModel();
114 disconnect(pOldSourceModel, &QAbstractItemModel::rowsAboutToBeInserted,
this,
115 &filter_model::ClearMappingCache);
116 disconnect(pOldSourceModel, &QAbstractItemModel::rowsAboutToBeMoved,
this,
117 &filter_model::ClearMappingCache);
118 disconnect(pOldSourceModel, &QAbstractItemModel::rowsAboutToBeRemoved,
this,
119 &filter_model::ClearMappingCache);
120 disconnect(pOldSourceModel, &QAbstractItemModel::columnsAboutToBeInserted,
this,
121 &filter_model::ClearMappingCache);
122 disconnect(pOldSourceModel, &QAbstractItemModel::columnsAboutToBeMoved,
this,
123 &filter_model::ClearMappingCache);
124 disconnect(pOldSourceModel, &QAbstractItemModel::columnsAboutToBeRemoved,
this,
125 &filter_model::ClearMappingCache);
126 disconnect(pOldSourceModel, &QAbstractItemModel::modelAboutToBeReset,
this,
127 &filter_model::ClearMappingCache);
131 connect(pNewSourceModel, &QAbstractItemModel::rowsAboutToBeInserted,
this,
132 &filter_model::ClearMappingCache);
133 connect(pNewSourceModel, &QAbstractItemModel::rowsAboutToBeMoved,
this, &filter_model::ClearMappingCache);
134 connect(pNewSourceModel, &QAbstractItemModel::rowsAboutToBeRemoved,
this, &filter_model::ClearMappingCache);
135 connect(pNewSourceModel, &QAbstractItemModel::columnsAboutToBeInserted,
this,
136 &filter_model::ClearMappingCache);
137 connect(pNewSourceModel, &QAbstractItemModel::columnsAboutToBeMoved,
this,
138 &filter_model::ClearMappingCache);
139 connect(pNewSourceModel, &QAbstractItemModel::columnsAboutToBeRemoved,
this,
140 &filter_model::ClearMappingCache);
141 connect(pNewSourceModel, &QAbstractItemModel::modelAboutToBeReset,
this, &filter_model::ClearMappingCache);
144 QSortFilterProxyModel::setSourceModel(pNewSourceModel);
147 void SetFilterColumn(int64_t nFilterColumn)
override
149 m_nFilterColumn = nFilterColumn;
151 emit headerDataChanged(Qt::Horizontal, 0, columnCount() - 1);
153 void ClearMatchingData()
override
155 if (m_setMatchingTexts)
157 m_setMatchingTexts.reset();
162 void SetMatchingTexts(QSet<QString> oMatchingTexts)
override
164 m_setMatchingTexts = SET<QString>{oMatchingTexts.cbegin(), oMatchingTexts.cend()};
170 bool filterAcceptsRow(
int source_row,
const QModelIndex& source_parent)
const override
172 if (!m_setMatchingTexts || m_nFilterColumn < 0)
177 return filterAcceptsRowInternal(sourceModel(), source_row, source_parent);
181 bool filterAcceptsRowInternal(
const QAbstractItemModel* pSourceModel,
183 const QModelIndex& source_parent)
const
186 const auto oHashKey = std::tuple{source_parent.internalId(), source_row};
188 if (
const auto it =
static_cast<const decltype(m_oAcceptedItems)&
>(m_oAcceptedItems).find(oHashKey);
189 it != m_oAcceptedItems.cend())
195 if constexpr (std::is_same_v<MAP<std::tuple<quintptr, int>,
bool>, QHash<std::tuple<quintptr, int>,
bool>>)
208 if (source_parent.isValid())
210 auto oGrandParent = pSourceModel->parent(source_parent);
211 if (filterAcceptsRowInternal(pSourceModel, source_parent.row(), oGrandParent))
218 const auto oRowIndex = pSourceModel->index(source_row, 0, source_parent);
221 const auto oElementIndex =
222 m_nFilterColumn != 0 ? pSourceModel->sibling(source_row, m_nFilterColumn, oRowIndex) : oRowIndex;
224 if ((*m_setMatchingTexts).contains(pSourceModel->data(oElementIndex).toString()))
230 if (!pSourceModel->flags(oRowIndex).testFlag(Qt::ItemNeverHasChildren))
234 if constexpr (std::is_same_v<MAP<std::tuple<quintptr, int>,
bool>, QHash<std::tuple<quintptr, int>,
bool>>)
236 m_oAcceptedItems.insert(oHashKey, result);
240 m_oAcceptedItems.emplace(oHashKey, result);
246 void ClearMappingCache()
override
248 m_oAcceptedItems.clear();
251 int64_t m_nFilterColumn = -1;
253 std::optional<SET<QString>> m_setMatchingTexts;
257 mutable MAP<std::tuple<quintptr, int>,
bool> m_oAcceptedItems;
343 void HandleChangedSearchParameters();
345 void SetCachedText(QSet<QString> oCachedText,
bool reset =
false,
bool schedule =
true);
347 void SearchNormalString();
348 void SearchWildcard();
349 void SearchRegexString();
352 void SetMatchingTexts(QSet<QString> oMatchingTexts);
354 QSet<QString> ComputeItemTexts(
const QModelIndex& oModelIndex,
const uint64_t nFilterColumn);
355 void ComputeTreeModelIndexs(
const QModelIndex& oModelIndex,
356 const uint64_t nFilterColumn,
357 const std::function<
void(
const QModelIndex& oIndex)>& fnCallback);
360 bool eventFilter(QObject* obj, QEvent* event)
override;
363 IFilterModel* m_pFilterModel =
nullptr;
364 QAbstractItemModel* m_pSourceModel =
nullptr;
366 QLineEdit* m_pSearchTextLineEdit =
nullptr;
367 QLabel* m_pErrorLabel =
nullptr;
368 QToolButton* m_pClearButton =
nullptr;
369 QMenu* m_pFilterMenu =
nullptr;
370 QActionGroup* m_pFilterActionGroup =
nullptr;
371 QAction* m_pFuzzyFilterAction =
nullptr;
372 QAction* m_pCaseSensitiveAction =
nullptr;
373 QPushButton* m_pFilterButton =
nullptr;
374 QMenu* m_pFilterColumnMenu =
nullptr;
375 QActionGroup* m_pFilterColumnActionGroup =
nullptr;
376 QWidget* m_pFuzzyParametersWidget =
nullptr;
377 QSpinBox* m_pFuzzyScaledScoreThresholdSpinBox =
nullptr;
378 QStringListModel* m_pAutoCompletionModel =
nullptr;
379 QCompleter* m_pAutoCompleter =
nullptr;
380 QTimer* m_pPendingSearch =
nullptr;
382 bool m_bIsInInitialization =
false;
384 struct cSearchIndexState
386 uint64_t nSelectedFilterColumn = std::numeric_limits<uint64_t>::max();
387 QSet<QString> setItemTextCache;
388 std::optional<QSet<QString>> setMatchingItemText;
390 cSearchIndexState m_oSearchIndex;
392 QThreadPool m_oSearchThreadPool;
393 std::atomic<bool> m_bSearchCanceled =
false;
void searchParametersChanged()
This signal is emitted when the search parameters changed.
cSearchTextWidget(QWidget *pParent=nullptr)
void SetCaseSensitive(bool bCaseSensitive)
void selectedFilterColumnChanged()
This signal is emitted when the selected filter column changed.
void SetFilterColumnNames(const std::vector< QString > &vecFilterColumnNames)
void SelectFilterType(FilterType oFilterType)
void SetSearchText(const QString &strSearchText)
void SetFilterColumnNamesFromModel(const QAbstractItemModel &oModel)
bool IsCaseSensitive() const
Returns whether 'case sensitive' is selected.
void SetFilterModel(IFilterModel &oFilterModel)
FilterType GetSelectedFilterType() const
uint64_t GetSelectedFilterColumn() const
Namespace for the ADTF UI SDK.
Definition adtfui_pkg.h:13
Namespace for all functionality provided by ADTF and its SDKs.
Definition adtfui_pkg.h:13
FilterType
Filter type.
Definition search_text_widget.h:62
Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR uint qHash(const ::std::tuple< quintptr, int > &i, uint seed=0) noexcept
qHash for tuple of (quintptr, int)
Definition search_text_widget.h:46