From 6657b3de2be341f82c092846d1b2fe8b5be3a73c Mon Sep 17 00:00:00 2001 From: ispyisail Date: Mon, 24 Aug 2026 23:09:12 +1200 Subject: [PATCH] Make ProjectAutoNumConfigPage follow ProjectConfigPage's documented init() contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ProjectConfigPage::init() is documented as "Typically, you should call this function in your subclass constructor" -- it runs initWidgets(), initLayout(), and (if a project is set) readValuesFromProject() and adjustReadOnly(), in that order. ProjectMainConfigPage's constructor follows this. Until now, ProjectAutoNumConfigPage's did not: it called initWidgets(), its own buildConnections(), and readValuesFromProject() directly, skipping both initLayout() and adjustReadOnly() entirely, and calling readValuesFromProject() with no null-project guard. In practice this was harmless today -- this subclass's initLayout() and adjustReadOnly() overrides are both empty, and every construction site happens to pass a real project -- but it is exactly the kind of latent inconsistency Joshua's own refactor notes call out for this class ("remove inconsistent virtual method usage... allow subclasses independent implementation"). The day someone fills in adjustReadOnly() for this page (e.g. to disable auto-numbering editing on a read-only project, which is what the empty override's own doc comment says it is for), the constructor path would silently never call it. Fixed narrowly: the constructor now calls init() like its sibling does. buildConnections() moves to the end of initWidgets(), the same relative position it held in the constructor, so behaviour for the paths already exercised is unchanged. This is the safe, no-redesign half of Joshua's note; removing the init()/initWidgets()/initLayout()/readValuesFromProject() scaffolding itself, so subclasses are free to sequence things however they want, is a real redesign of the ConfigPage contract and needs his sign-off on what should replace it -- not attempted here. Verified with a GUI capture rather than by reading: opened Project Properties on examples/industrial.qet, selected "Numérotation auto", and confirmed the Management tab renders with its saved policy (Conductor/Element "Both", "Apply to Entire Project") and the Conducteurs tab's combo box comes up pre-populated with the project's saved context ("de la nouvelle numérotation"), which on selection correctly fills the Type/Valeur/Formule fields -- proving both readValuesFromProject() and the buildConnections() signal wiring still work end-to-end through the new call sequence. Co-Authored-By: Claude Sonnet 5 --- sources/ui/configpage/projectconfigpages.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sources/ui/configpage/projectconfigpages.cpp b/sources/ui/configpage/projectconfigpages.cpp index e1e404bb1..ab31a9aa1 100644 --- a/sources/ui/configpage/projectconfigpages.cpp +++ b/sources/ui/configpage/projectconfigpages.cpp @@ -290,9 +290,14 @@ ProjectAutoNumConfigPage::ProjectAutoNumConfigPage (QETProject *project, QWidget *parent) : ProjectConfigPage(project, parent) { - initWidgets(); - buildConnections(); - readValuesFromProject(); + // Follow the same contract ProjectMainConfigPage's constructor does -- + // init() is documented to be the thing a subclass constructor calls + // (see ProjectConfigPage::init()'s doc comment). Calling the pieces + // individually here used to skip both initLayout() and adjustReadOnly(), + // and called readValuesFromProject() even when m_project was null. + // buildConnections() itself is invoked from the end of initWidgets() + // below, in the same relative position it held here. + init(); } /** @@ -352,6 +357,8 @@ void ProjectAutoNumConfigPage::initWidgets() QHBoxLayout *main_layout = new QHBoxLayout(); main_layout->addWidget(tab_widget); setLayout(main_layout); + + buildConnections(); } /**