Terminal block manager: show the folios being read, stay responsive
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 1m41s

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.
This commit is contained in:
Laurent Trinques
2026-10-18 17:13:02 +02:00
parent 662a0c8f5c
commit 24c90cc049
3 changed files with 59 additions and 1 deletions
@@ -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_;
}
+33 -1
View File
@@ -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<void (int, int)> 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<Diagram *> &folios) const
const bool signals_were_blocked = self->m_data_base.signalsBlocked();
self->m_data_base.blockSignals(true);
QList<Diagram *> 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);
+4
View File
@@ -18,6 +18,7 @@
#ifndef QET_PROJECT_H
#define QET_PROJECT_H
#include <functional>
#include "ElementsCollection/elementslocation.h"
#include "NameList/nameslist.h"
#include "project/projectpropertieshandler.h"
@@ -150,6 +151,7 @@ class QETProject : public QObject
QSet<Diagram *> tableChainFolios(Diagram *folio) const;
void loadFolios() const;
void buildFolios(const QList<Diagram *> &folios) const;
void setFolioBuildObserver(std::function<void(int, int)> observer);
void folioLoaded(Diagram *folio);
int folioIndex(const Diagram *) const;
XmlElementCollection *embeddedElementCollection()const;
@@ -625,6 +627,8 @@ class QETProject : public QObject
QHash<QUuid, std::pair<int, int>> m_shared_uuid_keepers; //symbol and wire uuids the file carries, see derivedItemUuid()
projectDataBase m_data_base;
QVector<TerminalStrip *> m_terminal_strip_vector;
//Called after each folio built, see setFolioBuildObserver()
std::function<void(int, int)> m_folio_build_observer;
QVector<Cable *> m_cables;
ProjectPropertiesHandler m_project_properties_handler;