Am Donnerstag, dem 18.08.2022 um 11:42 +0200 schrieb Jürgen
Spitzmüller:
> The attached seems to work basically. But I haven't check for all
> cases (I am dure there are cases I missed) and didn't push hard for
> performance (currently the timer is commented out; if this is too
> expensive, processes should be managed via QFuture).

Performance is an issue in larger documents (e.g., UserGuide).

This one, using threads, is snappy and seems to update reliably.

However, it crashes on each undo or redo action.

-- 
Jürgen
diff --git a/src/Buffer.cpp b/src/Buffer.cpp
index da630da90a..5770a95b9b 100644
--- a/src/Buffer.cpp
+++ b/src/Buffer.cpp
@@ -4223,6 +4223,13 @@ void Buffer::structureChanged() const
 }
 
 
+void Buffer::updateStats() const
+{
+	if (d->gui_)
+		d->gui_->updateStats();
+}
+
+
 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();
 }
 
 
diff --git a/src/Buffer.h b/src/Buffer.h
index ba066f724c..1e4d90fa44 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() 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/Cursor.cpp b/src/Cursor.cpp
index ce0281251a..fd7ac3c484 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();
 }
 
 
@@ -501,6 +503,7 @@ void CursorData::clearSelection()
 	setWordSelection(false);
 	setMark(false);
 	resetAnchor();
+	buffer()->updateStats();
 }
 
 
@@ -1394,6 +1397,7 @@ bool Cursor::selHandle(bool selecting)
 
 	resetAnchor();
 	selection(selecting);
+	buffer()->updateStats();
 	return true;
 }
 
@@ -2284,6 +2288,7 @@ bool Cursor::upDownInText(bool up, bool & updateNeeded)
 		setCurrentFont();
 
 		updateNeeded |= bv().checkDepm(*this, old);
+		buffer()->updateStats();
 	}
 
 	if (updateNeeded)
@@ -2534,6 +2539,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..389a4e47d6 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() = 0;
 };
 
 } // namespace frontend
diff --git a/src/frontends/qt/GuiView.cpp b/src/frontends/qt/GuiView.cpp
index edcc99983f..5218eef5bb 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(showStats()));
+
 	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()
 {
 	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,31 @@ 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);
+	QFuture<void> f = QtConcurrent::run(&bv->buffer(),
+					    &Buffer::updateStatistics, from, to, true);
+	d.stats_watcher_.setFuture(f);
+}
 
+void GuiView::showStats()
+{
+	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 +1467,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 +2058,7 @@ void GuiView::setBuffer(Buffer * newBuffer, bool switch_to)
 	connectBufferView(wa->bufferView());
 	if (switch_to)
 		setCurrentWorkArea(wa);
+	updateStats();
 }
 
 
diff --git a/src/frontends/qt/GuiView.h b/src/frontends/qt/GuiView.h
index 7b89370151..7007abfa4a 100644
--- a/src/frontends/qt/GuiView.h
+++ b/src/frontends/qt/GuiView.h
@@ -236,6 +236,8 @@ public Q_SLOTS:
 	/// clear any temporary message and replace with current status.
 	void clearMessage();
 	/// show documents stats in toolbar and trigger new iteration
+	void updateStats() override;
+	/// show documents stats in toolbar and trigger new iteration
 	void showStats();
 	///
 	void updateWindowTitle(GuiWorkArea * wa);

Attachment: 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

Reply via email to