mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-28 04:54:13 +02:00
Let a script wire, label and rotate, not only place
The scripting API (bugtracker #162) could place an element and move it, and could count conductors but not make one. So a script could put a coil and a motor on a folio and had no way to connect them, which is most of what drawing is. This adds the missing verbs: addConductor() wire terminal i of one element to terminal j of another rotateElement() setElementInfo() any information key setElementLabel() the label key, by name, since it is the one people want addFolio() setFolioTitle() elementUuids() what is on this folio elementName() elementTerminals() which terminal index is which, before wiring it Each goes through the command the GUI already uses, so a script's edits undo like manual ones and reach the project database the same way: ConductorCreator (the drag-a-rectangle-over-terminals path, which is what makes a new conductor inherit an existing potential's properties and join auto-numbering), ChangeElementInformationCommand, QETProject::addNewDiagram(), ChangeTitleBlockCommand. rotateElement() pushes the same QPropertyUndoCommand on "rotation" that RotateSelectionCommand pushes for an Element, rather than RotateSelectionCommand itself, which works on the diagram's selection and would mean rewriting the user's selection to rotate one element. Terminals are addressed by index, not uuid. Terminal::uuid() is a property of the catalog .elmt definition: empty for most of the installed base, and where present, identical across every instance of that element -- two coils of the same type placed side by side have byte-identical terminal uuids, so a uuid cannot say which coil's A1 is meant. elementTerminals() exists so a script can see the indexing instead of guessing it. The one real hazard is that ConductorCreator asks the user which potential to inherit from when the two terminals sit on two different existing ones, and it asks with a plain modal QDialog that QET::QetMessageBox's non-interactive mode does not cover -- so under headless --run there is nobody to answer and the call never returns. Measured: with the check removed, that one call hangs until killed; with it, it declines in 0.4 s. addConductor() therefore refuses that case, the same way and for the same reason addElement() already refuses the import-conflict dialog. To make that check without duplicating the condition, existingPotential() becomes static over an explicit terminal list and ConductorCreator gains a public needsPotentialChoice() predicate. Behaviour of the GUI path is unchanged; setUpPropertieToUse() passes m_terminals_list to the same code it called before. Verified headlessly against a copy of examples/ArduinoLCD.qet: new folio titled, two coils placed, wired, labelled, an info key set and the element rotated; saved, reloaded, and the conductor, label, title and rotation (persisted as orientation="1") all read back. Re-saving the result is byte-identical. qet-lint clean on the generated project; qet-coherence-check clean on it and on the 24-project example corpus, and shown to report 9 findings on a deliberately broken copy of the same file, so the clean result discriminates. Qt 6.10.2, ctest identical to master (the 61 failures are the vendored KDE ECM suite, present on both). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
class QETProject;
|
||||
class DiagramView;
|
||||
class Element;
|
||||
class Terminal;
|
||||
|
||||
/**
|
||||
@brief The QetScriptApi class
|
||||
@@ -65,12 +66,34 @@ class Element;
|
||||
QPropertyUndoCommand merges consecutive commands on the same
|
||||
object+property when their text() also matches
|
||||
(QPropertyUndoCommand::mergeWith(), pre-existing), and
|
||||
setElementPosition()/moveElement() always use the same text for a
|
||||
given element -- so several position changes to the same element in a
|
||||
row collapse into one undo step, the same way dragging an element
|
||||
does, not one step per call. Verified against exactly that: two
|
||||
setElementPosition()/moveElement()/rotateElement() always use the
|
||||
same text for a given element -- so several position changes, or
|
||||
several rotations, of the same element in a row collapse into one
|
||||
undo step, the same way dragging or repeatedly rotating an element
|
||||
does, not one step per call. setElementInfo()/setElementLabel()
|
||||
behave the same way for the same reason, through
|
||||
ChangeElementInformationCommand::mergeWith(). Verified against exactly that: two
|
||||
consecutive calls on one element, then undo/undo/redo/redo, land
|
||||
where a merge predicts, not where two independent steps would.
|
||||
- @b Wiring, @b labelling and @b folios: create a conductor between two
|
||||
terminals (ConductorCreator, the same class the GUI's
|
||||
drag-a-rectangle-over-terminals path uses, so the result inherits an
|
||||
existing potential's properties and joins conductor auto-numbering),
|
||||
change an element's label or any other information key
|
||||
(ChangeElementInformationCommand, which also tells the project
|
||||
database what changed), add a folio (QETProject::addNewDiagram(),
|
||||
already undoable) and set its title (ChangeTitleBlockCommand). With
|
||||
addElement() these are what make a script able to draw rather than
|
||||
only rearrange: before them a script could place two symbols and had
|
||||
no way to connect them.
|
||||
|
||||
Terminals are addressed by their @b index in Element::terminals(),
|
||||
not by uuid, and elementTerminals() prints that indexing so a script
|
||||
can see what it is about to wire. Terminal uuids look like the
|
||||
obvious key and are not one: Terminal::uuid() is a property of the
|
||||
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 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
|
||||
@@ -87,7 +110,11 @@ class Element;
|
||||
import-collision case that would otherwise reach
|
||||
QETProject::importElement()'s own ImportElementDialog::exec() and
|
||||
refuses instead, rather than let a plain QDialog (not routed through
|
||||
QetMessageBox) block a script the same way.
|
||||
QetMessageBox) block a script the same way. addConductor() declines the
|
||||
same way, for the same reason, when the two terminals belong to two
|
||||
different existing potentials and ConductorCreator would therefore ask
|
||||
which one's properties to inherit -- measured: with that check removed,
|
||||
exactly that call never returns.
|
||||
*/
|
||||
class QetScriptApi : public QObject
|
||||
{
|
||||
@@ -128,7 +155,29 @@ class QetScriptApi : public QObject
|
||||
Q_INVOKABLE QString addElement(int folioIndex, const QString &locationPath, double x, double y);
|
||||
Q_INVOKABLE bool setElementPosition(int folioIndex, const QString &elementUuid, double x, double y);
|
||||
Q_INVOKABLE bool moveElement(int folioIndex, const QString &elementUuid, double dx, double dy);
|
||||
Q_INVOKABLE bool rotateElement(int folioIndex, const QString &elementUuid, double angle);
|
||||
Q_INVOKABLE bool deleteElement(int folioIndex, const QString &elementUuid);
|
||||
|
||||
// -- address what is already there --
|
||||
Q_INVOKABLE QStringList elementUuids(int folioIndex) const;
|
||||
Q_INVOKABLE QString elementName(int folioIndex, const QString &elementUuid) const;
|
||||
Q_INVOKABLE QStringList elementTerminals(int folioIndex, const QString &elementUuid) const;
|
||||
|
||||
// -- element information, through ChangeElementInformationCommand --
|
||||
Q_INVOKABLE QString elementInfo(int folioIndex, const QString &elementUuid, const QString &key) const;
|
||||
Q_INVOKABLE bool setElementInfo(int folioIndex, const QString &elementUuid, const QString &key, const QString &value);
|
||||
Q_INVOKABLE QString elementLabel(int folioIndex, const QString &elementUuid) const;
|
||||
Q_INVOKABLE bool setElementLabel(int folioIndex, const QString &elementUuid, const QString &label);
|
||||
|
||||
// -- wire two terminals together --
|
||||
Q_INVOKABLE bool addConductor(int folioIndex,
|
||||
const QString &elementUuidA, int terminalIndexA,
|
||||
const QString &elementUuidB, int terminalIndexB);
|
||||
|
||||
// -- folios --
|
||||
Q_INVOKABLE int addFolio();
|
||||
Q_INVOKABLE bool setFolioTitle(int folioIndex, const QString &title);
|
||||
|
||||
Q_INVOKABLE bool undo();
|
||||
Q_INVOKABLE bool redo();
|
||||
Q_INVOKABLE bool canUndo() const;
|
||||
@@ -148,6 +197,10 @@ class QetScriptApi : public QObject
|
||||
private:
|
||||
bool runFlag(const QString &flag, const QStringList &args);
|
||||
Element *findElement(int folioIndex, const QString &elementUuid) const;
|
||||
Terminal *findTerminal(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);
|
||||
|
||||
QETProject *m_project;
|
||||
DiagramView *m_view;
|
||||
|
||||
Reference in New Issue
Block a user