Commit Graph

3956 Commits

Author SHA1 Message Date
enesgursoy6110 36dd1624d2 Show folio identity first in report link picker 2026-09-08 21:02:46 +03:00
Laurent Trinques a583b3c43c Merge pull request #688 from IBSYSLevi/fix/saving-coil-master
Fix: saving coil master
2026-09-08 08:35:00 +02:00
Laurent Trinques 1738c3ad6c Merge pull request #771 from Kellermorph/spinbox-crossref
Add configurable distance between label and slave XRef
2026-09-08 08:20:33 +02:00
Laurent Trinques 1793dcb9a8 Revert "Feature: Terminal potential grouping" 2026-09-07 15:44:12 +02:00
Laurent Trinques cc7aaf3538 Merge pull request #804 from IBSYSLevi/feature/terminal-potential-grouping
Feature: Terminal potential grouping
2026-09-07 15:08:00 +02:00
Laurent Trinques a6285c7ef7 Merge pull request #815 from ispyisail/test/diagramsortkeys-unit-test
Add unit test locking in Diagram::toXml() coordinate sort order
2026-09-07 14:31:26 +02:00
ispyisail bd5cff4211 Add a unit test locking in Diagram::toXml()'s coordinate sort order
Follow-up to the positionKey() fix merged directly in #779
(b2f4ef5d2): per review request, add a small regression test so this
class of bug (fixed-precision "%.4f" formatting compares out of
numeric order once the integer part's digit count differs) can't
silently reappear.

positionKey()/coordinateKey() move out of diagram.cpp's anonymous
namespace into a small header-only diagramsortkeys.h so the test can
link against the exact same code Diagram::toXml() uses, instead of
duplicating the algorithm. Behavior is unchanged.

tst_diagramsortkeys covers: single- vs double-digit, double- vs
triple-digit, negative-vs-negative, negative-vs-positive, and
negative-vs-zero coordinate pairs, plus sub-precision deltas.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 20:54:18 +12:00
Andre Rummler 296f142036 Adding icons to graphs and image operations. 2026-09-07 10:44:30 +02:00
Andre Rummler 4d991d0419 Conversion of ellipses and rounded rectangles to bezier curves instead of polylines. 2026-09-07 10:44:30 +02:00
Andre Rummler a85bd6a49b Fixing undo operations of graphs and images. Changing undo names. 2026-09-07 10:44:30 +02:00
Andre Rummler ef8e41a5c3 Fix transparency export (not possible for jpeg). 2026-09-07 10:44:30 +02:00
Andre Rummler 6f80da66d5 Connected to previous image handling updates: images were not exported at all to dxf. In this
update instead of the image a placeholder box is drawn and a warning is given during export.

Current dxf version is extremely old and does not support any image embedding. Future possible
update is the introduction of a newer dxf version export option which would allow to embed a link to an external
image file.
2026-09-07 10:44:30 +02:00
Andre Rummler a065867502 Fix issue that made it impossible to remove all transparency colours defined in a previously opened dialog. On the last color the OK button was greyed out. 2026-09-07 10:44:29 +02:00
Laurent Trinques b98d41357a Merge pull request #814 from ispyisail/fix/diagram-toxml-deterministic-order
Fix: positionKey() didn't sort coordinates numerically
2026-09-07 10:30:48 +02:00
ispyisail b2f4ef5d25 Fix: positionKey() didn't sort coordinates numerically
Plain fixed-precision formatting ("%.4f") produces strings that don't
compare in numeric order once the integer part has a different digit
count -- e.g. "15.0000" sorts before "5.0000" as text, even though
15 > 5. That silently broke the determinism goal of this branch for
any diagram with coordinates spanning more than one digit width.

Shift into a non-negative range and zero-pad to a fixed width instead,
so the formatted string sorts the same way the number does, including
negative values.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 20:13:05 +12:00
Laurent Trinques bd8470afa8 Merge pull request #787 from ispyisail/fix/removediagram-cascade-delete
Cascade-delete a diagram's element/terminal/conductor rows on removal
2026-09-07 10:05:27 +02:00
ispyisail 7c5f8c6a4b Fix: roll back removeDiagram cascade delete on query failure
Each cascade delete (element_info/terminal/conductor/element) only
logged its error and fell through to the next query regardless, so a
mid-cascade failure (e.g. a locked DB) still let the diagram row get
deleted while its child rows survived -- the same inconsistency this
branch set out to fix, just via a different failure path. Wrap the
cascade in a transaction and roll back + bail on the first failed
exec(), matching the existing transaction pattern in updateDB().

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 20:02:38 +12:00
Laurent Trinques 6b27043f33 Merge pull request #779 from ispyisail/fix/diagram-toxml-deterministic-order
Make Diagram::toXml() serialize elements and conductors deterministically
2026-09-07 09:38:28 +02:00
Laurent Trinques ed5a510592 Merge pull request #778 from ispyisail/fix/qpropertyundocommand-undo-symmetry
Give QPropertyUndoCommand::undo() its own first-time grace period
2026-09-07 01:09:44 +02:00
Laurent Trinques 3abf187688 Merge pull request #813 from jp2images/fix-element-editor-mirror-in-place
Element editor: mirror and flip the selection in place instead of across the origin
2026-09-06 14:38:15 +02:00
Jeff Patterson 825a1a594d Fix element editor Mirror and Flip to reflect the selection in place
Mirror (M) and Flip (F) in the element editor reflected the selected
parts across the element origin: every part's mirror() and flip()
negated the scene x or y coordinate. A part drawn to the right of the
origin landed the same distance to the left, so the selection jumped
to the other side of the canvas instead of turning around.

MirrorElementsCommand and FlipElementsCommand now compute the united
scene bounding rectangle of the selected items and reflect across the
vertical or horizontal line through its center. The center is snapped
to the nearest half of the diagram grid, so points that were on the
grid stay on the grid after the reflection. Terminals in particular
keep their grid alignment.

Each part's mirror() and flip() takes the axis coordinate as a
parameter with a default of 0, so the previous behavior remains
available to any other caller. The command stores the axis when it is
created and undo reapplies the same reflection, which is its own
inverse, so the existing undo path is unchanged.

Parts covered: PartArc, PartDynamicTextField, PartEllipse, PartLine,
PartPolygon, PartRectangle, PartTerminal, PartText.

Fixes #812
2026-09-06 06:48:45 -05:00
Andre Rummler b395527915 Add transparency to each color for image transparency. 2026-09-05 20:54:19 +02:00
Andre Rummler 7741bb33b2 Use downscaled image for image transparency window to improve resposiveness. 2026-09-05 20:54:09 +02:00
Laurent Trinques 70c665199f Merge pull request #809 from arummler/feature-graphics-primitives-squashed
Add editable resize/rotate/skew handles for shapes and images
2026-09-05 19:13:48 +02:00
Kellermorph a494a8fd6c Add 'Text field' option for slave cross-reference positioning 2026-09-05 18:55:14 +02:00
Andre Rummler 6b577ee757 Add editable resize/rotate/skew handles for shapes and images
Shapes and images can now be resized, rotated, and skewed directly
on the canvas, not just moved. Both share one small transform
struct (rotation, then skew, then scale, anchored on a movable
pivot) and one handle widget, so a corner drag, an edge skew, or
grabbing the rotate handle behaves the same way and runs through
the same matrix math everywhere, instead of every item type
reinventing its own.

Shapes also gained a proper pen tool (bezier paths, corner/smooth/
symmetric nodes), arc support, and mirroring. Images gained
non-destructive cropping and colour-keyed transparency, both
remember their own settings, so reopening the dialog picks up
where you left off instead of starting over.

Properties dialogs for both were extended to match (position,
size, angle, skew), with undo/redo wired through for every handle
drag.

Old XML files can read easily as the transformation is only added
if needed and the old syntax is still used and understood if it is
not needed.
2026-09-05 15:48:28 +02:00
Laurent Trinques 74e878207a Merge pull request #731 from philippeagray/cli-export-hide-terminals
CLI export: hide terminal markers and names in rendered output (add --show-terminals)
2026-09-05 15:14:12 +02:00
plc-user 3e66d403c8 adjust whitespace 2026-09-05 00:22:35 +02:00
plc-user a7fa4dfdcf FIX language-setting
Set language to system-default on start-up, if for
whatever reason the setting in file or registry
for language is empty.
2026-09-04 21:46:23 +02:00
Levi Jetzer 1e1039dd32 Address review
1. Drop dead prepareGeometryChange()/update() calls in
setPotential(), split unrelated terminaleditor.h re-indent into its
own change

2. Removed: setPotential() had prepareGeometryChange()/update() left over from
the label-display mechanism that was dropped before this PR
2026-09-04 13:12:21 +02:00
Laurent Trinques f997550e07 Merge pull request #805 from Kellermorph/fix-marked-site
Select newly added diagram in project tree
2026-09-04 08:30:41 +02:00
Kellermorph d9f148ab2f fix 2026-09-03 15:05:22 +02:00
Kellermorph 9fdd7b5fc0 Select newly added diagram in project tree 2026-09-02 21:30:10 +02:00
IBSYSLevi e410896f5d Merge branch 'qelectrotech:master' into feature/terminal-potential-grouping 2026-09-02 20:12:14 +02:00
Levi Jetzer 10bf0411bb Add "Potentiel" field to the terminal editor (element editor)
New QLineEdit (m_potential_le) between Type and Nom: an optional,
symbol-author-chosen grouping identifier shared by terminals that
belong to the same physical terminal within a multi-terminal block.

Stored as TerminalData::m_potential (new field, persisted as the
"potential" XML attribute, empty by default).
Used by relatedPotentialTerminal() in terminal.cpp: when
potential_isolating is enabled on a Terminal-type element, terminals
sharing a non-empty, matching potential value now stay electrically
linked to each other instead of every terminal in the block being
isolated from every other one.

Tooltip on the field for explanation
2026-09-02 19:30:26 +02:00
ispyisail c69e5747a1 Add position-lock checkbox to element properties (issue #801)
Elements already inherited QetGraphicsItem::isMovable()/setMovable() --
the same mechanism images and drawn shapes use for their "lock position"
checkbox -- but nothing exposed it in the element properties panel, and
Element::toXml()/fromXml() never persisted it.

- ElementPropertiesWidget::generalWidget(): add a "Verrouiller la
  position" checkbox mirroring ShapeGraphicsItemPropertiesWidget's
  m_lock_pos_cb, toggling the element's inherited setMovable().
- Element::toXml()/fromXml(): persist is_movable, same attribute name
  and default-true behavior as DiagramImageItem/QetShapeItem.

Verified via headless --resave round-trip: is_movable="0" survives
load -> save unchanged, existing elements without the attribute default
to movable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HdWpDp3TrPKbHnv7YUcNJj
2026-09-01 07:16:32 +12:00
ispyisail 5027ffda9b Apply the same zoom clamp to DiagramView::zoom()
DiagramView::zoom() had the same unbounded scale() as the element editor:
a held scroll-wheel zoom could overflow the view transform. Clamp the
resulting scale to [m_min_zoom, m_max_zoom] before applying it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HdWpDp3TrPKbHnv7YUcNJj
2026-08-31 05:47:04 +12:00
ispyisail 3ca5d4ab29 Fix GitHub issue #798: element editor crash on scroll-wheel zoom
ElementView applied scale() on every wheel notch with no bound on the
resulting view transform. Held down, the scroll-wheel zoom drives the
transform scale (m11) to floating-point overflow; the transform becomes
non-invertible, mapToScene() returns NaN and the next background paint
aborts the editor ("program closes completely" as reported on Windows).

Route zoomIn/zoomOut/zoomInSlowly/zoomOutSlowly through a new
scaleClamped() helper that only applies the scale while the result stays
within [m_min_zoom, m_max_zoom] (0.1 .. 200). Behaviour within that range
is unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HdWpDp3TrPKbHnv7YUcNJj
2026-08-31 05:45:35 +12:00
Laurent Trinques 3fa73e945e fix(ui): remove legacy Qt5 font weight tags in autonumberingmanagementw.ui
Qt6's QFont::setWeight() now takes a QFont::Weight enum instead of
a raw int, so uic-generated code from the old <weight>75/50</weight>
XML properties fails to compile (worked on GCC via -fpermissive,
but hard error on Apple Clang for the macOS build).

<bold> is already set on all affected widgets, so <weight> was
redundant and can be dropped without any visual change.
2026-08-29 11:02:59 +02:00
Laurent Trinques 4038122f99 Merge pull request #797 from arummler/fix-load-empty-project
Fix: avoid crash when opening a project without a folio (diagram).
2026-08-29 10:15:04 +02:00
Laurent Trinques 860a12b970 Merge pull request #796 from Kellermorph/fix-crossref-plc
Fix PLC cross-reference links and make cross-ref column clickable
2026-08-29 10:14:25 +02:00
Andre Rummler 0a98cce8de Fix: avoid crash when opening a project without a folio (diagram). 2026-08-28 19:55:29 +02:00
Kellermorph cceddba44e Fix PLC cross-reference links and make cross-ref column clickable 2026-08-28 12:36:03 +02:00
Laurent Trinques 487b22f483 Merge pull request #769 from Kellermorph/layout-fix
Fix dock widget size/position not being restored on Qt6
2026-08-28 09:25:00 +02:00
Kellermorph c9899372d3 Fix crash when expanding templates/macros tree (Qt6 regression) 2026-08-27 07:27:25 +02:00
Laurent Trinques bfe2aa26a0 Merge pull request #786 from ispyisail/fix/remove-dead-exclude-bom-clause
Remove dead exclude_from_bom clause from ElementQueryWidget
2026-08-25 06:52:29 +02:00
Laurent Trinques 4bde81937d Merge pull request #789 from ispyisail/fix/removediagram-safe-teardown
Fix segfault when a project is destroyed with a diagram still pending deleteLater()
2026-08-25 06:50:50 +02:00
ispyisail e5935c75d1 Fix segfault when a project is destroyed with a diagram still pending deleteLater()
QETProject::removeDiagram() detaches a diagram from m_diagrams_list and
schedules it via deleteLater(), but that deferred delete only runs on
a future event-loop iteration. If ~QETProject() runs first (e.g. a
CLI/headless caller with no event loop, or a project closed
immediately after removeDiagram()), the diagram is still a QObject
child of the project and gets destroyed later by QObject's own
automatic child cleanup -- which runs after m_data_base has already
been torn down as a plain C++ member. Diagram::~Diagram() calls back
into dataBase()->removeElement() for each of its elements, so that
ordering is a use-after-free (SIGSEGV in QSqlResult::exec()).

Delete any such still-parented diagrams synchronously in ~QETProject()
while m_data_base is still alive, before the base QObject destructor
runs. Any deleteLater() event that does eventually fire afterward is a
safe no-op on an already-deleted QObject.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 06:59:02 +12:00
plc-user 2e49f4588a fix problem with PDF-links in files with brackets in name 2026-08-24 18:24:30 +02:00
ispyisail e3cb994e0e Cascade-delete a diagram's element/element_info/terminal/conductor rows
removeDiagram() only ever deleted the diagram's own row. No foreign key in
this schema is declared ON DELETE CASCADE (and SQLite foreign-key
enforcement is never turned on for this connection anyway), so removing a
diagram left every element, element_info, terminal and conductor row that
belonged to it behind in the database -- silently, since nothing reads them
until the next full updateDB() rebuild papers over it.

Traced why this had never crashed anything: Diagram::~Diagram() explicitly
walks and deletes its top-level items through removeItem() (which does call
dataBase()->removeElement() correctly), but deliberately skips conductors --
because a conductor's destructor touches both of its terminals
(terminal1->removeConductor(this)), and those terminals may belong to an
element already destroyed earlier in the same sweep. Conductors are instead
destroyed as a side effect of Terminal::~Terminal()'s qDeleteAll() on its own
conductor list, which is a plain C++ delete that never goes through
Diagram::removeItem() and therefore never calls dataBase()->removeConductor()
at all. So the object graph is torn down safely, but the database is never
told about the conductors or their terminals.

Fixed by adding the missing bulk deletes to projectDataBase::removeDiagram()
itself, run while the diagram (and its live scene) still exist -- verified
that QETProject::detachDiagram() emits diagramRemoved() (which this class's
constructor connects to this slot) synchronously, before the Diagram object
is scheduled for destruction via deleteLater(), so nothing here races the
C++ teardown described above. Order matters: element_info and terminal have
no diagram_uuid column of their own, so both are scoped through a subquery
on element and must run before element itself is deleted.

Verified against examples/industrial.qet (50 diagrams) by calling
projectDataBase::removeDiagram() directly and comparing table counts before
and after, with no intervening updateDB() call to mask a gap:

  element=354->335 element_info=354->335 terminal=1087->1033 conductor=671->626 diagram=50->49

Every delta matches a direct SQL count for that diagram's own rows exactly
(19 elements, 54 terminals), and both "orphan rows still referencing the
removed diagram" checks read 0 afterward -- so the cascade is complete and,
just as importantly, scoped: nothing belonging to the other 49 diagrams
moved.

Separate finding, not fixed here: QETProject::removeDiagram(Diagram*) (the
synchronous, non-undoable variant, not the usual GUI
ProjectView::removeDiagram() path) segfaults if the enclosing QETProject is
destroyed before an event loop iteration lets its pending deleteLater() run
-- reproduces identically on unmodified master, so it predates and is
unrelated to this change. Worth its own report; a headless caller is the
only realistic way to hit it, which is how this surfaced.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 22:51:39 +12:00