Let a script number a conductor and link a cross-reference

Two gaps left over from the drawing verbs. A script could create a
conductor but not say what it was -- no number, colour, section or
formula -- and could not link a master to its slave, although
LinkElementCommand has been there all along and nothing bound it.

  conductors()            what is on this folio, and how to address it
  conductorProperty()
  setConductorProperty()  num, formula, function, bus, cable,
                          tension_protocol, conductor_color,
                          conductor_section, color, text_color
  elementLinkType()       simple / master / slave / next_report / ...
  linkedElements()
  linkElements()          two folio indices: a master and its slave are
                          normally on different folios
  unlinkElement()

The property names are the ones the .qet file uses for the same fields,
so what a script sets is what a reader of the file sees rather than a
third spelling invented here.

A property is applied to every conductor of the same electrical
potential, not to the one conductor named. That is the rule the
application already follows -- SearchAndReplaceWorker pushes one
QPropertyUndoCommand per conductor of relatedPotentialConductors()
inside a macro -- because a wire number describes a potential, not one
drawn segment; setting it on one and leaving the rest of the potential
disagreeing would produce a file no GUI action could have produced.

Linking asks LinkElementCommand::isLinkable() rather than re-deriving
its rules, so a script cannot make a link the GUI would refuse: master
to master, a PLC master to a non-PLC slave, a next-report to another
next-report, or anything to an already-taken target.

A conductor is addressed as "the conductor on terminal i of element U".
It has no identity of its own to use instead: conductors carry no
persisted uuid, and the terminal1/terminal2 ids in the file are
folio-scoped integers QElectroTech renumbers on every save. Since the
change is potential-wide, any terminal of the potential names it equally
well, so in practice a potential is addressed from one of its leaves; a
terminal carrying several conductors names none of them and is refused
rather than guessed at.

Verified headlessly. Conductor: num, section and colour set from one end
of a potential and read back from the other, saved and reloaded, present
in the XML. Propagation shown to discriminate, which took two tries --
the first attempt wired A.0-B.0 and B.1-C.0 and saw no propagation,
correctly, because a coil's two terminals are opposite ends of the coil
and not one potential. Wiring a real hub at A.0 instead, a number set
via the B leaf appears on the C conductor too, in memory and in the
saved file. Cross-reference: a master on one folio linked to a slave on
another, linkedElements() agreeing from both ends, surviving save and
reload with link_uuid written on both folios; master-to-master,
self-link, unlink and relink all behave. Unknown property, invalid
colour, bare terminal and ambiguous terminal all decline with a reason.

Qt 6.10.2, build clean, ctest matches master, qet-coherence-check clean
on the example corpus, qet-lint clean on the generated projects.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-09-21 18:48:40 +12:00
parent c740cdf1ac
commit 82262c5980
2 changed files with 322 additions and 0 deletions
+39
View File
@@ -26,6 +26,7 @@ class QETProject;
class DiagramView;
class Element;
class Terminal;
class Conductor;
/**
@brief The QetScriptApi class
@@ -94,6 +95,27 @@ class Terminal;
catalog .elmt definition, empty for most of the installed base and,
where present, identical across every instance of that element -- so
it does not distinguish one placed coil's A1 from another's.
- @b Conductor properties and @b cross-references: set a conductor's
number, formula, colour or section, and link a master to a slave or
one report to another. Both follow the application's own rules rather
than writing the field: a conductor property is applied to every
conductor of the same electrical potential, which is what the GUI and
search-and-replace both do -- a wire number belongs to a potential,
not to one drawn segment -- and a link is refused unless
LinkElementCommand::isLinkable() allows it, which is where the
master/slave, PLC-pairing and report-direction rules already live.
linkElements() takes a folio index for each end because a master and
its slave are usually on different ones.
A conductor is addressed as "the conductor on terminal i of element
U", not by an identity of its own: conductors have no persisted uuid,
and the folio-scoped integer ids the file uses for their ends are
renumbered on every save, so there is nothing stable to name one by.
Since the change is potential-wide anyway, any terminal of the
potential names it equally well. A terminal carrying more than one
conductor is ambiguous and is refused rather than guessed at -- which
in practice means a potential is addressed from one of its leaf
terminals, not from the hub several conductors meet at.
- @b Navigating and @b messaging: select an element, zoom the active
view, and show the user a message. Deliberately narrow: selection and
messaging work with no view at all (headless `--run`); zoom is a no-op
@@ -174,6 +196,21 @@ class QetScriptApi : public QObject
const QString &elementUuidA, int terminalIndexA,
const QString &elementUuidB, int terminalIndexB);
// -- conductor properties, applied to the whole potential --
Q_INVOKABLE QStringList conductors(int folioIndex) const;
Q_INVOKABLE QString conductorProperty(int folioIndex, const QString &elementUuid,
int terminalIndex, const QString &property) const;
Q_INVOKABLE bool setConductorProperty(int folioIndex, const QString &elementUuid,
int terminalIndex, const QString &property,
const QString &value);
// -- cross-references: master/slave and report links --
Q_INVOKABLE QString elementLinkType(int folioIndex, const QString &elementUuid) const;
Q_INVOKABLE QStringList linkedElements(int folioIndex, const QString &elementUuid) const;
Q_INVOKABLE bool linkElements(int folioIndexA, const QString &elementUuidA,
int folioIndexB, const QString &elementUuidB);
Q_INVOKABLE bool unlinkElement(int folioIndex, const QString &elementUuid);
// -- folios --
Q_INVOKABLE int addFolio();
Q_INVOKABLE bool setFolioTitle(int folioIndex, const QString &title);
@@ -199,6 +236,8 @@ class QetScriptApi : public QObject
Element *findElement(int folioIndex, const QString &elementUuid) const;
Terminal *findTerminal(int folioIndex, const QString &elementUuid, int terminalIndex,
const QString &caller);
Conductor *findConductor(int folioIndex, const QString &elementUuid, int terminalIndex,
const QString &caller);
bool setInfoKey(int folioIndex, const QString &elementUuid,
const QString &key, const QString &value, const QString &caller);