From 467fa84fd851459d5d9c9e5297e2500e938f0a18 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Sat, 31 Oct 2026 11:26:52 +0100 Subject: fix: keep bulk tag actions linear, and say when they land Select all on a 10k-row search, then Archive, froze the window with one CPU pinned. gdb on the live process showed the UI thread cubic before the write was ever sent: each optimistic row write emitted dataChanged, whose handler refreshed the action labels by walking the whole selection, and each step of that walk looked the message up with a linear scan of every thread. ThreadListModel now answers id lookups from a lazily rebuilt hash, invalidated by its own structural signals and by hand at the two in-place id changes. MainWindow::batchModelWrites() holds the label refresh while a loop of optimistic writes runs, then refreshes once. Two list membership tests became sets. The announcement also used to fade on a timer whether or not the write had landed. It now reads "applying" until a round trip through the worker's queue says the write has run, then "done". An error takes the label back from a late "done". Item 211. Co-Authored-By: Claude Opus 5.5 --- src/mainwindow.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/mainwindow.h') diff --git a/src/mainwindow.h b/src/mainwindow.h index 87ed171..868964a 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -1179,6 +1179,10 @@ private: /// something, the same rule refreshUnreadAction() applies to the label. void refreshTrashActions(); + /// Runs a loop of optimistic model writes with the dataChanged-driven + /// action refresh held, then refreshes once (item 211). + void batchModelWrites(const std::function &writes); + /// Whether every selected row's file already sits in its account's trash /// folder. Empty selection answers false. /// @@ -1209,6 +1213,8 @@ private: /// for exit has finished. Stops closeEvent asking a second time, and is /// what lets the deferred close through. bool m_closeApproved = false; + bool m_batchingModelWrites = false; ///< see batchModelWrites() + quint64 m_announceTicket = 0; ///< see announceAction() /// True while a sync started by the exit prompt is running. The window /// stays open until it finishes: killing the process mid-sync is exactly -- cgit v1.2.3