Commit Graph

9738 Commits

Author SHA1 Message Date
Alfmat01 db3ca9eb6d Merge pull request #1 from Alfmat01/Alfmat01-Complete-Spanish-translations
Complete Spanish translations

Complete 1,383 pending entries in lang/qet_es.ts, using terminology appropriate for electrical schematics, wiring and control panels.

Translate missing entries and review unfinished drafts.

Preserve placeholders, plural forms, links and markup.

Leave previously completed entries unchanged.

Validation: XML structure checked and no pending translations remain in the submitted file. Not tested in the running application.
2026-09-28 09:33:08 +02:00
Alfmat01 257ec77136 Complete Spanish translations
Complete Spanish translations
2026-09-28 09:27:43 +02:00
ispyisail 1586aaec75 Merge pull request #1097 from ispyisail/fix/qet-mcp-free-texts-only
Fix qet_diff counting a symbol's own texts as free texts
2026-09-28 16:48:53 +13:00
ispyisail 4ad352126b Merge master into fix/qet-mcp-free-texts-only
Conflict in _extras(): keep master's tables and folio uuids and _angle(),
and read only the folio's own inputs/shapes/images as this branch does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:26:31 +13:00
ispyisail 2e56001c9d Merge pull request #1102 from ispyisail/fix/legacy-symbol-input-texts
Fix schema_indus.qet example showing no device labels
2026-09-28 16:21:27 +13:00
ispyisail 65f10f6c86 Merge pull request #1092 from ispyisail/fix/search-list-dark-icons
Fix element icons that are dark on a dark theme in search results
2026-09-28 16:20:42 +13:00
ispyisail 5585d87ea5 Merge pull request #1089 from ispyisail/fix/1069-align-lone-shape
Fix Align centre commands when a group is left with only a shape
2026-09-28 16:20:11 +13:00
ispyisail 83da997c83 Merge pull request #1100 from ispyisail/feat/qet-mcp-items
Add qet_items: list drawn items with their uuids
2026-09-28 16:15:03 +13:00
ispyisail 049a4ba673 Merge pull request #1101 from ispyisail/feat/qet-mcp-edit-table-text-uuid
Let qet_edit address tables and symbol text fields by uuid
2026-09-28 16:14:41 +13:00
ispyisail f14bc0de28 Merge pull request #1098 from ispyisail/feat/script-table-text-uuid-index
Add scripting lookups for tables and symbol text fields by uuid
2026-09-28 16:14:09 +13:00
ispyisail 6d62140445 Merge pull request #1096 from ispyisail/fix/qet-mcp-diff-rotation
Fix qet_diff not reporting a rotated symbol
2026-09-28 16:13:34 +13:00
ispyisail d04eee756a Merge pull request #1095 from ispyisail/test/qet-mcp-read-tool-contracts
Add exact-answer tests for the MCP read tools and qet_diff
2026-09-28 16:13:02 +13:00
ispyisail d8c309afce Merge pull request #1094 from ispyisail/fix/qet-mcp-autonum-not-a-wire
Fix the MCP server counting a wire-numbering rule as a wire
2026-09-28 16:12:37 +13:00
ispyisail b1689fb760 Merge pull request #1093 from ispyisail/fix/qet-mcp-continuity-folio
Fix qet_continuity reporting a missing folio as clean
2026-09-28 16:12:13 +13:00
ispyisail 2529b11d69 Convert examples/schema_indus.qet to the current format; its labels show again
schema_indus.qet was saved by QElectroTech 0.3, where each placed symbol
kept its own values for its definition's old text fields, as
<element><inputs><input text="T1" .../>. Loading those was deliberately
dropped in 1f53c3929 ("Remove retro compatibility of element text item
prior to qet 0.7"), so since 2021 this shipped example has shown none of
its per-symbol texts: 122 texts on 44 of its 48 symbols, including every
device label (Q1, KM1, KM2, T1, M1, S1-S5, H1, H2, the X terminals) and
ratings such as "24VAC" and "F0 am 0,5A".

This commit changes the example file only, not the loader. It was
converted by loading it once with a local build that had 1f53c3929
reverted (and the converted label kept when the symbol's own label was
empty, as that code intended), and saving it. That build is not proposed.

Checked with a build of current master: every one of the 44 symbols shows
exactly the texts its <inputs> held; the 48 symbols (type, position,
rotation), the 69 wires (ends and numbers) and the folio are unchanged; the
two free texts only gain their font written out, as any save does. Like any
save, the file also gains uuids and the current version number.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:01:31 +13:00
ispyisail 503c8c69b5 qet-mcp: qet_edit addresses tables and symbol text fields by uuid
set_table_position and delete_table took a table's index, and
set_element_text / delete_element_text a text field's index. An index
shifts when an earlier item is deleted, so a run that deletes table 0 and
then moves "table 1" moved the wrong table.

Each now also takes the item's uuid, resolved at run time through
qet.tableIndex() and qet.elementTextIndex() (the previous commit), as
texts, shapes and pictures already are through textIndex() and friends. A
text field's lookup is scoped to the op's element, since copies of a symbol
share their fields' uuids. An index still works, and a build without the
lookups is refused with the usual missing-methods hint only when a uuid is
actually used.

Tests: the generated script (no binary), and end to end: delete one table
then move the other, both by uuid; and edit one copy's shared field by uuid,
leaving the other copy's untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:49:36 +13:00
ispyisail 9232775a25 Merge branch 'feat/qet-mcp-diff-uuids' into feat/qet-mcp-items 2026-09-28 13:31:54 +13:00
ispyisail d92a0781b3 qet-mcp: test the text-field uuid guard on each side of a diff
A field with a uuid on a symbol with none cannot be keyed by
(symbol, field); the mutation audit showed either side's guard could be
dropped unnoticed. Now tested with the symbol uuid missing on one side,
then the other.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:31:54 +13:00
ispyisail fd962619b5 Scripting: look up a table or a symbol text field by its uuid
qet.textIndex(), shapeIndex() and imageIndex() turn a free text's, shape's
or picture's uuid into the index the other calls take. Tables and symbol
text fields had no such lookup, so a script could only name them by index,
and an index shifts when an earlier item is deleted: a script that deletes
table 0 and then moves "table 1" moves the wrong table.

- qet.tableIndex(folio, uuid): the table's current index in tables(folio),
  or -1.
- qet.elementTextIndex(folio, elementUuid, textUuid): the field's current
  index in elementTexts(folio, elementUuid), or -1. The element is part of
  the address because a field's uuid is unique only within its element:
  copying an element keeps its fields' uuids (2612_ats_singlephase.qet has
  one field uuid on 20 copies).

