Discussion #1158: a real terminal takes one or two wires (four with
double ferrules), a folio report is a virtual point that carries one, but
QElectroTech lets any number of wires be connected anywhere.
Project properties > General gets a "Conducteurs par borne" group:
- the most wires a terminal may take (0, the default, is no limit);
- "one wire per folio report".
When set, a new wire that would go past the limit is refused: the
terminal shows red while dragging, as for any refused link, and a tooltip
says why on release. Auto-connect on placing, moving or multi-pasting a
symbol skips full terminals, and qet.addConductor() refuses with its own
message. Wires already drawn, opening, pasting and undo are never
refused.
Settings > General gets a master switch, on by default, that turns every
rule of this feature off in every project; the project group is greyed
with a note while it is off.
The rules live in wiringrules.cpp. The project setting is saved as
<wiring_rules .../> only when a rule is on, so a project that never used
it saves exactly as before; an older version drops it, which means "off".
tst_wiringrules covers the rules, the save round trip and, through the
real binary, that a wire past the limit is refused unless the master
switch is off (checked to fail with the limit check removed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
Review of the previous commit:
- The load fallback compared a saved uuid with occurrence 0 only, so a
wire on the second of two terminals at one point of a symbol was lost
once the definition was replaced, and one on the first could go to
either of the pair (Element::m_terminals is sorted, not in definition
order). Element::parseTerminal() now records each terminal's rank among
the terminals of the definition at the same point, derivedUuid() uses
it, and fillMissing() starts from the same rank.
derivedUuidFoundAfterReplacement runs on perceuse.qet and industrial.qet
too: 154/156 and 670/671 wires without the rank, all with it.
qet-mcp: the first save of an older project now rewrites its wires from
the numbered form to the uuid form, and qet_diff keyed the two forms
differently, so an untouched resave showed every wire removed and added
(4 failures in test_qet_mcp.py). A uuid end is now resolved to the same
key as a numbered one: the terminal's definition position, moved to where
the wire docks, is the placed symbol's <terminal> record.
test_conductor_key_same_in_both_forms fails without it; 253/253 pass on
this build and on the previous stage's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Most symbols stored in older projects have no uuid on their terminals
(706 of the 900 in the 24 examples), so a terminal's identity is worked
out from where it sits in its symbol on every load (stableUuid()). That
is only sound while nothing keyed on it is kept between loads.
- On opening a project, every terminal of its embedded symbols without a
uuid gets that same derived value (TerminalUuids::fillMissing(), from
XmlElementCollection's loading constructor, before any folio is
built). The next save writes it, and the wires on it in the form that
names terminals by uuid, which QElectroTech reads since 0.8.0.
- The recipe moves to TerminalUuids::derived(), which stableUuid() now
calls, so the two cannot drift apart. A second terminal at the same
point of a symbol gets the next occurrence, and no value is given
twice within a symbol.
- findTerminal(): a wire whose terminal uuid is not found is matched to
the terminal whose derived value it is, so a saved uuid still finds its
terminal after the symbol's definition was replaced by one whose
terminals carry other uuids.
The project database's terminal and conductor tables are identical before
and after on all 24 examples except the 3 terminals that share a point
with another in their symbol (industrial.qet 1, perceuse.qet 2), which
now have an identity of their own. Every example keeps every wire through
a resave, and a second save changes nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New QLineEdit (m_potential_le) between Type and Nom: an optional,
symbol-author-chosen grouping identifier shared by terminals that
belong to the same physical terminal within a multi-terminal block.
Stored as TerminalData::m_potential (new field, persisted as the
"potential" XML attribute, empty by default).
Used by relatedPotentialTerminal() in terminal.cpp: when
potential_isolating is enabled on a Terminal-type element, terminals
sharing a non-empty, matching potential value now stay electrically
linked to each other instead of every terminal in the block being
isolated from every other one.
Tooltip on the field for explanation
The conductor table keyed on Terminal::uuid(), which comes from the catalog
.elmt definition and is empty for every element authored before that field
existed. A conductor was dropped unless *both* its terminals had one, so the
tables this slice adds were empty on almost every project in existence:
examples corpus conductor rows in the database
industrial.qet 0 of 671
affuteuse_250h.qet 0 of 263
tremie_vibrante.qet 0 of 77
741.qet 0 of 67
Across the 23 example projects, 16 of the 20 that contain conductors have
zero terminal uuids -- 2366 of 3002 conductors -- and overall coverage is
7.3%. Meanwhile --export-cables, already on master, lists all 671 conductors
of industrial.qet from the document. A feature that only works on newly
authored elements is not one users can rely on.
Terminal::stableUuid() returns the terminal's own uuid when it has one and
otherwise derives one from its local position and orientation inside its
element. That is not an invented scheme: it is what the project format
already does. TerminalData::fromXml() says so where it parses the field --
"if the attribute not exists, means, the element is created with an older
version of qet. So use the legacy approach to identify terminals" -- and the
legacy approach is the terminal's position. m_pos is read from the definition
and is not touched by moving the element on a folio, so the identity survives
loads, saves and folio moves. Derived values are UUID v5 in a fixed namespace,
so they are reproducible without being stored, and cannot collide with the v4
uuids the element editor generates.
Every project in the corpus now has exactly as many conductor rows as the
document has conductors -- 20 of 20 measured, 0 mismatches. (schema_indus.qet
is excluded: it blocks on a modal dialog at zero CPU under any CLI flag, the
pre-existing hang PR #661 addresses.)
Two things this deliberately does not key on:
- The terminal name. It is not stable: QET rewrites a terminal named "_" as
unnamed, which would have silently changed the identity of 1421 of
industrial.qet's 1790 terminals on their first resave. Measured across the
corpus, dropping it costs nothing -- geometry alone yields exactly the same
three collisions -- and it means renaming a terminal no longer changes what
it is.
- Uniqueness in the face of a definition that declares two terminals at the
same point and orientation. Three cases exist in the whole corpus. They
merge to a single terminal row, which is harmless: two terminals identical
in position and orientation are indistinguishable in every observable
respect, and every conductor on either still resolves to the right element
and terminal name. Both affected projects (industrial, perceuse) return
their full conductor count.
The only conductor still skipped is one whose terminal has no parent element,
which has no identity to key on at all.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Extend TerminalData::Type enum with three new semantic values:
- No : Normally Open terminal of a switch (SW) contact
- Nc : Normally Closed terminal of a switch (SW) contact
- Common : Common terminal of a switch (SW) contact
Update typeToString() and typeFromString() accordingly.
Fully backward compatible: existing Generic/Inner/Outer types
are unchanged. Elements without typed terminals fall back
to the previous behavior (first 2 named terminals).
terminal: expose terminalType() as public accessor
Add Terminal::terminalType() returning the TerminalData::Type
of this terminal. This allows crossrefitem and other consumers
to filter terminals by semantic role (No, Nc, Common) without
accessing TerminalData internals directly.
terminaleditor: add No, Nc, Common entries to type combobox
Expose the three new TerminalData types (No, Nc, Common) in
the element editor UI so users can assign a semantic role to
each terminal of a SW contact element.
Also fix a pre-existing bug in updateForm() where m_type_cb
was incorrectly using m_orientation_cb->findData() instead
of m_type_cb->findData(), preventing the type from being
restored correctly when selecting a terminal.
terminaleditor: add No, Nc, Common entries to type combobox
Expose the three new TerminalData types (No, Nc, Common) in
the element editor UI so users can assign a semantic role to
each terminal of a SW contact element.
Also fix a pre-existing bug in updateForm() where m_type_cb
was incorrectly using m_orientation_cb->findData() instead
of m_type_cb->findData(), preventing the type from being
restored correctly when selecting a terminal.
When the search function is searching in a terminal element, they search only for the first terminal found, no matter if the terminal element have more than two terminals.
So the list of conductors at the same potential is missing some conductors.
This commit fix it, now the search function search for every terminals of a terminal element
git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@5307 bfdf4180-ca20-0410-9c96-a3a8aa849046