Commit Graph

10691 Commits

Author SHA1 Message Date
Laurent Trinques 015811d243 Terminal strip editor: add spare terminals, numbered, counted in the nomenclature
A spare (reserved) terminal is a terminal of a strip which is drawn on no
folio. RealTerminal already foresaw it ("a terminal set by user but not
present on any folio") but every terminal needed an element.

- RealTerminal::createSpare(): a terminal without element, with its own
  data (label, type, function, led, informations: section, width, catalog
  terminal, color, manufacturer...). Saved in the strip:
  <real_terminal spare_uuid="..." type="..." function="..."><informations>
  Older versions ignore these terminals.
- TerminalStrip::insertSpareTerminals() / insertTerminals(): insert at a
  position of the strip. Undoable commands AddSpareTerminalsCommand and
  ChangeSpareTerminalDataCommand.
- Terminal strip editor: "Add spare terminals..." button. The terminals
  are inserted after the selected terminal (at the end if none), numbered
  from its label ("X1:12" -> "X1:13", "X1:14", leading zeros kept), with
  its properties if asked. The labels can be changed or removed in the
  table, like the other cells; the Xref column shows "Spare". Moving a
  spare terminal to the independent terminals removes it (undoable).
- Nomenclature: the spare terminals are in the new spare_terminal table,
  added to element_nomenclature_view (UNION ALL, same columns), after the
  folios, in the order of their strip. exclude_from_bom is honoured.
- The modified cells of the editor model are kept by real terminal, not by
  element, since a spare terminal has none.
2026-10-18 16:34:41 +02:00
Laurent Trinques ddc71553e2 Terminal strip item: redraw the strip as soon as it changes
TerminalStripItem was connected to nothing: after applying the terminal
strip editor (width, catalog terminal, color, type...), undo or redo, the
strip drawn on the folio kept its old drawing until something else made
the scene repaint, and its bounding rect was not updated when the width of
the terminals changed.

- TerminalStrip::dataChanged() is emitted when the data of the strip is
  set, and when the data of the element of one of its terminals changes
  (Element::setElementData(), Element::setElementInformations()).
- TerminalStripItem connects to dataChanged(), orderChanged(),
  bridgeChanged() and bridgeColorChanged() of its strip, and updates its
  geometry and redraws itself.
2026-10-18 16:06:59 +02:00
Laurent Trinques cbe41aeebf Previous versions: avoid the trigraph warnings of the file name pattern
The glob "????-??-?? ??-??-??" contains the trigraph "??-", which GCC
reports with -Wtrigraphs (8 warnings). The pattern is now written with
"\?" escapes, in one place; it is the same string.
2026-10-18 16:01:58 +02:00
Laurent Trinques ea2acfcaeb Realistic terminal strip: draw the clamp of the terminal chosen in the catalog
The realistic styles drew every terminal of a strip with the clamp of the
layout (RealisticScrew or RealisticPushIn), whatever terminal was chosen:
a Phoenix Contact ST (spring) was drawn with screws in a screw layout.

Each entry of the terminal catalog now has its clamp: screw (Phoenix
Contact UT, Weidmüller WDU, ABB Entrelec M, Legrand Viking 3), spring
(Phoenix Contact ST) or push-in (WAGO TOPJOB S). A terminal chosen in the
catalog is drawn with its own clamp, the spring-cage ones like the push-in
ones; the clamp of the layout is kept for the other terminals, so a strip
mixing screw and spring terminals is drawn as it is.
2026-10-18 15:48:00 +02:00
Laurent Trinques f7196c48e1 Terminal strip editor: remember the manufacturer filter of each strip
The manufacturer chosen to filter the terminals of the Width column is
stored in the data of the terminal strip (information "manufacturer" of
terminal_strip_data, written only when set), and selected again when the
strip is shown in the editor. Each strip keeps its own manufacturer.
Older versions ignore this information.

TerminalStripEditor::apply() now starts from the current data of the strip
instead of a new TerminalStripData: the uuid of the strip was replaced by
a new one at each apply, and the new information would have been lost.
2026-10-18 15:48:00 +02:00
Laurent Trinques 851ddfad16 Terminal catalog: remember the chosen terminal, not only its width
Several terminals of the catalog have the same width (6.2 mm: Phoenix
Contact UT 4 and ST 4; 5.2 mm: WAGO 2002 and Phoenix Contact ST 2,5...).
Only the width was stored, so on reopening the first entry with that
width was shown instead of the terminal that was chosen.

- New element information terminal_catalog_entry: the label of the
  terminal chosen in the catalog (e.g. "Phoenix Contact ST 4").
- Choosing a terminal also fills the manufacturer and manufacturer
  reference informations (bill of materials, %{manufacturer_reference}),
  only when they are empty or still hold what the previous catalog entry
  wrote: a value typed by the user is never overwritten.
- Element editor: the manufacturer and the exact terminal are restored on
  reopening. A width typed by hand, or stored before this change, stays a
  plain width instead of taking the first terminal with the same width.
- Terminal strip editor: new "Manufacturer" combo filtering the terminals
  proposed in the Width column (with the section filter); the column shows
  "6,2 - Phoenix Contact ST 4", and copy/paste keeps the terminal.

Existing projects are unchanged: without the new information, only the
width is used, as before.
2026-10-18 15:48:00 +02:00
Laurent Trinques 41339869a6 Add Traditional Chinese (zh_TW) translation, draft converted from qet_zh.ts with OpenCC s2twp, to be reviewed 2026-10-18 15:07:11 +02:00
plc-user 3a92ec3fb1 PartArc: normalize start and span to have posive values in element-file 2026-10-18 15:01:21 +02:00
ispyisail b473a07b7d Save a symbol's links from the project database
A symbol's <links_uuids> are now what the project database's link rows
list for it, in their order (projectDataBase::savedLinks()), instead of
a list the save built itself from the symbol's partners: QETZ-DB-FIRST
stage 2a, the save reads links from the database. A symbol the database
does not hold (saved outside a project) still lists them itself.

The rows leave out a partner the project no longer has, so removing a
folio with every folio built no longer saves links to its symbols, as
lazy folios already did (the links part of F113). Every other save is
unchanged.

tst_resaveunchanged removedFolioLeavesNoLinkToIt: affuteuse_250h with
every folio built, folio 3 removed: 4 links named symbols no longer in
the file, none now.

Needs #1522 (each symbol its own uuid) and #1523 (rows in saved order);
local only until both are merged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XCdg2Er2vYhB8Vwa5G7fSR
2026-10-19 01:50:35 +13:00
Laurent Trinques a98f8e33be Merge pull request #1530 from DaTweety/fix/continuity-cable-cores
Continuity check: conductors in different cables are no divergence
2026-10-18 14:45:26 +02:00
hairykiwi 959695ed5c Add regression test for elements-panel project-open auto-select crash
- tst_elementspanelprojectopen drives ElementsPanel::projectWasOpened() --
  the slot the application connects to a project being opened -- on a fresh
  panel whose first reload() has not run, reproducing the detached-item
  ordering deterministically offscreen.
- On master without the guard the test fails: the auto-select leaves
  currentItem() pointing at an item whose treeWidget() is not the panel (and
  on some builds crashes in QTreeModel). With the guard it passes: no item is
  selected while the project is detached.
- Registered via qet_add_app_test(), which links the application code and
  runs a real QETApp offscreen.

Generated-by: Claude Code
Signed-off-by: hairykiwi <174199+hairykiwi@users.noreply.github.com>
2026-10-18 13:44:35 +01:00
hairykiwi 64869810cd Guard elements-panel project-open auto-select against a detached item
- ElementsPanel::addProject auto-selects the first diagram via
  setCurrentItem(qtwi_project->child(0)). When a project is opened before
  the panel's first reload() has created its title-block collection items,
  indexOfTopLevelItem(common_tbt_collection_item_) returns -1 and the
  preceding insertChild() leaves qtwi_project detached from the tree model.
- The unguarded auto-select leaves a detached/invalid current item -- an
  intermittent SIGSEGV in QTreeModel::index()/parent() on some builds; on
  current master with Qt 6.11.2 the test shows the invalid selection without
  a fault. Calling setCurrentItem() on an item the QTreeModel does not own is
  unsafe; guard the auto-select with qtwi_project->treeWidget() so it runs
  only when the item is attached.
- No behavioural change in the normal case: reload() re-adds the project
  attached shortly after and performs the selection then.
- Pre-existing since a82f6de23 ("Add highlight current page in ProjectView").

Assisted-by: Claude Code
Signed-off-by: hairykiwi <174199+hairykiwi@users.noreply.github.com>
2026-10-18 13:44:35 +01:00
Laurent Trinques 3b517d31c0 Merge pull request #1527 from DaTweety/feature/terminal-catalog-phoenix-st
Terminal catalog: add the Phoenix Contact ST spring-cage terminals
2026-10-18 13:56:20 +02:00
ispyisail 89c3979957 Fix Save writing a .qetz beside an opened .qet: keep the .qet
A project opened from a .qet was saved as a .qetz beside it, with a
notice, and the .qet left as it was: a project kept in git did not stay
a .qet. Save now writes the format the project was opened in; only Save
As changes it (scorpio810, discussion #1512). A .qetz is saved as a
.qetz as before.

The save-beside path goes: the flag set on opening, the .qetz path made
from the .qet's, write()'s switch to it and back on failure, and the
notice and replace question in ProjectView::doSave().

tst_resaveunchanged::qetSavedAsQetzBeside becomes qetSavedAsQet: Save of
an opened .qet writes no .qetz and the .qet holds what a plain save of
it holds (it fails without the fix: a .qetz is written beside).
tst_changedondisk makes its .qetz with Save As, as Save no longer does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 22:56:22 +13:00
DaTweety f325b8001e qet-mcp: count duplicate labels per plant and location
qet_check reported -F1 as a duplicate master when one sits in +UV1 and one
in +UV2, although they are two devices: the place is part of the name, as
the %M/%LM label formulas show it and as IEC 81346 tools treat it. Group
the two duplicate-label checks by label and the effective place, the
element's own plant/location or else its folio's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 11:47:49 +02:00
DaTweety 1ff2fa5dcf qet MCP: keep the edit script's report lines when cutting long output
_run_qet() kept only the last 400 000 characters of a run's output. A
large qet_edit (a whole multi-folio drawing in one call, some 2000 ops)
logs more than that, and the cut took the capability report the script
makes first: the tool then answered "the binary never ran the script"
although QElectroTech had run it and saved the result.

Lines the script reports through its marker are now kept whole wherever
they stand; only the other output is cut to the tail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 11:47:49 +02:00
DaTweety 7d966a0ed4 Show the logo in the Linux system tray
The tray icon was QET::Icons::QETLogo, which comes from QElectroTech's
own icon theme bundled in its resources and so carries the theme name
"qet". On Linux Qt's StatusNotifierItem then sends only that name, and
the panel -- another process, without those resources -- cannot resolve
it: KDE Plasma showed an empty slot. Seen on D-Bus as IconName "qet"
and no IconPixmap.

The tray now gets an icon made of the logo's pixmaps only (16 to
256 px), which the tray sends as pixels. Checked on Plasma: IconName
is empty and IconPixmap carries the eight sizes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 11:47:49 +02:00
DaTweety a8463288aa Continuity check: conductors in different cables are no divergence
checkContinuity() reported potential_mismatch on "cable" whenever the
conductors of one potential ran in different cables. A conductor held
by a cable carries its own core's label in the cable field (15W1:BN,
written by CableManager); a potential spread over several cables is the
normal case, e.g. a neutral fed from a terminal strip into each room.
On a house installation every N and PE potential was flagged.