Tests in misc/qet-mcp's integration suite, which drives these through
--run: a table followed across a deletion of the one before it, and the
same field uuid resolving on two copies to each copy's own field. Both
fail against a build without this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:29:24 +13:00
ispyisail fd8b816475 qet-mcp: qet_items test fixture wraps its table in <tables>, as saved files do
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:20:23 +13:00
ispyisail bbe1903ec8 qet-mcp: read a folio's tables from its <tables> block only (as #1097 does for texts)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:20:22 +13:00
ispyisail 56a23d85dc Merge branch 'feat/qet-mcp-diff-uuids' into feat/qet-mcp-items 2026-09-28 13:20:22 +13:00
ispyisail a89a57bb10 qet-mcp: a symbol's own texts are not free texts on the folio
qet_diff's texts, shapes and pictures sections collected every <input>,
<shape> and <image> under a folio with iter(). Symbols in older files carry
their own <inputs><input> texts, so those were counted as the folio's free
texts: schema_indus.qet folio 1 showed 124 where QElectroTech has 2, and
editing one of those symbol texts would have been reported as a free text
changing.

Only the folio's direct <inputs>, <shapes> and <images> children are read
now. Shapes and pictures have no nested copies in the shipped examples;
they are changed too so the three stay alike. Found by comparing the
tools' answers with QElectroTech's own lists over the shipped examples.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:19:54 +13:00
ispyisail 1de307c13c Merge branch 'feat/qet-mcp-diff-uuids' into feat/qet-mcp-items 2026-09-28 13:15:21 +13:00
ispyisail 279c98f10a qet-mcp: add qet_items, listing drawn items with their uuids
qet_edit addresses free texts, shapes, pictures and tables by uuid, and
qet_diff reports them by uuid, but no tool listed them: the only way to
learn an item's uuid was to read the .qet. qet_items lists every free
text, shape, picture, table and symbol text field per folio (counted from
1, as qet_elements), with its uuid and main fields; filter by folio and
kind; default limit 500.

Also a test that every tool argument holding a data path is in the
workspace policy (_DATA_PATHS). Nothing checked that direction: a new tool
left out of the policy would have read or written anywhere with every test
passing, as removing qet_items' entry showed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:15:21 +13:00
ispyisail 8fd692783c qet-mcp: key symbol text fields by symbol and field uuid; refuse shared uuids
A symbol text field's uuid is unique only within its symbol: copying a
symbol keeps them, so 7 of the 24 shipped examples repeat one, up to 20
times (2612_ats_singlephase.qet). Keyed on the field uuid alone, those
fields merged and an edit to one copy could be reported on another. They
are now keyed on (symbol uuid, field uuid).

