From a1e4e153ae700b917fc63d1feb334d7a0783c8b9 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Mon, 21 Sep 2026 21:13:54 +1200 Subject: [PATCH] Let a script delete a conductor or a folio, and set title block fields deleteConductor() the conductor on a terminal, addressed as elsewhere removeFolio() RemoveDiagramCommand, the GUI's delete-folio command setFolioProperty() title, author, filename, plant, locmach, indexrev, folioProperty() version, folio -- via ChangeTitleBlockCommand deleteConductor removes only the named conductor; unlike a property change it is not potential-wide, and DeleteQGraphicsItemCommand rebuilds the rest of the potential so it stays connected, as when a user selects one conductor and presses Delete. Verified: deleting one leaf of a three-terminal potential leaves the other conductor, with its number. removeFolio skips the GUI's confirmation box, which nobody could answer headlessly. Undo and redo both work; later folio indexes shift down. Undoing a removal prints a UNIQUE-constraint warning from projectDataBase::addDiagram. That is inside RemoveDiagramCommand::undo(), which the GUI runs too, so it predates this change. The date and template are not offered as folio properties: the date has a use-current-date mode a plain string cannot express honestly. Verified headlessly, including save/reload of the title block fields. Qt 6.10.2, build clean, ctest matches master. Co-Authored-By: Claude Sonnet 5 --- sources/scripting/qetscriptapi.cpp | 111 +++++++++++++++++++++++++++++ sources/scripting/qetscriptapi.h | 6 ++ 2 files changed, 117 insertions(+) diff --git a/sources/scripting/qetscriptapi.cpp b/sources/scripting/qetscriptapi.cpp index c8f30b417..7475d4669 100644 --- a/sources/scripting/qetscriptapi.cpp +++ b/sources/scripting/qetscriptapi.cpp @@ -41,6 +41,7 @@ #include "../undocommand/changetitleblockcommand.h" #include "../undocommand/deleteqgraphicsitemcommand.h" #include "../undocommand/linkelementcommand.h" +#include "../undocommand/removediagramcommand.h" #include "../utils/conductorcreator.h" #include @@ -1257,6 +1258,116 @@ QString QetScriptApi::queryError() const return m_query_error; } +/** + @brief QetScriptApi::deleteConductor + Delete the single conductor attached to a terminal (same addressing as + setConductorProperty()). Unlike a property change this removes only that + conductor: DeleteQGraphicsItemCommand itself rebuilds the remaining + conductors of the potential so it stays connected, exactly as when a user + selects one conductor and presses Delete. +*/ +bool QetScriptApi::deleteConductor(int folioIndex, const QString &elementUuid, int terminalIndex) +{ + if (!m_project) return false; + const QString caller = QStringLiteral("deleteConductor"); + if (m_project->isReadOnly()) { + log(QStringLiteral("qet.%1: project is read-only").arg(caller)); + return false; + } + Conductor *conductor = findConductor(folioIndex, elementUuid, terminalIndex, caller); + if (!conductor) return false; + Diagram *diagram = m_project->diagrams().at(folioIndex); + + DiagramContent content; + content.m_conductors_to_move << conductor; + diagram->undoStack().push(new DeleteQGraphicsItemCommand(diagram, content)); + return true; +} + +/** + @brief QetScriptApi::removeFolio + Remove a folio through RemoveDiagramCommand, the command the GUI's + "delete folio" pushes (minus its confirmation box, which nobody could + answer headlessly). Undoable. Later folio indexes shift down by one. +*/ +bool QetScriptApi::removeFolio(int folioIndex) +{ + if (!m_project) return false; + if (m_project->isReadOnly()) { + log(QStringLiteral("qet.removeFolio: project is read-only")); + return false; + } + const QList diagrams = m_project->diagrams(); + if (folioIndex < 0 || folioIndex >= diagrams.count()) return false; + m_project->undoStack()->push(new RemoveDiagramCommand(m_project, diagrams.at(folioIndex))); + return m_project->diagrams().count() == diagrams.count() - 1; +} + +namespace { +QString *titleBlockField(TitleBlockProperties &p, const QString &name) +{ + if (name == QLatin1String("title")) return &p.title; + if (name == QLatin1String("author")) return &p.author; + if (name == QLatin1String("filename")) return &p.filename; + if (name == QLatin1String("plant")) return &p.plant; + if (name == QLatin1String("locmach")) return &p.locmach; + if (name == QLatin1String("indexrev")) return &p.indexrev; + if (name == QLatin1String("version")) return &p.version; + if (name == QLatin1String("folio")) return &p.folio; + return nullptr; +} +const QStringList &titleBlockFieldNames() +{ + static const QStringList n{QStringLiteral("title"), QStringLiteral("author"), + QStringLiteral("filename"), QStringLiteral("plant"), QStringLiteral("locmach"), + QStringLiteral("indexrev"), QStringLiteral("version"), QStringLiteral("folio")}; + return n; +} +} // namespace + +QString QetScriptApi::folioProperty(int folioIndex, const QString &property) const +{ + if (!m_project) return QString(); + const QList diagrams = m_project->diagrams(); + if (folioIndex < 0 || folioIndex >= diagrams.count()) return QString(); + TitleBlockProperties p = diagrams.at(folioIndex)->border_and_titleblock.exportTitleBlock(); + QString *field = titleBlockField(p, property); + return field ? *field : QString(); +} + +/** + @brief QetScriptApi::setFolioProperty + Set one text field of a folio's title block (title, author, filename, + plant, locmach, indexrev, version, folio) via ChangeTitleBlockCommand, + like setFolioTitle() which this generalises. The date and the template are + not offered: the date has a use-current-date mode that a plain string + cannot express honestly. +*/ +bool QetScriptApi::setFolioProperty(int folioIndex, const QString &property, const QString &value) +{ + if (!m_project) return false; + if (m_project->isReadOnly()) { + log(QStringLiteral("qet.setFolioProperty: project is read-only")); + return false; + } + const QList diagrams = m_project->diagrams(); + if (folioIndex < 0 || folioIndex >= diagrams.count()) return false; + Diagram *diagram = diagrams.at(folioIndex); + + TitleBlockProperties old_p = diagram->border_and_titleblock.exportTitleBlock(); + TitleBlockProperties new_p = old_p; + QString *field = titleBlockField(new_p, property); + if (!field) { + log(QStringLiteral("qet.setFolioProperty: unknown property '%1'; expected one of %2") + .arg(property, titleBlockFieldNames().join(QStringLiteral(", ")))); + return false; + } + if (*field == value) return true; + *field = value; + m_project->undoStack()->push(new ChangeTitleBlockCommand(diagram, old_p, new_p)); + return true; +} + int QetScriptApi::addFolio() { if (!m_project) return -1; diff --git a/sources/scripting/qetscriptapi.h b/sources/scripting/qetscriptapi.h index 2759b7636..d61c7b945 100644 --- a/sources/scripting/qetscriptapi.h +++ b/sources/scripting/qetscriptapi.h @@ -263,6 +263,12 @@ class QetScriptApi : public QObject Q_INVOKABLE QVariantList query(const QString &sql); Q_INVOKABLE QString queryError() const; + // -- removing a conductor or a folio; folio properties beyond the title -- + Q_INVOKABLE bool deleteConductor(int folioIndex, const QString &elementUuid, int terminalIndex); + Q_INVOKABLE bool removeFolio(int folioIndex); + Q_INVOKABLE bool setFolioProperty(int folioIndex, const QString &property, const QString &value); + Q_INVOKABLE QString folioProperty(int folioIndex, const QString &property) const; + // -- folios -- Q_INVOKABLE int addFolio(); Q_INVOKABLE bool setFolioTitle(int folioIndex, const QString &title);