Am Donnerstag, dem 18.08.2022 um 18:43 +0200 schrieb Jean-Marc Lasgouttes: > Indeed, threads create lots of interesting bugs... It would be better > if we could avoid them
The UX difference to the timer approach is huge. The threaded calculation feels smooth and is almost instant. The crash is fixed in the attached patch, which works well for me. -- Jürgen
diff --git a/src/Buffer.cpp b/src/Buffer.cpp index da630da90a..88f21ced0e 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -4223,6 +4223,13 @@ void Buffer::structureChanged() const } +void Buffer::updateStats(bool threaded) const +{ + if (d->gui_) + d->gui_->updateStats(threaded); +} + + void Buffer::errors(string const & err, bool from_master) const { if (d->gui_) @@ -4944,6 +4951,7 @@ void Buffer::updateBuffer() const { updateBuffer(UpdateMaster, InternalUpdate); d->need_update = false; + updateStats(false); } diff --git a/src/Buffer.h b/src/Buffer.h index ba066f724c..5ef97828af 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -660,6 +660,8 @@ public: void updateTocItem(std::string const &, DocIterator const &) const; /// This function is called when the buffer structure is changed. void structureChanged() const; + /// This function updates the statistics in the stats bar. + void updateStats(bool threaded = true) const; /// This function is called when some parsing error shows up. void errors(std::string const & err, bool from_master = false) const; /// This function is called when the buffer busy status change. diff --git a/src/BufferView.cpp b/src/BufferView.cpp index da309d63e5..85badcf9ae 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -2827,6 +2827,7 @@ bool BufferView::mouseSetCursor(Cursor & cur, bool const select) d->cursor_.resetAnchor(); d->cursor_.setCursor(cur); d->cursor_.clearSelection(); + cur.buffer()->updateStats(); } d->cursor_.boundary(cur.boundary()); d->cursor_.finishUndo(); diff --git a/src/Cursor.cpp b/src/Cursor.cpp index ce0281251a..49522fed11 100644 --- a/src/Cursor.cpp +++ b/src/Cursor.cpp @@ -254,6 +254,7 @@ void CursorData::setSelection() pit() == normalAnchor().pit() && pos() == normalAnchor().pos()) selection(false); + buffer()->updateStats(); } @@ -263,6 +264,7 @@ void CursorData::setSelection(DocIterator const & where, int n) selection(true); anchor_ = where; pos() += n; + buffer()->updateStats(); } @@ -1394,6 +1396,7 @@ bool Cursor::selHandle(bool selecting) resetAnchor(); selection(selecting); + buffer()->updateStats(); return true; } @@ -2284,6 +2287,7 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded) setCurrentFont(); updateNeeded |= bv().checkDepm(*this, old); + buffer()->updateStats(); } if (updateNeeded) @@ -2534,6 +2538,7 @@ void Cursor::checkBufferStructure() // In case the master has no gui associated with it, // the TocItem is not updated (part of bug 5699). buffer()->tocBackend().updateItem(*this); + buffer()->updateStats(); } diff --git a/src/Text2.cpp b/src/Text2.cpp index 3dae072cec..54cd27fc80 100644 --- a/src/Text2.cpp +++ b/src/Text2.cpp @@ -552,6 +552,8 @@ bool Text::setCursor(Cursor & cur, pit_type pit, pos_type pos, bool const update_needed = !tm.contains(pit); Cursor old = cur; setCursorIntern(cur, pit, pos, setfont, boundary); + if (cur.selection()) + cur.buffer()->updateStats(); return cur.bv().checkDepm(cur, old) || update_needed; } diff --git a/src/Text3.cpp b/src/Text3.cpp index da23857c1a..86feb5e704 100644 --- a/src/Text3.cpp +++ b/src/Text3.cpp @@ -2877,6 +2877,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) case LFUN_ESCAPE: if (cur.selection()) { cur.selection(false); + cur.buffer()->updateStats(); } else { cur.undispatched(); // This used to be LFUN_FINISHED_RIGHT, I think FORWARD is more diff --git a/src/frontends/Delegates.h b/src/frontends/Delegates.h index c50df6b33f..98f672064f 100644 --- a/src/frontends/Delegates.h +++ b/src/frontends/Delegates.h @@ -71,6 +71,8 @@ public: virtual void setBusy(bool) = 0; /// Reset autosave timers for all users. virtual void resetAutosaveTimers() = 0; + /// Update status bar statistics + virtual void updateStats(bool threaded = true) = 0; }; } // namespace frontend diff --git a/src/frontends/qt/GuiView.cpp b/src/frontends/qt/GuiView.cpp index b87b494dac..4f6aa1248b 100644 --- a/src/frontends/qt/GuiView.cpp +++ b/src/frontends/qt/GuiView.cpp @@ -523,7 +523,6 @@ public: /// QTimer statusbar_timer_; - QTimer statusbar_stats_timer_; /// auto-saving of buffers Timeout autosave_timeout_; @@ -533,6 +532,7 @@ public: /// QFutureWatcher<docstring> autosave_watcher_; QFutureWatcher<Buffer::ExportStatus> processing_thread_watcher_; + QFutureWatcher<void> stats_watcher_; /// string last_export_format; string processing_format; @@ -547,20 +547,6 @@ public: /// flag against a race condition due to multiclicks, see bug #1119 bool in_show_; - - // Timers for statistic updates in buffer - /// Current time left to the nearest info update - int time_to_update = 1000; - ///Basic step for timer in ms. Basically reaction time for short selections - int const timer_rate = 500; - /// Real stats updates infrequently. First they take long time for big buffers, second - /// they are visible for fast-repeat keyboards even for mid documents. - int const default_stats_rate = 5000; - /// Detection of new selection, so we can react fast - bool already_in_selection_ = false; - /// Maximum size of "short" selection for which we can update with faster timer_rate - int const max_sel_chars = 5000; - }; QSet<Buffer const *> GuiView::GuiViewPrivate::busyBuffers; @@ -598,9 +584,6 @@ GuiView::GuiView(int id) } connect(&d.statusbar_timer_, SIGNAL(timeout()), this, SLOT(clearMessage())); - connect(&d.statusbar_stats_timer_, SIGNAL(timeout()), - this, SLOT(showStats())); - d.statusbar_stats_timer_.start(d.timer_rate); // We don't want to keep the window in memory if it is closed. setAttribute(Qt::WA_DeleteOnClose, true); @@ -768,6 +751,9 @@ GuiView::GuiView(int id) connect(&d.processing_thread_watcher_, SIGNAL(finished()), this, SLOT(processingThreadFinished())); + connect(&d.stats_watcher_, SIGNAL(finished()), this, + SLOT(displayStats())); + connect(this, SIGNAL(triggerShowDialog(QString const &, QString const &, Inset *)), SLOT(doShowDialog(QString const &, QString const &, Inset *))); @@ -1312,7 +1298,6 @@ void GuiView::closeEvent(QCloseEvent * close_event) // Make sure the timer time out will not trigger a statusbar update. d.statusbar_timer_.stop(); - d.statusbar_stats_timer_.stop(); // Saving fullscreen requires additional tweaks in the toolbar code. // It wouldn't also work under linux natively. @@ -1418,14 +1403,13 @@ void GuiView::clearMessage() d.statusbar_timer_.stop(); } -void GuiView::showStats() + +void GuiView::updateStats(bool threaded) { if (!statsEnabled()) return; - d.time_to_update -= d.timer_rate; - - BufferView * bv = currentBufferView(); + BufferView * bv = documentBufferView(); Buffer * buf = bv ? &bv->buffer() : nullptr; if (!buf) { stat_counts_->hide(); @@ -1434,26 +1418,36 @@ void GuiView::showStats() Cursor const & cur = bv->cursor(); - // we start new selection and need faster update - if (!d.already_in_selection_ && cur.selection()) - d.time_to_update = 0; - - if (d.time_to_update > 0) - return; - DocIterator from, to; if (cur.selection()) { from = cur.selectionBegin(); to = cur.selectionEnd(); - d.already_in_selection_ = true; } else { from = doc_iterator_begin(buf); to = doc_iterator_end(buf); - d.already_in_selection_ = false; } + if (d.stats_watcher_.isRunning()) + // keep a snappy interface + return; - buf->updateStatistics(from, to); + if (threaded) { + QFuture<void> f = QtConcurrent::run(&bv->buffer(), + &Buffer::updateStatistics, from, to, true); + d.stats_watcher_.setFuture(f); + } else { + buf->updateStatistics(from, to); + displayStats(); + } +} +void GuiView::displayStats() +{ + BufferView * bv = documentBufferView(); + Buffer * buf = bv ? &bv->buffer() : nullptr; + if (!buf) { + stat_counts_->hide(); + return; + } QStringList stats; if (word_count_enabled_) { int const words = buf->wordCount(); @@ -1478,11 +1472,6 @@ void GuiView::showStats() } stat_counts_->setText(stats.join(qt_(", [[stats separator]]"))); stat_counts_->show(); - - d.time_to_update = d.default_stats_rate; - // fast updates for small selections - if (chars_with_blanks < d.max_sel_chars && cur.selection()) - d.time_to_update = d.timer_rate; } @@ -2074,6 +2063,7 @@ void GuiView::setBuffer(Buffer * newBuffer, bool switch_to) connectBufferView(wa->bufferView()); if (switch_to) setCurrentWorkArea(wa); + updateStats(); } @@ -5031,15 +5021,15 @@ bool GuiView::lfunUiToggle(string const & ui_component) } else if (ui_component == "statistics-w") { word_count_enabled_ = !word_count_enabled_; if (statsEnabled()) - showStats(); + displayStats(); } else if (ui_component == "statistics-cb") { char_count_enabled_ = !char_count_enabled_; if (statsEnabled()) - showStats(); + displayStats(); } else if (ui_component == "statistics-c") { char_nb_count_enabled_ = !char_nb_count_enabled_; if (statsEnabled()) - showStats(); + displayStats(); } else if (ui_component == "frame") { int const l = contentsMargins().left(); diff --git a/src/frontends/qt/GuiView.h b/src/frontends/qt/GuiView.h index 7b89370151..c02fefd5a4 100644 --- a/src/frontends/qt/GuiView.h +++ b/src/frontends/qt/GuiView.h @@ -235,8 +235,10 @@ public Q_SLOTS: /// idle timeout. /// clear any temporary message and replace with current status. void clearMessage(); - /// show documents stats in toolbar and trigger new iteration - void showStats(); + /// update documents statistics for status bar + void updateStats(bool threaded = true) override; + /// show/hide documents stats in status bar + void displayStats(); /// void updateWindowTitle(GuiWorkArea * wa); ///
signature.asc
Description: This is a digitally signed message part
-- lyx-devel mailing list lyx-devel@lists.lyx.org http://lists.lyx.org/mailman/listinfo/lyx-devel