More generally, uuids are used as keys only when present on every item and
unique on each side; otherwise the old position/ends matching is kept, for
texts, shapes, pictures, tables, conductors and folios alike. Found by the
seeded-edit invariants (an untouched symbol's field reported changed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:15:12 +13:00
ispyisail f5888e8b56 qet-mcp: qet_diff matches conductors, folios, text fields and tables by uuid
QElectroTech now saves a uuid on conductors (those created since, or
loaded with one), folios, symbol text fields and tables, but qet_diff still
matched them by position or by ends:

- conductors: a rewire read as one wire removed and another added; by
  uuid it is that conductor with changed "ends".
- folios: a reorder read as every later folio changing its fields; by uuid
  it is one "reordered" entry, plus "added"/"removed" folios.
- symbol text fields: deleting the first of two read as the second
  changing; by uuid it is that field removed.
- tables (<graphics_table>) were not compared at all; now a section of
  their own.

Each is matched by uuid only when every item of that kind on both sides
has one; otherwise the old matching is kept, and each section says which
in "keyed_by", since older files and their first re-save mix the two.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:03:06 +13:00
ispyisail e64ce0a6ba qet-mcp: qet_diff reports rotated symbols; equal angles compare equal
Rotating a symbol changes only its orientation attribute (quarter turns),
which qet_diff did not read, so a pure rotation reported no change in any
section. The elements section now has "rotated": each symbol whose
orientation changed, with the value before and after.

Rotating and undoing leaves QElectroTech writing text-field rotations as
"-270" where they were "90" (or "-90" for "270"); compared as strings that
read as a change. Rotations of texts, shapes, pictures and element text
fields are now compared reduced to [0, 360).

Found by a seeded-edit invariant run over the shipped examples: 51
rotations unreported across 20 projects, and 7 undo sequences reported as
changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 12:55:46 +13:00
ispyisail c1b93a8892 qet-mcp: pin the read tools' and qet_diff's exact answers in tests
A mutation audit -- planting one small bug at a time in the server's read
and diff code (a flipped comparison, a skipped branch, a dropped output
field, a list cap off by one) and running this suite -- caught 78 of 241
planted bugs with the tests that need no QElectroTech binary. qet_elements,
qet_conductors and their row builders caught none: a filter that never
applied, a missing field or a wrong default limit all passed.

Two new classes pin exact output on small hand-made projects:
ReadToolContracts (qet_project_info, qet_elements, qet_conductors: every
field, every filter, limit and truncation, legacy and current conductor
keys) and DiffContracts (every qet_diff section: moves, relabels, info,
conductors and the unstable-key warning, texts/shapes/pictures by uuid and
by position, element text fields, folio and project fields, terminal
strips, and every list cap). The same audit now catches 240 of 241; the
one left is equivalent (rsplit("/", 1) vs rsplit("/", 2) then [-1]).

Tests only; no change to the server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 12:42:01 +13:00
ispyisail 18e5c30bed qet-mcp: a folio's wire-numbering rule is not a wire
A folio's conductor auto-numbering rule is saved as
<autonum><conductor><part .../></conductor></autonum>. qet_project_info
and qet_conductors counted every <conductor> tag under the folio, so the
rule appeared as a wire with no ends and no number: schema_indus.qet
folio 1 reported 70 conductors where QElectroTech holds 69.

Only children of <conductors> are wires now. A new corpus test compares
each folio's element and conductor counts with QElectroTech's own
elementCount()/conductorCount() after loading the file, over every shipped
example; it failed only on schema_indus.qet before this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 12:09:58 +13:00
ispyisail a73e5c462d qet-mcp: qet_continuity no longer reports a folio that does not exist as clean
qet.checkContinuity() answers a folio index it has no folio for with an
empty list, so qet_continuity returned "0 findings" for it -- the same
answer as a clean folio. The index counts from 0 while qet_elements numbers
folios from 1, so passing the last folio's number checked nothing and said
so cleanly; any other folio's number checked the next folio instead.

An index with no folio is now refused before QElectroTech is launched, with
the valid range and the counting rule. Each finding also carries
folio_number (counted from 1) beside the existing folio index. The
qet_continuity and qet_conductors descriptions and the README say how each
tool counts. Nothing changes for a valid index.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 11:58:05 +13:00
ispyisail f5b644918b Merge pull request #1090 from ispyisail/fix/qet-mcp-diff-empty-info
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 2m12s
Fix qet_diff reporting untouched symbols as changed after a re-save
2026-09-28 11:54:13 +13:00
ispyisail 228e696b65 Merge pull request #1091 from ispyisail/fix/qet-mcp-edit-folio-hint
Fix qet_edit giving no clue when a folio number is off by one
2026-09-28 11:53:42 +13:00
ispyisail 9b09469a53 Adapt only element icons in the shortcut bar editor, not its commands
The editor's bar row and command list mix element previews with command
icons. The command icons already follow the palette through the qet-dark
icon theme, and running them through ElementPreviewDelegate again
flattened them to one lightness (up to 16/255 per pixel off master; a
two-tone icon would have had its tones swapped).

Adapt the element icons once, where the items are built, instead of
installing the delegate on those lists. This also covers an element
dragged from the element list onto the bar, which copies the item's icon
and so previously kept the dark one until the editor was reopened.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 11:53:13 +13:00
ispyisail c7f4a4f01d Show element icons light on a dark palette in search results and the picker
The collection tree draws element previews through ElementPreviewDelegate,
which inverts the black line art on a dark palette. The ranked search list
(#1051) and the Insert element picker (#1052) are separate views and never
installed it, so their icons stayed black on a dark background.

Install the delegate on the ranked list, the picker's list and the shortcut
bar editor's lists, and adapt the pinned-element buttons' icons directly.
Coloured icons and light palettes are unchanged.

Reported in #1083.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 11:30:08 +13:00
ispyisail 5da0b92001 qet-mcp: say which folio index to use when qet_edit is given the wrong one
qet_elements and qet_project_info number folios from 1, as the application
does; qet_edit passes "folio" straight to the scripting API, which counts
from 0. Using the number qet_elements showed addresses the next folio, and
the op fails with nothing but "returned False".

Nothing changes for a call that works. When an op fails and the element it
names is in the project on another folio, the hint now says which index to
use. The qet_edit description and the README say how folios are counted.
Counting from 1 instead was not done: it would silently move every existing
caller's edits to another folio.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 11:20:04 +13:00
ispyisail 40ed284b7a qet-mcp: qet_diff no longer reports untouched elements as changed
QElectroTech writes an empty label as an empty <elementInformation> and
drops it on the next save. qet_diff compared the raw information bags, so
re-saving grafcet.qet with no edit reported 9 of its 37 elements as
info_changed ({"label": ""} -> {}), and Projet_vierge.qet 4.

An empty field and a missing one now compare equal, and info_changed lists
only fields that hold a value. The resave test now also requires an empty
info_changed; it failed on grafcet.qet and Projet_vierge.qet before this
change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 11:12:25 +13:00
ispyisail 91804d5f5e Align: a group reduced to one shape lines up on its own centre
A group whose only unlocked member is a shape (its other members
locked) kept a centre of (0,0), so Centrer horizontalement and
Centrer verticalement pulled every item toward the folio origin and
the shape itself landed off the line. The rule that turns a group's
members into one item now lives in Alignment::combined(), where every
member, shapes included, brings its own centre, and tst_alignment
covers it.

Also comments why unitFor()'s returned reference is safe, as asked in
the review of #1087.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG
2026-09-28 09:19:59 +13:00
Laurent Trinques 37674d836f Merge pull request #1087 from ispyisail/feat/1069-align
Add Align left/centre/right/top/middle/bottom for the selection
2026-09-27 21:52:56 +02:00
Laurent Trinques 5cb97f1c89 Merge pull request #1085 from ispyisail/fix/1080-parseoption-qt65
Fix the build on Qt older than 6.5 (#1080)
2026-09-27 21:46:11 +02:00
Laurent Trinques 40f0235c71 Merge pull request #1088 from Kellermorph/materiallist
Add a material list lookup for the element article fields
2026-09-27 21:43:52 +02:00
Laurent Trinques b2f9ed952d Merge pull request #1086 from ispyisail/fix/nokde-kcolorbutton-include
Fix the build without KDE Frameworks (conductor properties panel)
2026-09-27 21:33:10 +02:00
Kellermorph d5ae15f568 Add a material list lookup for the element article fields
The element description dialog only offered typing, so every article of
a catalogue had to be copied in by hand into the Artikelbeschreibung
row of each block, over and over.

Settings > General now keeps the path of a CSV material list (Créer...
writes a template with the header lines), and the Artikelbeschreibung
row of every block of the Bauteil dialog shows a "..." button opening a
searchable listing of that file. "Appliquer" fills the fields of that
block only -- the main block gets everything but label and formula, an
auxiliary block gets description, number, manufacturer, references,
supplier, quantity, unit and additional info -- and a cell that is
empty in the file never erases a value already in the element. The
symbol editor is left alone.

- sources/materiallist/: CSV reading and writing (UTF-8 BOM, ';', every
  field quoted, atomic write through QSaveFile), two header lines
  (translated labels then the canonical English keys), the selection
  window and the new entry form.
- The selection window reads the file again every time it opens, keeps
  its size, column widths, column order and sort between openings,
  shows every column of the file, scrolls all four directions with the
  wheel (Shift + wheel moves the columns) and puts back the order of
  the file when the corner above the row numbers or a row number is
  clicked.
- German translations for the new strings in lang/qet_de.ts.
2026-09-27 21:18:54 +02:00
ispyisail ad88505f87 Fix the build without KDE Frameworks (conductor properties panel)
conductorpropertieseditorwidget.cpp, from the #500 work, included
<KColorButton> unconditionally, so a build with BUILD_WITH_KF=OFF stopped
at "KColorButton: No such file or directory". Include the nokde stand-in
there instead, as dynamictextfieldeditor.h and terminaleditor.h do. It
has the same changed() signal the file connects to.

Checked on Ubuntu 22.04 (Qt 6.2.4, BUILD_WITH_KF=OFF): the file fails on
master and compiles with this change; together with #1085 the whole tree
builds and links. Builds with KDE Frameworks compile the same line as
before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG
2026-09-28 07:59:41 +13:00
ispyisail c29d4aff24 Fix the build on Qt older than 6.5 (#1080)
QDomDocument::ParseOption::PreserveSpacingOnlyNodes, used since 84add7b3e
to keep a title-block variable set to a single space through a reload,
only exists from Qt 6.5. On older Qt the project file is parsed as it was
before that commit: the build works again, and such a value reloads as
empty there.

Checked on Ubuntu 22.04's Qt 6.2.4: qetproject.cpp fails on master with
"'QDomDocument::ParseOption' has not been declared" and compiles with
this change. On Qt 6.5 and later the code is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG
2026-09-28 07:57:21 +13:00
ispyisail 3c4d23bb4e Add Align left/centre/right/top/middle/bottom for the selected items
Edit > Aligner gains six commands, also in the selection's context menu
and the command search: Aligner à gauche, Centrer horizontalement,
Aligner à droite, Aligner en haut, Centrer verticalement, Aligner en bas.
One undo step; wires follow their symbols. Second stage of discussion
#1069, on top of "Aligner sur la grille".

Left/right/top/bottom line the edges up on the outermost one. The two
centre commands line the items up on the mean of their centres, and a
symbol's centre is its origin point, not the middle of its drawing: in
the collection, vertical two-terminal symbols almost always have their
terminals on the origin's axis, so this puts their wires on one line.
A picture is aligned by the picture itself, without its caption
(imageRect() becomes public for this).

A group (#1070) lines up as one piece: its edges are its members'
together, and every member moves by the same amount, so the group keeps
its shape; shapes inside a group come along.

Each item moves only across the line it is aligned on, and lands on the
grid its drag uses, so aligning never takes a symbol off the grid. Two
symbols whose edges sit at different distances from their origins
cannot both be exactly on the line and on the grid; they end up within
half a grid step of it.

The commands need two items (Aligner sur la grille still needs one).
Locked items stay put and the status bar says so. If nothing moves, no
undo step is pushed and the status bar says the selection is already
aligned as far as the grid allows. The geometry is in alignment.h,
tested by tst_alignment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 07:52:17 +13:00
Laurent Trinques 1331ed6677 Merge pull request #1079 from ispyisail/feat/1071-dxf-layers
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 2m1s
Put the DXF export on named layers
2026-09-27 20:25:43 +02:00
ispyisail ae400d4da6 Merge master into feat/1071-dxf-layers 2026-09-28 07:22:42 +13:00
Laurent Trinques 7fdd4417a4 Merge pull request #1074 from ispyisail/feat/1070-item-groups
Add Group and Ungroup for items on a folio
2026-09-27 20:15:37 +02:00
Laurent Trinques 6637127910 Merge branch 'master' into feat/1070-item-groups 2026-09-27 20:15:27 +02:00