diff --git a/src/timeline/TimelineFilter.cpp b/src/timeline/TimelineFilter.cpp index 91cae637..e2d48862 100644 --- a/src/timeline/TimelineFilter.cpp +++ b/src/timeline/TimelineFilter.cpp @@ -4,12 +4,59 @@ #include "TimelineFilter.h" +#include +#include + #include "Logging.h" +static int FilterRole = Qt::UserRole * 3; + +static QEvent::Type +getFilterEventType() +{ + static QEvent::Type t = static_cast(QEvent::registerEventType()); + return t; +} + TimelineFilter::TimelineFilter(QObject *parent) : QSortFilterProxyModel(parent) { setDynamicSortFilter(true); + setFilterRole(FilterRole); +} + +void +TimelineFilter::startFiltering() +{ + incrementalSearchIndex = 0; + continueFiltering(); +} + +void +TimelineFilter::continueFiltering() +{ + if (auto s = source(); s && s->rowCount() > incrementalSearchIndex) { + auto ev = new QEvent(getFilterEventType()); + QCoreApplication::postEvent(this, ev, Qt::LowEventPriority - 1); + } +} + +bool +TimelineFilter::event(QEvent *ev) +{ + if (ev->type() == getFilterEventType()) { + int orgIndex = incrementalSearchIndex; + incrementalSearchIndex += 30; + + if (auto s = source(); s) { + s->dataChanged(s->index(orgIndex), + s->index(std::min(incrementalSearchIndex, s->rowCount() - 1)), + {FilterRole}); + continueFiltering(); + } + return true; + } + return QSortFilterProxyModel::event(ev); } void @@ -18,10 +65,10 @@ TimelineFilter::setThreadId(const QString &t) nhlog::ui()->debug("Filtering by thread '{}'", t.toStdString()); if (this->threadId != t) { this->threadId = t; - invalidateFilter(); - fetchMore({}); emit threadIdChanged(); + startFiltering(); + fetchMore({}); } } @@ -31,10 +78,10 @@ TimelineFilter::setContentFilter(const QString &c) nhlog::ui()->debug("Filtering by content '{}'", c.toStdString()); if (this->contentFilter != c) { this->contentFilter = c; - invalidateFilter(); - fetchMore({}); emit contentFilterChanged(); + startFiltering(); + fetchMore({}); } } @@ -52,11 +99,25 @@ TimelineFilter::fetchAgain() } } +void +TimelineFilter::sourceDataChanged(const QModelIndex &topLeft, + const QModelIndex &bottomRight, + const QVector &roles) +{ + if (!roles.contains(TimelineModel::Roles::Body) && !roles.contains(TimelineModel::ThreadId)) + return; + + if (auto s = source()) { + s->dataChanged(topLeft, bottomRight, {FilterRole}); + } +} + void TimelineFilter::setSource(TimelineModel *s) { if (auto orig = this->source(); orig != s) { - cachedCount = 0; + cachedCount = 0; + incrementalSearchIndex = 0; if (orig) { disconnect(orig, @@ -64,6 +125,7 @@ TimelineFilter::setSource(TimelineModel *s) this, &TimelineFilter::currentIndexChanged); disconnect(orig, &TimelineModel::fetchedMore, this, &TimelineFilter::fetchAgain); + disconnect(orig, &TimelineModel::dataChanged, this, &TimelineFilter::sourceDataChanged); } this->setSourceModel(s); @@ -71,7 +133,13 @@ TimelineFilter::setSource(TimelineModel *s) connect(s, &TimelineModel::currentIndexChanged, this, &TimelineFilter::currentIndexChanged); connect( s, &TimelineModel::fetchedMore, this, &TimelineFilter::fetchAgain, Qt::QueuedConnection); + connect(s, + &TimelineModel::dataChanged, + this, + &TimelineFilter::sourceDataChanged, + Qt::QueuedConnection); + incrementalSearchIndex = 0; emit sourceChanged(); invalidateFilter(); } @@ -104,6 +172,9 @@ TimelineFilter::currentIndex() const bool TimelineFilter::filterAcceptsRow(int source_row, const QModelIndex &) const { + if (source_row > incrementalSearchIndex) + return true; + if (threadId.isEmpty() && contentFilter.isEmpty()) return true; diff --git a/src/timeline/TimelineFilter.h b/src/timeline/TimelineFilter.h index a602f84f..30ec3300 100644 --- a/src/timeline/TimelineFilter.h +++ b/src/timeline/TimelineFilter.h @@ -39,6 +39,8 @@ public: return data(index(i, 0), role); } + bool event(QEvent *ev) override; + signals: void threadIdChanged(); void contentFilterChanged(); @@ -47,11 +49,17 @@ signals: private slots: void fetchAgain(); + void sourceDataChanged(const QModelIndex &topLeft, + const QModelIndex &bottomRight, + const QVector &roles); protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; private: + void startFiltering(); + void continueFiltering(); + QString threadId, contentFilter; - int cachedCount = 0; + int cachedCount = 0, incrementalSearchIndex = 0; };