From 24c90cc04994c9d87e3d049ae6160d953051db77 Mon Sep 17 00:00:00 2001 From: Laurent Trinques Date: Sun, 18 Oct 2026 17:13:02 +0200 Subject: [PATCH] Terminal block manager: show the folios being read, stay responsive Opening the terminal block manager builds the folios not built yet (lazy folios). This is done in one go without running the event loop, so the window system said the opening message was "not responding". - QETProject::setFolioBuildObserver(): a function called after each folio built by buildFolios(), with the number of folios built and to build. - The manager uses it to show "Reading folio n of N..." with a real progress bar, and runs the event loop (without the user input) between two folios, so the window system keeps getting answers. - The autosave skips its turn while folios are being built, since the event loop can now run then. - The opening message only has a title bar: nothing to minimize, maximize or close. --- .../ui/terminalstripeditorwindow.cpp | 22 ++++++++++++ sources/qetproject.cpp | 34 ++++++++++++++++++- sources/qetproject.h | 4 +++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/sources/TerminalStrip/ui/terminalstripeditorwindow.cpp b/sources/TerminalStrip/ui/terminalstripeditorwindow.cpp index cc1d86a94..ef7538c49 100644 --- a/sources/TerminalStrip/ui/terminalstripeditorwindow.cpp +++ b/sources/TerminalStrip/ui/terminalstripeditorwindow.cpp @@ -52,6 +52,8 @@ TerminalStripEditorWindow *TerminalStripEditorWindow::instance(QETProject *proje { QProgressDialog busy_(tr("Opening the terminal block manager..."), QString(), 0, 0, parent); busy_.setWindowTitle(tr("Terminal block manager")); + //Only a title : nothing to minimize, maximize or close + busy_.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint); busy_.setWindowModality(Qt::ApplicationModal); busy_.setCancelButton(nullptr); busy_.setMinimumDuration(0); @@ -74,6 +76,23 @@ TerminalStripEditorWindow *TerminalStripEditorWindow::instance(QETProject *proje QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); QApplication::setOverrideCursor(Qt::WaitCursor); + //The folios not built yet (lazy folios) are built now : show the + //progress, and run the event loop between two folios, so that the + //window system still gets answers (else the message is said + //"not responding") + if (project) + { + project->setFolioBuildObserver([&busy_](int built, int total) + { + if (busy_.maximum() != total) { + busy_.setMaximum(total); + } + busy_.setLabelText(tr("Reading folio %1 of %2...").arg(built).arg(total)); + busy_.setValue(built); + QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + }); + } + static QMutex mutex_; if (!window_) { mutex_.lock(); @@ -84,6 +103,9 @@ TerminalStripEditorWindow *TerminalStripEditorWindow::instance(QETProject *proje window_->setProject(project); } + if (project) { + project->setFolioBuildObserver({}); + } QApplication::restoreOverrideCursor(); return window_; } diff --git a/sources/qetproject.cpp b/sources/qetproject.cpp index c63d09602..23034f30e 100644 --- a/sources/qetproject.cpp +++ b/sources/qetproject.cpp @@ -407,6 +407,11 @@ void QETProject::init() m_autosave_timer.setInterval(ms); connect(&m_autosave_timer, &QTimer::timeout, this, [this]() { + //Not while folios are being built (the event loop can run + //then, see setFolioBuildObserver()) : the next time + if (this->m_state == ProjectParsingRunning) { + return; + } if(!this->m_file_path.isEmpty()) { //No one is there to ask: a file changed behind this @@ -762,6 +767,18 @@ void QETProject::loadFolios() const buildFolios(m_diagrams_list); } +/** + @brief QETProject::setFolioBuildObserver + @p observer is called after each folio built by buildFolios(), with the + number of folios built so far and the number to build : a long build + can show its progress, and keep the window system answered by running + the event loop (without the user input) in @p observer. The autosave + waits meanwhile. An empty function removes the observer. +*/ +void QETProject::setFolioBuildObserver(std::function observer) { + m_folio_build_observer = std::move(observer); +} + /** @brief QETProject::buildFolios Build those of @p folios still waiting, as opening builds them: all @@ -785,8 +802,23 @@ void QETProject::buildFolios(const QList &folios) const const bool signals_were_blocked = self->m_data_base.signalsBlocked(); self->m_data_base.blockSignals(true); QList built; + int waiting_ = 0; + if (m_folio_build_observer) { + for (Diagram *d : folios) + if (!d->isLoaded()) ++waiting_; + } for (Diagram *d : folios) - if (d->buildDeferred()) built << d; + { + if (d->buildDeferred()) + { + built << d; + //Someone shows the progress (a long build, opening the + //terminal block manager...) + if (m_folio_build_observer) { + m_folio_build_observer(built.size(), waiting_); + } + } + } for (Diagram *d : std::as_const(built)) self->folioLoaded(d); self->m_data_base.blockSignals(signals_were_blocked); diff --git a/sources/qetproject.h b/sources/qetproject.h index aeb87a1b5..437112fcf 100644 --- a/sources/qetproject.h +++ b/sources/qetproject.h @@ -18,6 +18,7 @@ #ifndef QET_PROJECT_H #define QET_PROJECT_H +#include #include "ElementsCollection/elementslocation.h" #include "NameList/nameslist.h" #include "project/projectpropertieshandler.h" @@ -150,6 +151,7 @@ class QETProject : public QObject QSet tableChainFolios(Diagram *folio) const; void loadFolios() const; void buildFolios(const QList &folios) const; + void setFolioBuildObserver(std::function observer); void folioLoaded(Diagram *folio); int folioIndex(const Diagram *) const; XmlElementCollection *embeddedElementCollection()const; @@ -625,6 +627,8 @@ class QETProject : public QObject QHash> m_shared_uuid_keepers; //symbol and wire uuids the file carries, see derivedItemUuid() projectDataBase m_data_base; QVector m_terminal_strip_vector; + //Called after each folio built, see setFolioBuildObserver() + std::function m_folio_build_observer; QVector m_cables; ProjectPropertiesHandler m_project_properties_handler;