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.
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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
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.
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
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
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>