Commit Graph

4711 Commits

Author SHA1 Message Date
ispyisail b1247d4bb0 Merge pull request #1317 from ispyisail/fix/pdf-trailer-startxref
Fix repeatable PDF changing with the output folder (#1178)
2026-10-05 22:15:39 +13:00
ispyisail 16173c2070 Merge pull request #1316 from ispyisail/perf/live-timing
Add an optional timing log for live mode
2026-10-05 22:14:50 +13:00
ispyisail 97e81f7ebf Merge pull request #1314 from ispyisail/feature/live-remember
Remember live mode's start warning and "Always" across restarts
2026-10-05 22:14:31 +13:00
ispyisail 527b0f3b2d Fix repeatable PDF changing with the output folder (#1178)
Rewriting the links copied the old trailer up to %%EOF, so the old
startxref stayed in the file before the new one. Its offset is the size
the file had before the rewrite, and the links carry the output path,
so the same project exported to two folders gave different bytes, and
a different document id. Both rewrites now copy the trailer dictionary
only, through one helper; the print window's rewrite no longer leaves a
stray %%EOF either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 21:43:28 +13:00
ispyisail db9ba6c1ca Merge remote-tracking branch 'upstream/master' into perf/live-timing
# Conflicts:
#	sources/scripting/liveserver.cpp
2026-10-05 21:36:17 +13:00
ispyisail 7ddf2ca14f Merge remote-tracking branch 'upstream/master' into feature/assistant-house-style
# Conflicts:
#	misc/qet-mcp/README.md
#	misc/qet-mcp/qet_mcp.py
2026-10-05 21:36:08 +13:00
ispyisail 33f7d27388 Merge remote-tracking branch 'upstream/master' into feature/live-remember
# Conflicts:
#	lang/qet_en.ts
2026-10-05 21:35:52 +13:00
ispyisail 32f7b94594 Merge pull request #1313 from ispyisail/feature/live-tools
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 1m50s
Add printing, save/close and a layout check to live mode
2026-10-05 21:33:18 +13:00
ispyisail dccde2b8c8 Merge pull request #1312 from ispyisail/feature/live-new-project
Add live-mode commands to create, open and switch projects
2026-10-05 21:32:59 +13:00
ispyisail 36d574179b Assistant house style: rewrite qet-assistant.json when the style changes
qet.setHouseStyle() only saved the setting, so an assistant reading
qet-assistant.json saw the old text until QElectroTech restarted.
AssistantInfo::refresh() writes the file again, but only in a
QElectroTech that writes it at all: a headless --run would otherwise
replace the open QElectroTech's live channel with its own empty one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 20:34:57 +13:00
ispyisail 44dfb9d8d5 Assistant house style: a drawing-convention text every AI assistant reads
QetSettings::houseStyle()/setHouseStyle() (assistant/house_style),
qet.houseStyle()/qet.setHouseStyle() in the script API, a house_style
field in qet-assistant.json, and qet_about in the qet MCP server
showing it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 20:34:56 +13:00
ispyisail 0bb0ea225f Live mode print: draw at 96 dpi, as the PDF export does
At the printer's own resolution (600-1200 dpi) symbols and texts were
replayed many times too big next to the wires and grid. Seen on a test
print to PDF; the same page now matches qet_export's PDF.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 20:34:14 +13:00
ispyisail 0df8ca5b3c Live mode: print, save/close, changes, snapshot; house-style layout rules; saved symbol index
QElectroTech (LiveServer):
- print: folios to the default (or a named) printer with no print dialog,
  always after asking the user (paper cannot be undone); or to a new PDF
  file. Rendered as the PDF export draws a folio (no grid, no terminals).
- save_project (own file, or save as a new file, never over one) and
  close_project (only without unsaved changes: never discards work).
- changes: the undo history, each step marked assistant or user, with
  "since" to ask what changed after a point.
- snapshot: a copy of the open project as on screen, for a check to read,
  without saving it or changing its file.
- qet.elementTextGeometry(): where a symbol's text is drawn on the folio.

qet MCP server:
- qet_live_print, qet_live_save_project, qet_live_close_project,
  qet_live_changes, qet_live_layout_check (snapshot + qet_layout_check, no
  "run this script?" window); write paths never overwrite.
- Layout rules from the house style, for file and live checks alike:
  label_on_wire, four_way_junction, misaligned_branch.
- The element index is saved under ~/.cache/qet-mcp: a new server process
  loads 8839 symbols in 0.4 s instead of parsing them for 6.9 s; the
  change check is a third faster.
- qet_about lists the installation's standard symbols
  (standard-symbols.json in QElectroTech's data folder) when there are any.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 20:34:14 +13:00
ispyisail 2fb48e791b Live mode: open_project never stops on the backup question
openAndAddProject() asked "Créer une copie de sauvegarde ?" even when
called non-interactively, so open_project waited for an answer from the
user in front of the window. Only live mode opens projects that way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:15:19 +13:00
ispyisail 550dcdda71 Live mode: remember the start warning and "always" across restarts
Live mode asked at every start (the "Mode direct" warning) and forgot
"always" for scripts when QElectroTech closed, so a user who works
with an assistant every day re-enabled it every day. Both are now
opt-in and remembered: the warning has a "Ne plus demander au
démarrage" checkbox (scripting/live_skip_warning), and the ask-first
choice is saved (scripting/live_ask_first; the Assistant panel's
checkbox and "Toujours" in the script window). The status bar still
shows live mode whenever it is open. Switching live mode off in the
settings clears "don't ask again", so turning it back on warns again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:11:47 +13:00
ispyisail ad20eb94ba Live mode: open a saved project, switch between open projects
open_project opens a .qet and makes it current, as File > Open does but
with no file dialog and no error windows: a missing, unreadable or
foreign file is refused in the answer. A project already open is only
made current. switch_project makes another open project current, by its
index or its file. status now lists every open project (index, title,
file, folios, unsaved changes, current), so the assistant sees what it
can switch to. MCP: qet_live_open_project, qet_live_switch_project; both
paths go through the workspace policy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:00:13 +13:00
ispyisail 42b1e43e4a Live mode: create a new project (new_project, qet_live_new_project)
An assistant in live mode could only work on the project already open.
new_project makes one as File > New does -- this installation's
new-folio defaults, optional title and number of folios -- and makes it
the current project, so the next request works on it. An optional
absolute path saves it at once, never over an existing file: QElectroTech
refuses, and the MCP server refuses before asking (a new never-overwrite
class in its path policy, so an "overwrite" flag cannot get round it).

Pages and links across pages already worked through scripts
(qet.addFolio, setFolioTitle, linkElements across folios); the tool's
description now says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 18:48:38 +13:00
ispyisail e77a175fc9 Live mode: optional timing of each request (QET_LIVE_PERF_LOG)
A request with "timing": true gets queue, confirm and exec times in its
answer; with QET_LIVE_PERF_LOG set, QElectroTech also appends one JSON
line per request, with the time until the folio is next painted. The
qet MCP server logs its side of each live call to the same file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 18:32:42 +13:00
ispyisail b8eb5c90a1 Cross references at the folio bottom: stack only when texts overlap, add a checkbox (#1287 follow-up)
The stacking added in #1287 tested the crosses' bounding rects, so
crosses whose frames or empty margins touched were raised although no
text was hidden (the list display case found in review). The texts each
cross really draws are now recorded while its geometry is built, and a
cross is raised only when one of its texts would be drawn over a text of
another one.

A new "Empiler les références dont les textes se chevauchent" checkbox
in the cross reference properties, per type, turns the stacking off;
the crosses of that type are then only centred, as before #1287. It is
saved in the project (xref attribute "stackoverlapping") and in the
settings, and is on when absent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 17:24:11 +13:00
Jeff Patterson 1dc9c5cc3d Served the app icon from the icon theme in the new element wizard
The qet theme now lists Nuri's app icon PNGs under the name
qelectrotech, and the wizard loads its logo by that name instead of
the 256 px file path. The files stay in ico/breeze-icons/, where the
packaging scripts install them from.

Part of #1269.
2026-10-04 10:16:34 -05:00
Jeff Patterson 20ee3383d3 Sorted the icon folders by source and added ico/README.md
Each folder now holds icons from one source: qet/ for QET's own SVGs,
breeze/ for KDE Breeze (with breeze/added/), flags/, colors/, and
themes/ for script output (with themes/generated/). The unused
128x128/terminalstrip.svg is removed. The generator, qrc files,
qeticons.cpp and ico/copyright follow the new paths. ico/README.md
lists each folder's source, script and license.

Part of #1269.
2026-10-04 07:28:56 -05:00
Laurent Trinques 1c09c4e391 Merge pull request #1282 from arummler/formula-improvements
Auto numeration: a lot of changes for elements, condutors, sheets
2026-10-04 11:52:56 +02:00
Laurent Trinques bbb8e5d2e2 Tested in list display on a real project: neighbouring references on the same row were raised alternately (980 / 927 / 980...) although nothing visibly overlapped.
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 1m52s
Cause: in list mode `drawAsContacts()` adds a margin (`adjust(-30, -4, 4, 4)`) to `boundingRect()`, and the horizontal test in `stackAtBottom()` uses that rect. Two lists overlapping only inside the empty margin (1.4 units in my log) count as overlapping. `gap` only changes how far the raised ones move, not which ones.

Fix: test the content only in list mode (`rect.adjust(30, 0, -4, 0)`), with the two margins as constants shared with `drawAsContacts()`.

Result: all references stay at the bottom (980 -> 980), none raised by mistake, also when moving an element sideways.

Checked: [to complete: same-column coils in list mode still stack, cross mode unchanged]
2026-10-04 09:32:12 +02:00
Laurent Trinques ac2f360910 Merge pull request #1302 from ispyisail/fix/1252-parttext-align-while-typing
Fix #1252: aligned static text drifts while typing in the element editor
2026-10-04 07:38:51 +02:00
Laurent Trinques 7bd9979777 Merge pull request #1303 from ispyisail/fix/text-group-dangling-xref-connection
Fix a crash in Project properties after a text group is deleted
2026-10-04 07:37:27 +02:00
Laurent Trinques faa0ca92a5 Merge pull request #1301 from ispyisail/fix/zoom-content-hidden-items
Fix #1281: Zoom to content includes hidden wire texts
2026-10-04 07:35:52 +02:00
Laurent Trinques 8a275be6da Merge pull request #1299 from ispyisail/fix/1280-junction-dot-potential
Fix #1280: missing junction dot where wires share a line
2026-10-04 07:34:46 +02:00
ispyisail e055438f30 Fix a crash when cross-reference settings change after a text group is deleted
A text group kept at the bottom of the page, on a master element,
connects to its project's XRefPropertiesChanged with a lambda that has
no context object. The connection belongs to the project, so it
outlives the group: once the group is deleted (paste a coil, undo,
then make any other edit), changing a cross-reference setting in the
project properties calls QTimer::singleShot() on the freed group and
QElectroTech crashes.

Pass the group as the context of that connection and of the
linkedElementChanged one beside it, so Qt removes both when the group
goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 14:59:10 +13:00
ispyisail 9d7fac1f53 Element editor: keep a static text's alignment while typing (#1252)
startEdition() records the bounding rect, but the aligned point was only
restored in endEdition(), so a right/centre/bottom-aligned text grew from
its old left/top edge while being typed into and jumped into place when
the edition ended. Re-anchor after every content change during inline
edition.

endEdition() now always clears previous_text, which marks an edition in
progress. It used to stay set after an edition that left the text
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 12:06:55 +13:00
Andre Rummler 8eb2024bb1 Fix jump to element search. 2026-10-04 01:04:44 +02:00
ispyisail cbacd2bb62 Merge pull request #1283 from jp2images/svg-icons-c
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 1m39s
Finish the SVG icons and fix the icon licenses in ico/copyright (#1063, #1269)
2026-10-04 11:45:07 +13:00
ispyisail 2ff0f0d860 Merge pull request #1300 from arummler/fix-qobject
Fix missing Q_OBJECT
2026-10-04 11:44:13 +13:00
ispyisail 6f5db879c1 Zoom to content: count only visible items
itemsBoundingRect() also counts hidden items. The text of a single-line
wire, and the wire texts hidden by "one text per potential", are never
positioned again and can sit far outside the drawing, so Zoom to content
zoomed out to include them. On photovoltaique.qet 14 such texts reach
x = -729 and the zoom covered 2421x924 instead of 1135x648.

Add Diagram::visibleItemsBoundingRect() and use it for Zoom to content,
the scene rect and the borderless export. Zoom to content now goes through
zoomToRect(), which re-centres after the scroll bars appear; before, the
view could stay scrolled to the top-left with part of the content cut off.

Fixes #1281

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 11:23:26 +13:00
Andre Rummler 30281032e4 Fix missing Q_OBJECT. Required to pull declaration into the header. 2026-10-04 00:11:38 +02:00
ispyisail bec0f1c7b4 Fix #1280: junction dot missing where a wire's corner meets a wire it is not wired to
A conductor draws a junction dot at each of its bends that lies on
another conductor. It only looked at the conductors on its own two
terminals, so a bend lying on a conductor of the same potential that
shares no terminal with it got no dot. Dragging the horizontal parts of
a chain of conductors onto one line, as in the report, does exactly that.

Look at every conductor of the potential on the folio instead
(relatedPotentialConductors(false)). The folio scene uses NoIndex, so a
scene lookup at each bend scans every item and made export of the
366-conductor Polonez example 60% slower; walking the potential costs
nothing measurable there (2.08 s vs 2.11 s) or on a 153-conductor
potential (0.97 s both).

The test for one other conductor moves into bendMakesJunction(). It
also stops a point being appended once per matching segment: master drew
the dot above K2 in the fixture ten times.

Across the 23 examples (133 folios) exported to SVG, 6 dots are added,
all at T-joints that had none, and none removed.

tst_junctiondots exports fixtures/junction_dot_shared_potential.qet and
checks for both dots; it fails on master with the dot above K3 missing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 10:57:27 +13:00
ispyisail 69aed0cf84 Merge pull request #1287 from ispyisail/fix/xref-bottom-stack
Fix cross-references printing over each other at the folio bottom (#1178)
2026-10-04 10:55:24 +13:00
ispyisail 30d29b933a Stack cross-references snapped to the bottom of a folio instead of overlapping (#1178)
With "snap to bottom", each master's cross was centred under it at the
bottom of the folio on its own, so two coils in one column drew their
crosses on the same spot and the references printed over each other.

The crosses of a folio are now placed together: when two would overlap,
the one of the higher element goes above the other, so a column of
coils gets its crosses in the same order. Crosses that do not overlap
stay where they were. Moving an element sideways now re-places them
too, since it can move a cross into or out of another's column.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 08:54:13 +13:00
ispyisail ef96b7d948 Give a repeatable PDF the same document id however the project was made (#1178)
With SOURCE_DATE_EPOCH set, the document id came from the project's uuid
and a hash of the .qet file. A project generated again from the same
data has new uuids, so its PDF differed in the id alone (XMP DocumentID
and trailer /ID, 120 bytes) although every page was the same.

Qt now writes a fixed placeholder id, and once the file is written the
placeholder is replaced with an id derived from the bytes of the PDF:
the same pages give the same id. Same length, so no offset changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 08:54:13 +13:00
Jeff Patterson da90cb8452 Served the remaining Breeze icons from ico/breeze and dropped unused icon files (#1269)
The search panel's close button and the five KDE Breeze icons that sat in
ico/breeze-icons/ now come from ico/breeze/, with 16, 22 and 32 px art.
André's three SVGs moved from ico/generated/ to ico/scalable/. Removed the
18 .svgz files and the QETIcon and QETOxygenLogo icons nothing used.
2026-10-03 12:20:38 -05:00
Andre Rummler d76f3528ae AutoNum: a lot of changes
Schemas now get saved with a UUID and do not have to be looked up according to the form. They can be renamed and it gets reflected in existing elements. The GUI for
editing them is now much easier, e.g. forms can be reshuffled. A formula can be applied. Many options now also for conductors and sheets.
2026-10-03 18:09:33 +02:00
Laurent Trinques 3bf1a7b86b Merge pull request #1273 from ispyisail/feature/wires-per-terminal-chains
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 1m48s
Wire terminals in a chain, not a star, under a wire limit
2026-10-03 16:56:02 +02:00
Laurent Trinques 389fd454da Merge pull request #1278 from ispyisail/fix/301-dxf-picture-warning
Fix DXF export warning about pictures hidden by View > Show (#301)
2026-10-03 16:38:42 +02:00
Laurent Trinques dedd3b6d03 Merge pull request #1272 from ispyisail/feature/wires-per-terminal
Add an optional limit on wires per terminal (discussion #1158)
2026-10-03 16:35:10 +02:00
ispyisail 9e3376919c Merge branch 'feature/wires-per-terminal' into feature/wires-per-terminal-chains
# Conflicts:
#	sources/wiringrules.cpp
2026-10-04 01:43:37 +13:00
ispyisail 3150b42087 Warn with a pop-up, not a box, when a wires-per-terminal rule is turned on
Review of #1272: scorpio810 asked for a warning box for users; the inline
box added in 9a55939bb is replaced by a pop-up, as the element editor
gives for unnamed terminals. When OK in Settings > General or in Project
properties turns a rule on (a limit where there was none, or one wire
per folio report), a warning says the rules are experimental, may change
with settings to redo if wires and conductors become separate objects,
and can all be turned off in Settings > General. OK goes on. Changing a
limit that was already on, or turning rules off, shows nothing.

tst_wiringrules: when the warning is due (WiringRules::turnsRuleOn()).
Checked in the GUI from both pages, and that a plain OK shows nothing.

English for translators: "Warning"; "The wires-per-terminal rules are an
experimental feature. They count wires as QElectroTech represents them
today. They could change, and your settings need redoing, if wires and
conductors become separate objects in a future version. All these rules
can be turned off in Configure QElectroTech > General."

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
2026-10-04 01:43:21 +13:00
ispyisail fc4e589d60 View > Show: no DXF picture warning when pictures are hidden
The DXF export warns that pictures become outlines. Pictures hidden by
View > Show are left out of the export, so they no longer trigger it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 01:32:03 +13:00
ispyisail 79b595d66d Merge branch 'feature/wires-per-terminal' into feature/wires-per-terminal-chains 2026-10-04 01:13:09 +13:00
ispyisail 9a55939bb4 Warn that the wires-per-terminal rules are experimental
Review of #1272 (scorpio810, after arummler's note that the rules would
need redesigning if wires and conductors become separate objects): a
warning box, with the standard warning icon, at the top of the rules in
Settings > General and in Project properties. It says the feature is
experimental, counts wires as QElectroTech models them today, and that
the rules, and the user's settings, could change if wires and conductors
are separated.

English for translators: "Experimental feature. These rules count wires
as QElectroTech represents them today; they could change, and your
settings need redoing, if wires and conductors become separate objects
in a future version."

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
2026-10-04 01:13:09 +13:00
Laurent Trinques 5044d3d235 Merge pull request #1270 from ispyisail/fix/script-delete-element-wires
Fix qet.deleteElement() leaving the symbol's wires in the project
2026-10-03 13:54:21 +02:00
ispyisail 17e9f53b81 View > Show: keep the wire text of a potential when its wire is deleted
With "one text per potential", deleting the wire that carries the text
moves it to another wire of the potential, but only if the text
isVisible(). While wire texts were hidden by View > Show none was, so the
text was never moved and the potential came back with no text.

ShownKinds::wantsVisible() also counts a text hidden only by its kind.
Also drop the always-true/false enum range checks clang warned about.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 00:07:16 +13:00