mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-29 05:44:14 +02:00
Let a script group, bridge and sort a terminal strip's real terminals
stripRealTerminals(strip) index, owning element, current
physical position, neighbours
groupTerminals(strip, indices) merge onto one physical position
bridgeTerminals(strip, indices) wire together without merging
sortTerminalStrip(strip) canonical physical order
Each goes through the same command the terminal strip editor's own
group/bridge/sort buttons push (GroupTerminalsCommand,
BridgeTerminalsCommand, SortTerminalStripCommand), so a script's changes
undo like the editor's.
groupTerminals() replicates the editor's own receiver-selection heuristic
line for line rather than picking the first terminal named: the physical
position that already carries the most real terminals receives the
others, not necessarily the one at index 0. Verified with a case built to
distinguish the two: three terminals grouped first (one position, three
real terminals), then a fourth, previously-alone terminal grouped with
one of those three, named first in the call -- the alone terminal moved
onto the three-terminal position, ending at four, not the other way
around.
bridgeTerminals() refuses through TerminalStrip::isBridgeable() itself,
the same check the editor's bridge button applies, rather than
re-deriving what "the same level" means. Real terminals are addressed by
index into stripRealTerminals(), the strip's own order; grouping shifts
later physical-position indices down, so the header says to re-list
after a change that adds or removes one, the same rule already
documented for texts, shapes and images.
Verified end to end on four placed terminal elements: added to a strip,
grouped two, refused a group of one and an out-of-range index, bridged
the remaining two, sorted, undo restoring order without disturbing the
grouping (sort doesn't touch it, so it shouldn't), and a bad strip index
refused on all three operations. Qt 6.10.2, build clean, ctest 12/12,
coherence gate clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,10 @@
|
||||
#include "../qetgraphicsitem/qetshapeitem.h"
|
||||
#include "../TerminalStrip/UndoCommand/addterminalstripcommand.h"
|
||||
#include "../TerminalStrip/UndoCommand/addterminaltostripcommand.h"
|
||||
#include "../TerminalStrip/UndoCommand/bridgeterminalscommand.h"
|
||||
#include "../TerminalStrip/UndoCommand/groupterminalscommand.h"
|
||||
#include "../TerminalStrip/UndoCommand/sortterminalstripcommand.h"
|
||||
#include "../TerminalStrip/physicalterminal.h"
|
||||
#include "../TerminalStrip/realterminal.h"
|
||||
#include "../TerminalStrip/terminalstrip.h"
|
||||
#include "../autoNum/assignvariables.h"
|
||||
@@ -1668,6 +1672,177 @@ bool QetScriptApi::addTerminalToStrip(int stripIndex, int folioIndex, const QStr
|
||||
return real->parentStrip() == strips.at(stripIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::stripRealTerminals
|
||||
The strip's real terminals -- the wire-ends added by addTerminalToStrip()
|
||||
-- one line per index: the owning element's uuid, the terminal's own
|
||||
name, and which physical position (clamp) it currently sits on, by that
|
||||
position's own index (so several real terminals reporting the same
|
||||
physical index are already grouped together).
|
||||
*/
|
||||
QStringList QetScriptApi::stripRealTerminals(int stripIndex) const
|
||||
{
|
||||
QStringList list;
|
||||
if (!m_project) return list;
|
||||
const QVector<TerminalStrip *> strips = m_project->terminalStrip();
|
||||
if (stripIndex < 0 || stripIndex >= strips.count()) return list;
|
||||
TerminalStrip *strip = strips.at(stripIndex);
|
||||
|
||||
const QVector<QSharedPointer<PhysicalTerminal>> physical = strip->physicalTerminal();
|
||||
const QVector<QSharedPointer<RealTerminal>> real = strip->realTerminals();
|
||||
for (int i = 0 ; i < real.count() ; ++i)
|
||||
{
|
||||
QSharedPointer<RealTerminal> rt = real.at(i);
|
||||
QSharedPointer<PhysicalTerminal> pt = rt->physicalTerminal();
|
||||
const int physical_index = pt ? physical.indexOf(pt) : -1;
|
||||
list << QStringLiteral("%1: %2 terminal '%3', physical position %4 (%5 terminal(s) there)")
|
||||
.arg(i)
|
||||
.arg(rt->element() ? rt->element()->uuid().toString() : QStringLiteral("?"))
|
||||
.arg(rt->label())
|
||||
.arg(physical_index)
|
||||
.arg(pt ? pt->realTerminalCount() : 0);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
namespace {
|
||||
/**
|
||||
Resolve a list of indices into stripRealTerminals() to the RealTerminal
|
||||
objects groupTerminals()/bridgeTerminals() need, or an empty (and
|
||||
therefore refusable) list if any index is out of range or the list has
|
||||
fewer than the two terminals either operation requires.
|
||||
*/
|
||||
QVector<QSharedPointer<RealTerminal>> resolveRealTerminals(
|
||||
TerminalStrip *strip, const QVariantList &indices, const QString &caller,
|
||||
QetScriptApi *api)
|
||||
{
|
||||
QVector<QSharedPointer<RealTerminal>> out;
|
||||
const QVector<QSharedPointer<RealTerminal>> all = strip->realTerminals();
|
||||
if (indices.count() < 2) {
|
||||
api->log(QStringLiteral("qet.%1: at least two real terminals are required").arg(caller));
|
||||
return {};
|
||||
}
|
||||
for (const QVariant &v : indices) {
|
||||
bool ok = false;
|
||||
const int i = v.toInt(&ok);
|
||||
if (!ok || i < 0 || i >= all.count()) {
|
||||
api->log(QStringLiteral("qet.%1: %2 is not a valid real terminal index (strip has %3)")
|
||||
.arg(caller, v.toString()).arg(all.count()));
|
||||
return {};
|
||||
}
|
||||
out << all.at(i);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::groupTerminals
|
||||
Merge several real terminals onto one physical position, through
|
||||
GroupTerminalsCommand exactly as the terminal strip editor's "group"
|
||||
button does -- including which position receives the others: the one
|
||||
among those named that already carries the most real terminals, the
|
||||
same heuristic the editor applies, not necessarily the first one given.
|
||||
*/
|
||||
bool QetScriptApi::groupTerminals(int stripIndex, const QVariantList &realTerminalIndices)
|
||||
{
|
||||
if (!m_project) return false;
|
||||
const QString caller = QStringLiteral("groupTerminals");
|
||||
if (m_project->isReadOnly()) {
|
||||
log(QStringLiteral("qet.%1: project is read-only").arg(caller));
|
||||
return false;
|
||||
}
|
||||
const QVector<TerminalStrip *> strips = m_project->terminalStrip();
|
||||
if (stripIndex < 0 || stripIndex >= strips.count()) {
|
||||
log(QStringLiteral("qet.%1: no strip at index %2").arg(caller).arg(stripIndex));
|
||||
return false;
|
||||
}
|
||||
TerminalStrip *strip = strips.at(stripIndex);
|
||||
const QVector<QSharedPointer<RealTerminal>> chosen = resolveRealTerminals(strip, realTerminalIndices, caller, this);
|
||||
if (chosen.isEmpty()) return false;
|
||||
|
||||
QSharedPointer<PhysicalTerminal> receiver = chosen.first()->physicalTerminal();
|
||||
int best_count = 0;
|
||||
for (const QSharedPointer<RealTerminal> &rt : chosen) {
|
||||
QSharedPointer<PhysicalTerminal> pt = rt->physicalTerminal();
|
||||
const int count = pt ? pt->realTerminalCount() : 0;
|
||||
if (count > 1 && count > best_count) {
|
||||
best_count = count;
|
||||
receiver = pt;
|
||||
}
|
||||
}
|
||||
if (!receiver) {
|
||||
log(QStringLiteral("qet.%1: no physical position to receive the group").arg(caller));
|
||||
return false;
|
||||
}
|
||||
|
||||
QVector<QSharedPointer<RealTerminal>> to_group = chosen;
|
||||
for (const QSharedPointer<RealTerminal> &rt : receiver->realTerminals()) {
|
||||
to_group.removeOne(rt);
|
||||
}
|
||||
if (to_group.isEmpty()) {
|
||||
log(QStringLiteral("qet.%1: every named terminal is already on the receiving position").arg(caller));
|
||||
return true;
|
||||
}
|
||||
const int before = strip->physicalTerminalCount();
|
||||
m_project->undoStack()->push(new GroupTerminalsCommand(strip, receiver, to_group));
|
||||
return strip->physicalTerminalCount() < before;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::bridgeTerminals
|
||||
Wire several real terminals together electrically, through
|
||||
BridgeTerminalsCommand as the editor's "bridge" button does. Refused,
|
||||
via TerminalStrip::isBridgeable(), when they are not all at the same
|
||||
level -- the editor's own check, not a rule reimplemented here.
|
||||
*/
|
||||
bool QetScriptApi::bridgeTerminals(int stripIndex, const QVariantList &realTerminalIndices)
|
||||
{
|
||||
if (!m_project) return false;
|
||||
const QString caller = QStringLiteral("bridgeTerminals");
|
||||
if (m_project->isReadOnly()) {
|
||||
log(QStringLiteral("qet.%1: project is read-only").arg(caller));
|
||||
return false;
|
||||
}
|
||||
const QVector<TerminalStrip *> strips = m_project->terminalStrip();
|
||||
if (stripIndex < 0 || stripIndex >= strips.count()) {
|
||||
log(QStringLiteral("qet.%1: no strip at index %2").arg(caller).arg(stripIndex));
|
||||
return false;
|
||||
}
|
||||
TerminalStrip *strip = strips.at(stripIndex);
|
||||
const QVector<QSharedPointer<RealTerminal>> chosen = resolveRealTerminals(strip, realTerminalIndices, caller, this);
|
||||
if (chosen.isEmpty()) return false;
|
||||
|
||||
if (!strip->isBridgeable(chosen)) {
|
||||
log(QStringLiteral("qet.%1: these terminals cannot be bridged -- they are not all at the same level")
|
||||
.arg(caller));
|
||||
return false;
|
||||
}
|
||||
m_project->undoStack()->push(new BridgeTerminalsCommand(strip, chosen));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QetScriptApi::sortTerminalStrip
|
||||
Reorder a strip's physical positions into the canonical order the
|
||||
editor's own "sort" button computes, through SortTerminalStripCommand.
|
||||
*/
|
||||
bool QetScriptApi::sortTerminalStrip(int stripIndex)
|
||||
{
|
||||
if (!m_project) return false;
|
||||
if (m_project->isReadOnly()) {
|
||||
log(QStringLiteral("qet.sortTerminalStrip: project is read-only"));
|
||||
return false;
|
||||
}
|
||||
const QVector<TerminalStrip *> strips = m_project->terminalStrip();
|
||||
if (stripIndex < 0 || stripIndex >= strips.count()) {
|
||||
log(QStringLiteral("qet.sortTerminalStrip: no strip at index %1").arg(stripIndex));
|
||||
return false;
|
||||
}
|
||||
m_project->undoStack()->push(new SortTerminalStripCommand(strips.at(stripIndex)));
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
QHash<QString, NumerotationContext> autoNumTable(QETProject *project, const QString &kind, bool *ok)
|
||||
{
|
||||
|
||||
@@ -168,6 +168,25 @@ class DynamicElementTextItem;
|
||||
re-sorted) and does shift when one is removed. Only elements whose
|
||||
link type is "terminal" can be added, the same restriction the
|
||||
editor enforces by construction.
|
||||
|
||||
stripRealTerminals() lists the strip's real terminals -- the actual
|
||||
wire-ends added by addTerminalToStrip(), one per index -- which
|
||||
physical position (clamp) each currently sits on and how many
|
||||
neighbours share it, since that is what groupTerminals() and
|
||||
bridgeTerminals() address by index into.
|
||||
|
||||
groupTerminals() merges several real terminals onto one physical
|
||||
position, choosing the receiving position the same way the terminal
|
||||
strip editor's own "group" button does: the position among the ones
|
||||
named that already carries the most real terminals, not necessarily
|
||||
the first one given -- a script asking to group indices [0, 1] is not
|
||||
guaranteed index 0's position is where they end up. bridgeTerminals()
|
||||
wires several real terminals together electrically without merging
|
||||
their positions, refused (TerminalStrip::isBridgeable()) when they
|
||||
are not all at the same level -- the same check the editor's bridge
|
||||
button applies, not a rule reimplemented here. sortTerminalStrip()
|
||||
reorders the strip's physical positions into the canonical order the
|
||||
editor's own sort button computes.
|
||||
- @b Auto-numbering: define a named numbering context of kind
|
||||
"conductor", "element" or "folio", built from parts written
|
||||
"type[:value[:increase]]" -- types are the ones the auto-numbering
|
||||
@@ -402,6 +421,10 @@ class QetScriptApi : public QObject
|
||||
Q_INVOKABLE bool removeTerminalStrip(int stripIndex);
|
||||
Q_INVOKABLE bool addTerminalToStrip(int stripIndex, int folioIndex,
|
||||
const QString &elementUuid);
|
||||
Q_INVOKABLE QStringList stripRealTerminals(int stripIndex) const;
|
||||
Q_INVOKABLE bool groupTerminals(int stripIndex, const QVariantList &realTerminalIndices);
|
||||
Q_INVOKABLE bool bridgeTerminals(int stripIndex, const QVariantList &realTerminalIndices);
|
||||
Q_INVOKABLE bool sortTerminalStrip(int stripIndex);
|
||||
|
||||
// -- auto-numbering contexts (conductor, element, folio) --
|
||||
Q_INVOKABLE QStringList autoNums(const QString &kind) const;
|
||||
|
||||
Reference in New Issue
Block a user