Conductors held by a cable are left out of the cable comparison; the
free-text cable field of other conductors is still compared.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 11:47:49 +02:00
DaTweety 83607c0b76 Terminal catalog: add the Phoenix Contact ST spring-cage terminals
ST 1,5 (4.2 mm, 1.5 mm²), ST 2,5 and ST 2,5-QUATTRO (5.2 mm, 2.5 mm²)
and ST 4 (6.2 mm, 4 mm²), next to the UT screw terminals already listed.
Widths from the Phoenix Contact catalog and data sheets (ST 2,5-QUATTRO
3031306, ST 4 3037151, ST 1,5 3031076).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 11:47:49 +02:00
DaTweety 04716b0731 Scripting and qet MCP: draw a cable across conductors
qet.addCable(folio, designation, type, coreColors, length, x1, y1, x2, y2)
does what the cable tool does after its dialog: a new cable whose trunk
is the line between the two points, every conductor the line crosses
taking the next core in order along the line, with the colour coreColors
lists at that place. One undo step, through AddCableCommand. An empty
designation takes the next free name. A conductor another cable already
holds is refused rather than taken away, since a script cannot be asked
the question the dialog asks. qet.cables() lists the project's cables.

The qet MCP server gains the add_cable op for qet_edit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 11:47:48 +02:00
DaTweety ff65b85357 Report composite texts: element information and the partner's label
A folio report whose text is a composite text replaced only %{label}
and the conductor variables. The report's own information is now
replaced as well, as on any other element, so a report can name the
device and terminal it leads to: "%{comment} %{label}" reads
"-XS27:N +UV1/2 UG Raum - 1.1" like EPLAN's interruption points.

