diff --git a/misc/qet-mcp/qet_mcp.py b/misc/qet-mcp/qet_mcp.py index 7de720d62..e6d392a1c 100755 --- a/misc/qet-mcp/qet_mcp.py +++ b/misc/qet-mcp/qet_mcp.py @@ -1581,6 +1581,13 @@ OPS = { "remove_folio": ("removeFolio", [("folio", "folio")]), "set_folio": ("setFolioProperty", [("folio", "folio"), ("property", "str"), ("value", "str")]), + # A cable drawn across conductors, as the cable tool draws it: every + # conductor the line crosses gets the next core and its colour. + "add_cable": ("addCable", [("folio", "folio"), ("designation", "str"), + ("type", "str"), ("core_colors", "list"), + ("length", "str"), + ("x1", "num"), ("y1", "num"), + ("x2", "num"), ("y2", "num")]), "add_terminal_strip": ("addTerminalStrip", [("installation", "str"), ("location", "str"), ("name", "str")]), "remove_terminal_strip": ("removeTerminalStrip", [("strip", "folio")]), @@ -5142,7 +5149,7 @@ TOOLS = [ "it to one element AFTER it is placed (add_element does not number " "what it places); slaves and reports are refused, since they take " "their label from their master. " - "Terminal strips: add_terminal_strip returns an index (name " + "Cables: add_cable (folio, designation -- empty for the next free name --, type, core_colors, length, x1, y1, x2, y2) draws a new cable's trunk line across the conductors between the two points, as the cable tool does: each crossed conductor, in order along the line, gets the next core and the colour core_colors lists at that place; a conductor another cable already holds makes the op fail. Returns the cable's uuid. Terminal strips: add_terminal_strip returns an index (name " "it \"$id\"); add_to_strip puts a terminal-type element on " "it, and refuses any other kind. group_terminals/bridge_terminals " "take \"indices\" (at least two) into that strip's real-terminal " diff --git a/misc/qet-mcp/test_qet_mcp.py b/misc/qet-mcp/test_qet_mcp.py index 57af9cdf0..51a010cd6 100644 --- a/misc/qet-mcp/test_qet_mcp.py +++ b/misc/qet-mcp/test_qet_mcp.py @@ -437,6 +437,9 @@ class EditValidation(unittest.TestCase): "set_element_text": el + [{"op": "set_element_text", "folio": "$f", "element": "$e", "index": 0, "property": "x", "value": "5"}], "delete_element_text": el + [{"op": "delete_element_text", "folio": "$f", "element": "$e", "index": 0}], + "add_cable": [f, {"op": "add_cable", "id": "k", "folio": "$f", "designation": "-W1", + "type": "NYM-J 3x1,5", "core_colors": ["BN", "BU", "GNYE"], + "length": "2 m", "x1": 0, "y1": 0, "x2": 100, "y2": 0}], "add_terminal_strip": [{"op": "add_terminal_strip", "installation": "a", "location": "b", "name": "c"}], "remove_terminal_strip": [{"op": "remove_terminal_strip", "strip": 0}], "add_to_strip": el + [{"op": "add_to_strip", "strip": 0, "folio": "$f", "element": "$e"}], diff --git a/sources/scripting/qetscriptapi.cpp b/sources/scripting/qetscriptapi.cpp index cec665675..cde86eef6 100644 --- a/sources/scripting/qetscriptapi.cpp +++ b/sources/scripting/qetscriptapi.cpp @@ -102,6 +102,10 @@ #include #include #include +#include "../cable/addcablecommand.h" +#include "../cable/cable.h" +#include "../cable/cablemanager.h" +#include "../cable/cablepart.h" #include #include #include @@ -2262,6 +2266,108 @@ int QetScriptApi::addShape(int folioIndex, const QString &type, return sortedShapes(folioIndex).indexOf(shape); } +/** + @brief QetScriptApi::addCable + Draw a cable across conductors, as the cable tool does: the line from + (x1, y1) to (x2, y2) on the folio becomes the cable's trunk, every + conductor it crosses gets the next core, in order along the line, and + with it the colour @p coreColors lists at that place. The cable is a + new one, named @p designation (the next free name when empty), of + type @p type, as long as @p length says. One undo step, through the + same AddCableCommand the tool pushes. + A conductor another cable already holds is not taken away from it: + the call is refused instead, since a script cannot be asked, as the + tool's dialog asks, whether to move it. + @return the cable's uuid, or an empty string +*/ +QString QetScriptApi::addCable(int folioIndex, const QString &designation, + const QString &type, const QStringList &coreColors, + const QString &length, + double x1, double y1, double x2, double y2) +{ + if (!m_project) return QString(); + if (m_project->isReadOnly()) { + log(QStringLiteral("qet.addCable: project is read-only")); + return QString(); + } + const QList diagrams = m_project->folios(); + if (folioIndex < 0 || folioIndex >= diagrams.count()) return QString(); + Diagram *diagram = built(diagrams.at(folioIndex)); + + const QLineF line(QPointF(x1, y1), QPointF(x2, y2)); + const QList crossings = CableManager::crossedConductors(diagram, line); + if (crossings.isEmpty()) { + log(QStringLiteral("qet.addCable: the line crosses no conductor")); + return QString(); + } + for (const CableCrossing &crossing : crossings) { + if (crossing.conductor && !crossing.conductor->properties().m_cable_uuid.isNull()) { + log(QStringLiteral("qet.addCable: a crossed conductor already belongs to a cable")); + return QString(); + } + } + + Cable *cable = m_project->newCable(); + cable->setType(type); + cable->setCoreCount(qMax(int(coreColors.size()), int(crossings.size()))); + cable->setCoreColors(coreColors); + cable->setLength(length); + if (designation.trimmed().isEmpty()) { + cable->setDesignation(CableManager::nextDesignation(m_project, diagram)); + } else { + cable->setDesignation(designation.trimmed()); + cable->setDesignationByHand(true); + } + + CablePartData part; + part.uuid = QUuid::createUuid(); + part.diagram = diagram->uuid(); + part.p1 = line.p1(); + part.p2 = line.p2(); + cable->addPart(part); + + int core_number = 0; + for (const CableCrossing &crossing : crossings) + { + Conductor *conductor = crossing.conductor; + if (!conductor) continue; + CableManager::claimConductor(m_project, conductor, cable); + //A cable binds a conductor by its identity (@see + //CableCreateDialog::assignCrossings) + conductor->setUuid(conductor->uuid()); + CableCore core; + core.core = core_number++; + core.part = part.uuid; + core.conductor = conductor->uuid(); + core.position = crossing.position; + cable->setCore(core); + } + + auto *item = new CablePart(part); + item->setCable(cable); + diagram->addItem(item); + m_project->undoStack()->push(new AddCableCommand(cable, item, diagram, true)); + return cable->uuid().toString(); +} + +/** + @brief QetScriptApi::cables + @return one line per cable of the project: designation, type, cores + used of cores, length and uuid +*/ +QStringList QetScriptApi::cables() const +{ + QStringList out; + if (!m_project) return out; + for (Cable *cable : m_project->cables()) { + out << QStringLiteral("%1: %2, %3/%4 cores, %5 %6") + .arg(cable->designation(), cable->type()) + .arg(cable->usedCoreCount()).arg(cable->coreCount()) + .arg(cable->length(), cable->uuid().toString()); + } + return out; +} + namespace { const QStringList &shapePropertyNames() { diff --git a/sources/scripting/qetscriptapi.h b/sources/scripting/qetscriptapi.h index 9d0c9c7b7..13b6a61ca 100644 --- a/sources/scripting/qetscriptapi.h +++ b/sources/scripting/qetscriptapi.h @@ -490,6 +490,13 @@ class QetScriptApi : public QObject Q_INVOKABLE bool setTextRotation(int folioIndex, int textIndex, double angle); Q_INVOKABLE bool deleteText(int folioIndex, int textIndex); + // -- cables -- + Q_INVOKABLE QString addCable(int folioIndex, const QString &designation, + const QString &type, const QStringList &coreColors, + const QString &length, + double x1, double y1, double x2, double y2); + Q_INVOKABLE QStringList cables() const; + Q_INVOKABLE QStringList shapes(int folioIndex) const; Q_INVOKABLE int shapeIndex(int folioIndex, const QString &uuid) const; Q_INVOKABLE int addShape(int folioIndex, const QString &type,