Changing a report's information rebuilt such a text the way an ordinary
element's is built, turning %{label} into the report's stored label,
where its partner was when last saved. It now takes the same text
updateReportText() builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 11:47:48 +02:00
DaTweety 1080188f6e Add %T, the target folio's title, to report and cross reference formulas
A folio report could name the folio it points to by position (%f), folio
number (%F), installation (%M) and location (%LM), but not by its title.
EPLAN and other tools print references like "+UV1/1 Versorgung UG/EG.0",
which with %T is the formula "+%LM/%F %T.%c".

- FormulaContext carries the folio title, filled from the title block.
- %T is replaced on its own only, not as the start of a longer word.
- A report whose formula uses %T follows the target folio's title block
  (BorderTitleBlock::informationChanged), as %F already follows its
  folio number.
- The report and cross reference property pages list %T.

tst_reportfoliotitle checks the replacement, that %total and title
block variables keep their values, and an empty title.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 11:47:48 +02:00
ispyisail 8c5a16d50e Merge pull request #1535 from ispyisail/fix/link-rows-test-skip-without-qml
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 1m39s
Fix the Linux CI failing since #1523
2026-10-18 22:31:50 +13:00
ispyisail a715ff25ff Merge pull request #1534 from ispyisail/feat/multi-symbol-info
Add editing the information of several symbols at once (#1439)
2026-10-18 22:31:36 +13:00
ispyisail b393e8a133 Merge pull request #1533 from ispyisail/fix/selection-panel-height
Fix the Selection properties panel losing the height the user gave it
2026-10-18 22:31:13 +13:00
ispyisail ff1a81d85d Fix the Selection properties panel losing the height the user gave it
The panel shrank to its title bar whenever the selection had nothing it
could edit (a click on an empty spot, several elements, a mix of items):
its content layout used QLayout::SetMaximumSize, and an empty vertical
layout's maximum height is 0. The other right-hand panels took the room,
and when an element was selected again the panels were split again from
their size hints, so the height the user had dragged the panel to was
lost (reported by ankostis in #1439).

With the default size constraint the panel keeps its height and stays
blank while there is nothing to edit. The element, wire, text and shape
editors draw the same: their screenshots in a 730-860 px tall panel are
pixel-identical before and after.

Test: tst_selectionpanelheight (on master the height goes from 560 to
19 px).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 22:29:54 +13:00
DaTweety a0e2193971 Joining potentials: agreeing ones leave nothing to choose
ConductorCreator asked which potential's properties to keep whenever a
new wire joined two potentials, even when they agreed in every
property; headless (scripting, qet MCP) such a wire was refused. Only
distinct properties are offered now, and with one left the wire takes it.

A potential's properties seen through one of a cable's cores carried
the core with them -- cable, cable uuid, core slot, and the core label
CableManager writes as text -- so a new wire claimed to be that core.
They are cleared; the text is left to the formula.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 11:21:09 +02:00
DaTweety fa498a3d20 A new wire takes the potential of a terminal it reaches through another
ConductorCreator::existingPotential() looked for an existing potential
only at the terminals being wired and, for a report, at its partner's
first conductor. A wire drawn to the free side of a terminal element
whose other side is wired, or to the far side of such a chain, found
none and got the folio's default properties: the neutral after a
terminal strip came out solid and unnumbered while relatedPotentialConductors()
counts it as part of the dashed, numbered N potential.

Each terminal is now followed through relatedPotentialTerminal() -- the
rule relatedPotentialConductors() applies -- until a wired terminal is
found, and two terminals on one potential count once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 11:10:10 +02:00
ispyisail 389dae2079 Merge pull request #1521 from ispyisail/fix/joined-wire-uuid
Fix a deleted symbol's joining wire getting a random uuid on every run
2026-10-18 21:54:26 +13:00
ispyisail e46492d575 Merge pull request #1524 from ispyisail/fix/1495-element-editor-zoom-content
Fix #1495: show the symbol editor's fit button as Zoom content
2026-10-18 21:53:54 +13:00
ispyisail e05b511cb2 Tests: skip linkRowsAfterLazyEdit on a build without --run
linkRowsAfterLazyEdit() (#1523) edits a project through --run, which a
QElectroTech built without Qt Qml does not have. The Linux CI builds it
that way, so the test has failed there since #1523 merged, on master
(e46bb97c5) and on every pull request after it: "MOVED true" is never
printed. It now skips, as the five other --run tests of
tst_resaveunchanged do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 21:51:25 +13:00
ispyisail ce0798bb18 Add editing the information of several elements at once (#1439)
Selecting several elements left the Selection properties panel blank and
Edit (Ctrl+E) disabled, so giving many elements the same supplier or
manufacturer meant editing them one by one.

The panel now shows the Information fields for two or more elements, or
for elements selected with other items (left unchanged, and counted in
the panel's header). Ctrl+E opens the same editor as a dialog when only
elements are selected.

- A field shows the value every element shares, or "Multiple values".
  Left alone, each element keeps its own value; typed text goes to every
  element; the erase box clears the field on every element.
- A restore button per field, and Reset, bring back the values the
  elements had.
- One apply is one undo step. The keystrokes typed in the panel merge
  into one step but never into an earlier change of the same elements
  (a paste of element information, another edit).
- Numbering scheme, label freezing and the number picker are left out:
  they are about one element. Custom properties are kept as they are.

Also:
- An element's own texts, selected with it by Select all, count as part
  of the element, not as other items.
- ElementInfoWidget::reset(): Reset in the element dialog now brings back
  the Information tab's values; it did nothing.
- The panel opens an element's editor on the tab picked last, instead of
  the first tab, after the selection went to something else and back.

Test: tst_multielementinfo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 21:44:00 +13:00
ispyisail 8db65ddaeb Merge master into fix/joined-wire-uuid
The conflict was tests/qttest/CMakeLists.txt, where #1520 added
tst_savedstamps at the place this branch adds tst_joinedwireuuid. Both
are kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 20:50:24 +13:00
ispyisail 1b54155cf9 Show the symbol editor's fit button as Zoom content (#1495)
The symbol editor has no sheet to fit: its "Fit in view" action zooms on
the drawn parts (elementSceneGeometricRect()), which is what the folio
editor calls "Zoom content". Use that command's zoom-draw icon and name,
and give the action a status tip like the folio editor's.

The object name and the shortcut id stay the same, so saved shortcuts
and toolbar layouts keep working.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 20:17:14 +13:00
ispyisail e46bb97c5b Merge pull request #1523 from ispyisail/refactor/link-rows-in-place
Fix the project database listing a symbol's links in another order than its file
2026-10-18 19:53:12 +13:00
ispyisail 5cba4dd7d7 Merge pull request #1522 from ispyisail/fix/shared-symbol-uuid-renew
Fix symbols sharing a uuid: give each copy its own when a project opens
2026-10-18 19:52:54 +13:00
ispyisail b36d9fc9a9 Merge pull request #1518 from ispyisail/fix/windows-test-failures
Fix the two tests that fail on Windows CI
2026-10-18 19:52:27 +13:00
ispyisail ee2a060b16 Write a symbol's link rows in the order it saves them, with its waiting partners
The project database's link table should say what each symbol saves:
QETZ-DB-FIRST stage 2a moves link reading and writing to it. Measured over
the corpus and 25 kinds of edit, its rows disagreed with the file for
three reasons; this fixes the one in the database:

- rows followed the order partners were built in, not the order the
  symbol saves them (11 symbols, mostly .qetz files where an edit built a
  partner's folio, with lazy folios);
- the rows were written by three pieces of code with three rules: the
  rebuild and the flush from the built partners then the waiting ones,
  the save from its own list.

Element::linksToSave() is now that one list: the order the symbol was
saved with, then partners linked since, a partner on a folio not built
included. toXml() writes it and the database's rows are written from it
(projectDataBase::insertLinkRows()), with their place in a new ord
column of the in-memory table (the .qetz file's own link table is not
touched). A built partner the project no longer has, on a removed folio,
still gets no row, as before.

The other two reasons are not here: symbols sharing a uuid (PR #1522)
and links saved to symbols on a removed folio (F113), which the save will
stop writing once it writes from the database (stage 2a-2).

QET_CHECK_LINK_ROWS=1 says at each save whether the rows are what the
symbols save, without building any folio. tst_resaveunchanged
linkRowsAfterLazyEdit moves a symbol of m_000 as a .qetz with lazy
folios: with the previous order, 2 symbols differ.

No saved byte changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XCdg2Er2vYhB8Vwa5G7fSR
2026-10-18 16:35:58 +13:00
ispyisail 1c0deb2bc8 Give each copy of a symbol sharing a uuid its own uuid when a project opens
Older versions' copy and paste could leave two symbols with the same
uuid. Wires, links and the project database name a symbol by its uuid,
so a copy was ambiguous: #1417 worked around it for wires, but the
project database keeps one row per uuid, and a link to the uuid could
mean either copy.

When a project opens, every symbol carrying a uuid another symbol also
carries gets a uuid of its own, derived from the shared one and its
folio's uuid, so the same file gives the same result on every open. The
copy that keeps the shared uuid is the first one linked to another
symbol (its partner's link names that uuid), else the first. It is done
once the folio's wires are connected, so #1417's choice of which copy a
wire meets is kept. Folios holding such a copy are built when the
project opens, also with lazy folios.

Only files with shared uuids change, once: 3 of the 341 corpus projects.

tst_sharedsymboluuid: the lamps given one uuid now come back with three;
a linked contact and an unlinked symbol sharing its uuid keep every link
and wire, the linked one keeping the uuid. Both fail without the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XCdg2Er2vYhB8Vwa5G7fSR
2026-10-18 15:01:26 +13:00
ispyisail abd1c8df2f Merge pull request #1520 from ispyisail/fix/stable-saved-stamps
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 1m52s
Fix the saved date and time lagging one save in the title block
2026-10-18 13:33:34 +13:00
ispyisail f49abcc6cc Fix a deleted symbol's joining wire getting a random uuid on every run
Deleting a symbol whose terminal held several wires joins the wires
left behind with a new one. That wire got a random uuid, so the same
deletion saved a different file every time: a diff for nothing in a
project kept in git (discussion #1512), and two copies with the same
edit could not be compared.

Its uuid now comes from its two ends (each end's symbol and terminal,
sorted), the recipe a wire saved without a uuid already gets on load
(Diagram::fromXml(), derivedItemUuid()). Undo and redo keep the same
wire, so its uuid too.

tst_joinedwireuuid deletes the coil KA1 of examples/affuteuse_250h.qet
in two runs: both saves are identical and no wire has a random uuid.
Without the fix one wire has a random uuid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XCdg2Er2vYhB8Vwa5G7fSR
2026-10-18 10:51:16 +13:00
ispyisail ea9da9b2c8 Fix the saved date and time lagging one save in the title block
The title block variables of a save (saveddate, saveddate-eu,
saveddate-us, savedtime, savedfilename, savedfilepath) were set after
the file was written, and also when a project was opened. A file
therefore held the previous save's date and path: after editing and
saving, the title block showed the date of the save before. And every
save but the first in a session wrote the time of the one before, so a
project saved twice without a change gave two different files, a diff
for nothing in a project kept in git (discussion #1512).

stampSaved() now sets them before writing, when the project has
unsaved changes (the modified flag or the undo stack moved since the
last save, as the window's "[modified]" uses) or is written to another
file. Otherwise they keep what the file holds, and opening a project no
longer sets them.

tst_savedstamps: an unchanged project saved twice in place is
byte-identical; a moved symbol then a save gives today's date and the
file's own path. Both fail without the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XCdg2Er2vYhB8Vwa5G7fSR
2026-10-18 10:51:16 +13:00
ispyisail 3c40bf5bd1 Tests: fix the two tests that fail on Windows
Windows CI stopped running tests (bdd3b2050) after these two failed:

- tst_reporttextafterinfo wrote "columns numbered from 1" to a .conf
  under XDG_CONFIG_HOME, which only Linux reads. On Windows the setting
  stayed in the registry, columns counted from 0 and the report read
  1-C8. The setting now goes to an INI file QET_SETTINGS_DIR points at
  (#1178), read on every system.
- tst_projectlock::readOnlyFolderDoesNotBlock relies on a read-only
  folder refusing new files. Windows ignores that flag on folders, so
  the lock was taken; the case is skipped there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 10:06:15 +13:00
ispyisail 732017b015 Merge pull request #1517 from ispyisail/fix/apptest-standardpaths-testmode
Fix app tests hanging on an autosave and rewriting the user's files
2026-10-18 10:02:27 +13:00
ispyisail eccf11d792 Merge pull request #1516 from ispyisail/fix/terminal-orientation-empty
Fix a crash opening a project whose symbol has a terminal with no orientation
2026-10-18 10:01:47 +13:00
ispyisail ea0d86e8f4 Merge master (0b0c20fdb: realistic drawer in the CMake sources) into fix/terminal-orientation-empty
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XCdg2Er2vYhB8Vwa5G7fSR
2026-10-18 09:01:04 +13:00
ispyisail 0a0809d7f4 Tests: keep every app test out of the user's standard folders
QetAppTest::run() moved settings, configuration and data into a
temporary folder, but QStandardPaths still pointed at the user's own.
Two things follow on a developer's machine:

- qet-assistant.json, live-mode token included, is rewritten by every
  app test as its editor opens.
- A .qetautosave file left in the user's data folder makes QETApp offer
  to restore it in a modal dialog at start. Offscreen nobody answers,
  so all six app tests hang until ctest times them out.

Test mode is now enabled first thing in run(). tst_assistantinfopaths
(#1513) did this in its own main(); it goes back to QET_APP_TEST_MAIN.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 08:33:17 +13:00
Laurent Trinques 0b0c20fdb5 Terminal strip: add the realistic drawer to the CMake sources 2026-10-17 21:32:12 +02:00
ispyisail 108f49443d Merge pull request #1513 from DaTweety/fix/assistant-info-collection-paths
Write qet-assistant.json after the settings dialog applies the paths
2026-10-18 08:25:51 +13:00
ispyisail ae151b350a Fix a crash opening a project whose symbol has a terminal with no orientation
A terminal in a symbol's definition saved without its orientation
attribute crashed QElectroTech whenever the project was opened, in the
GUI and with --resave alike: Qet::orientationFromString() read the
first character of an empty string. Hand-edited or generated symbols,
or a damaged file, can hold such a terminal.

An empty string is now an inconsistency like any other, and the terminal
faces north, as the function's comment already said. Every non-empty
string gives the same orientation as before.

tst_terminalnoorientation runs the real binary's --resave on
fixtures/terminal_no_orientation.qet (unlinked_contact_label.qet with one
terminal's orientation removed): it crashes without the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XCdg2Er2vYhB8Vwa5G7fSR
2026-10-18 08:04:13 +13:00