Commit Graph

8402 Commits

Author SHA1 Message Date
Laurent Trinques e9840728b4 Merge pull request #486 from qelectrotech/revert-484-master
Revert "Update-UI-Chinese-translation"
2026-06-11 12:28:55 +02:00
Laurent Trinques ffbcd12d9b Revert "Update-UI-Chinese-translation" 2026-06-11 12:22:45 +02:00
Laurent Trinques 0a124f6695 Merge pull request #484 from zi-mozhuang/master
Update-UI-Chinese-translation
2026-06-11 12:19:03 +02:00
Laurent Trinques 3f6f99b50f Merge pull request #485 from ispyisail/fix-cli-pdf-grid
CLI export: don't draw the editor grid in PDF/PNG/SVG output
2026-06-11 12:15:42 +02:00
Shane Ringrose 42b64a7f0a CLI export: disable the editor grid in rendered output
renderDiagram() had a no-op stub: was_drawing_grid was set to false and
Q_UNUSED'd, so the editor grid still leaked into exported PDF/PNG/SVG.
Toggle Diagram::setDisplayGrid(false) around the render and restore the
previous state afterwards. Fixes all three export formats (they share
renderDiagram).

Reported by scorpio810 on #483.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 22:00:07 +12:00
Laurent Trinques 361719ca74 Fix my error in .pro 2026-06-11 11:39:25 +02:00
Laurent Trinques 181e2b555d Fix missing closing parenthesis in function call in .pro 2026-06-11 11:10:08 +02:00
Laurent Trinques 420512595d Update qelectrotech.pro
add sourc'es files missing in .pro Add headless command-line export (PDF / PNG / SVG / cable-list / wire-list)
#483
2026-06-11 11:07:25 +02:00
zi-mozhuang 9b4bed361d Update qet_zh.ts 2026-06-11 16:59:31 +08:00
Laurent Trinques 339bc8700b Merge pull request #483 from ispyisail/cli-export-master
Add headless command-line export (PDF / PNG / SVG / cable-list / wire-list)
2026-06-11 10:53:23 +02:00
Shane Ringrose 87d5ae5580 CLI export: add wiring list and wire-number list (CSV)
Extends the headless command-line export with two CSV outputs:

  qelectrotech --export-cables <project.qet> <output.csv>   wiring list
  qelectrotech --export-wires  <project.qet> <output.csv>   wire numbers

- --export-cables reuses WiringListExport (one row per conductor).
- --export-wires reuses ConductorNumExport::wiresNum() (distinct wire numbers).

WiringListExport::toCsv() mixed CSV generation with the file dialog and
writing.  Extracted the generation into a new const method toCsvString()
that returns the CSV; toCsv() now calls it and writes the result.  This
makes the wiring list usable headlessly with no behavioural change to the
GUI export.

Addresses part of the CLI export requests (#162, #309): @pkess specifically
asked to "export all connections as a list".
2026-06-11 12:39:43 +12:00
Shane Ringrose 1070179617 Add headless command-line export (PDF/PNG/SVG)
Implements the long-requested batch/headless export
(bugtracker #171, GitHub #309): render a project's diagrams to files
without opening the GUI.

  qelectrotech --export-pdf <project.qet> <output.pdf>   one multi-page PDF
  qelectrotech --export-png <project.qet> <output_dir>   one PNG per diagram
  qelectrotech --export-svg <project.qet> <output_dir>   one SVG per diagram

main.cpp detects an export request before SingleApplication is created (so the
arguments are not forwarded to a running instance), spins up a plain
QApplication for rendering, and exits with the export's status code.

Rendering reuses Diagram::render() over
BorderTitleBlock::borderAndTitleBlockRect(), the same geometry the GUI
print/export path uses, so output matches the editor. Image files are named
NN_Title.<ext>.

New files: sources/cli_export.{h,cpp}, registered in
cmake/qet_compilation_vars.cmake.
2026-06-11 11:10:09 +12:00
Laurent Trinques 6c4711a8d0 Update qet_compilation_vars.cmake 2026-06-07 15:11:06 +02:00
Laurent Trinques 8a8a338a2e Update CMakeLists.txt 2026-06-07 15:06:23 +02:00
Laurent Trinques 407cc7a4c2 Update CMakeLists.txt 2026-06-07 14:59:36 +02:00
Laurent Trinques 5cb8930732 Update fetch_pugixml.cmake 2026-06-07 14:57:29 +02:00
Laurent Trinques a24acfac24 Update fetch_pugixml.cmake 2026-06-07 14:57:05 +02:00
Laurent Trinques 8b0b1d10d4 git submodule update --remote elements 2026-06-05 11:28:36 +02:00
Laurent Trinques 57dfa28674 fix erroneous comments in drawContact for SW terminal names
The comments describing the terminal_names layout were inherited from a
previous version and no longer matched the actual assignment order:

    terminal_names << nc_name << no_name << common_name;
    i.e. [0]=NC, [1]=NO, [2]=Common

Update all affected comments to reflect the current storage order.
2026-06-05 11:21:08 +02:00
Laurent Trinques 3848c7821a Merge pull request #479 from ChuckNr11/master
fix possible crashes in crossrefitem
2026-06-05 11:01:44 +02:00
Laurent Trinques 1572c23d51 Fix FTBFS https://github.com/qelectrotech/qelectrotech-source-mirror/
pull/477
2026-06-05 10:46:00 +02:00
achim e234f063f8 fix possible crashes in crossrefitem
fix access to QList with potentially out-of-bounds index
2026-06-04 14:49:43 +02:00
Laurent Trinques be21604ad0 Merge pull request #477 from Kellermorph/update-german-translation
Fix: Dynamic element text shifting/jumping when duplicating diagrams
2026-06-01 21:10:06 +02:00
Kellermorph e1ccc1e568 Fix: Dynamic element text shifting/jumping when duplicating diagrams 2026-06-01 11:25:25 +02:00
Laurent Trinques e202b5bc2b Merge pull request #475 from Kellermorph/update-german-translation
Update German translations for duplicate diagram feature
2026-05-31 16:05:45 +02:00
Laurent Trinques 2b7e62f901 [PATCH] print: fix black screen on macOS arm64 after PDF export
On macOS arm64 (Apple Silicon, Sequoia), exporting a PDF via
QPrintPreviewWidget leaves a black screen with only the mouse cursor
visible.  Cmd+Tab restores the display; the exported PDF itself is
correct and clickable cross-reference links work fine.

Root cause
----------
requestPaint() is a slot connected to QPrintPreviewWidget::paintRequested.
Inside this slot the code was calling painter.end() manually, then
pdfConvertUriToGoTo().  On macOS arm64 the Qt5 paint cycle backed by
Metal/CALayer is asynchronous: closing the QPainter from *within* the
paintRequested slot interrupts the compositor before it has flushed the
backing store.  The window goes black and never repaints because the
close() that follows immediately destroys it.

On x86_64 / older macOS (raster/CoreGraphics backend) the paint cycle is
synchronous, so the same code happened to work.

Fix
---
1. Remove the manual painter.end() and pdfConvertUriToGoTo() call from
   requestPaint().  The QPainter is stack-allocated; it destructs normally
   when the slot returns, which is the correct moment to flush the PDF.

2. In print(), capture the output file name before m_preview->print(),
   then defer both pdfConvertUriToGoTo() and this->close() to the next
   event-loop iteration via QTimer::singleShot(0, ...).  This gives the
   Metal compositor one full event-loop turn to finish compositing the
   backing store before the window is torn down.

The fix is a no-op on all other platforms: QTimer::singleShot(0) posts
an event that fires in the very next iteration, so there is no perceptible
delay.

Tested
------
- macOS Sequoia 15.x, Apple M-series, Qt 5.15.x (arm64): black screen gone
- macOS 10.15 x86_64 VM, Qt 5.15.x: no regression
- Linux/Debian Qt 5.15.x: no regression
- PDF cross-reference links and GoTo/FitR destinations: unaffected

Fixes: black screen after PDF export on macOS arm64
2026-05-31 13:01:52 +02:00
Kellermorph 23e8258ae1 Update German translations for duplicate diagram feature 2026-05-31 10:48:09 +02:00
Laurent Trinques 457d265f0a Update translation files 2026-05-30 21:27:19 +02:00
Laurent Trinques cd76b6a1d6 This adds native, clickable hyperlinks to PDF exports: cross-references jump
directly to the related component on its folio, framing the target element.

When a project is exported to PDF, every cross-reference becomes an internal
link. Four kinds are covered:

- **Master → contact**: the contact list on a coil/relay (`CrossRefItem`)
- **Folio report → report**: report element labels (`DynamicElementTextItem`)
- **Slave → master**: the `(folio-position)` reference shown on a slave
  (both standalone `DynamicElementTextItem` and grouped `ElementTextItemGroup`)

Clicking a link navigates **inside** the open document (no new viewer
instance) and zooms to frame the target element.

1. **Injection** (`printDiagram`, only when the paint engine is a `QPdfEngine`):
   link rectangles are added with `QPdfEngine::drawHyperlink()`. The scene→page
   mapping is rebuilt to match exactly what `QGraphicsScene::render()` does
   (top-left anchored, `KeepAspectRatio`, **no centering**), and rectangles are
   passed in device pixels — `pageMatrix()` already applies the 72/resolution
   scale and Y-flip internally.

2. Each link URL encodes the target page and the target element's rectangle, in
   PDF points on its own page: `#page=N&fitr=L_B_R_T`.

3. **Post-processing** (`pdfConvertUriToGoTo`, run after the painter is closed):
   the `/S /URI` annotations are rewritten to native `/S /GoTo` actions with a
   `/D [pageObj 0 R /FitR L B R T]` destination, and the xref table is rebuilt.
   Pages are enumerated from the `/Pages /Kids` tree (reliable), not by scanning
   for `/Type /Page` in raw bytes.

- `sources/print/projectprintwindow.{cpp,h}` — injection + post-processing
- `sources/qetgraphicsitem/crossrefitem.{cpp,h}` — `hoveredContactsMap()` accessor; store text rect for hit area
- `sources/qetgraphicsitem/dynamicelementtextitem.h` — `slaveXrefItem()` / `masterElement()` accessors
- `sources/qetgraphicsitem/elementtextitemgroup.h` — `slaveXrefItem()` accessor
- `qelectrotech.pro`, `cmake/qet_compilation_vars.cmake` — enable Qt gui-private headers (`<private/qpdf_p.h>`)

- **Fit-to-page mode only.** Links are not injected in tiled mode (multiple
  pages per folio), which would require a per-tile transform.
- Uses Qt private API (`QPdfEngine::drawHyperlink`), stable since Qt 4 but not
  part of the public API; the build links against `gui-private`.
- Page-tree enumeration assumes the flat `/Kids` array Qt produces (no nested
  page trees).
- The frame zoom is controlled by two constants in `destRectPdf` (`pad`,
  `minSide`) and can be tuned.
- Tested on Qt5; the `/Kids` parsing and `pageMatrix` behaviour are identical on
  Qt6.
2026-05-30 18:48:28 +02:00
Laurent Trinques b522a94556 Merge pull request #473 from Kellermorph/makro-fix
Feat: Add ability to duplicate diagrams/folios with all metadata and …
2026-05-30 05:27:35 +02:00
Kellermorph 399bc0e897 Feat: Add ability to duplicate diagrams/folios with all metadata and elements 2026-05-29 19:14:36 +02:00
Laurent Trinques de9eeed542 Merge pull request #472 from Kellermorph/makro-fix
Feature: Allow excluding specific elements from BOM (Nomenclature)
2026-05-28 14:17:46 +02:00
Kellermorph c071e92c58 Feature: Allow excluding specific elements from BOM (Nomenclature) 2026-05-28 12:23:54 +02:00
Laurent Trinques d22e4abf96 Update translations files 2026-05-28 10:00:09 +02:00
Laurent Trinques 38b91e8083 Merge pull request #471 from Kellermorph/makro-fix
Potential Isolation option for terminals
2026-05-28 09:45:04 +02:00
Kellermorph 19704cf5ca Potential Isolation option for terminals 2026-05-27 21:20:50 +02:00
Laurent Trinques 471d1f2538 Merge pull request #470 from Kellermorph/makro-fix
Fix: Wiring list filter and dynamic text timing
2026-05-27 06:19:06 +02:00
Kellermorph dc52105868 Fix: Wiring list filter and dynamic text timing 2026-05-26 18:31:37 +02:00
Laurent Trinques 1b8dc5f410 texteditor: set font size spinbox minimum to 4pt to prevent SIGSEGV 2026-05-25 13:14:57 +02:00
Laurent Trinques 26d5d019cc texteditor: fix SIGSEGV caused by font size spinbox reaching 0 2026-05-25 13:04:37 +02:00
Laurent Trinques 6dd7c2d926 crossrefitem: fix SIGSEGV crash + improve double-click navigation + fix PDF/SVG/print rendering
Windows Build / build-windows (push) Has been cancelled
Test Windows VS2026 migration / Build on windows-2025-vs2026 (push) Has been cancelled
Windows Build / deploy-pages (push) Has been cancelled
Fix a use-after-free crash (SIGSEGV in QRegion::begin, Qt5Gui+0x49af60)
confirmed by analysis of 19 coredumps. The crash was triggered when the
scene viewport clip region was freed during zoom/resize events while
QPicture::play() replayed drawPolyline commands through the scene painter.
Qt's raster engine then dereferenced a stale QRegionData pointer.

Root cause: CrossRefItem used three nested QPicture objects (m_drawing,
m_hdr_no_ctc, m_hdr_nc_ctc). The nested drawPicture() calls amplified
the use-after-free risk on any repaint event.

Fix: remove all QPicture from CrossRefItem entirely.
- updateLabel() now uses a QImage-backed dummy painter to compute
  m_bounding_rect, m_shape_path and m_hovered_contacts_map geometry.
  A bool m_update_map flag prevents the map from being overwritten
  during paint().
- paint() calls drawAsCross()/drawAsContacts() directly on the scene
  painter — no QPicture::play() anywhere in the class.
- buildHeaderContact() now draws NO/NC symbols directly onto the painter
  instead of recording them into QPicture members.

Also fix mouseDoubleClickEvent: the element under the click is now found
directly from m_hovered_contacts_map using the event position, rather
than relying on m_hovered_contact which could be reset by hoverMoveEvent
between the two clicks of a double-click.

Also remove setBold(true) on terminal name labels: the Qt PDF/SVG/print
engine rendered bold at 4pt as extremely thick glyphs, making exports
unreadable. Normal weight at 4pt is correct and legible on all backends.

Fixes: SIGSEGV in CrossRefItem::paint() on zoom/resize
Fixes: double-click navigation unreliable on Xref contact symbols
Fixes: terminal name labels unreadable in PDF/SVG/print export
2026-05-24 16:00:45 +02:00
Laurent Trinques 47796e183a Update translation files 2026-05-23 19:28:22 +02:00
Laurent Trinques ddf5ffcd89 xref: add option to hide terminal names in cross-references
Add a new boolean property 'showTerminalName' (default: true) to
XRefProperties, with full persistence in XML and QSettings.

A new checkbox "Afficher les numéros de bornes dans les Xrefs" is
added to the XRefPropertiesWidget in the main display group (not in
the cross-only group), so it is active in both Cross and Contacts modes.

When unchecked, terminal names are hidden in all three rendering paths:
  - drawContact()            (Contacts mode: NO/NC/SW symbols)
  - fillCrossRef()           (Cross mode: NO and NC columns)
  - setUpCrossBoundingRect() (Cross mode: bounding rect sizing)

Backward compatible: existing project files without the attribute
default to showTerminalName=true (no visual change).

Files changed:
  sources/properties/xrefproperties.h
  sources/properties/xrefproperties.cpp
  sources/ui/xrefpropertieswidget.ui
  sources/ui/xrefpropertieswidget.cpp
  sources/qetgraphicsitem/crossrefitem.cpp
2026-05-23 19:23:43 +02:00
Laurent Trinques 7d718bb9a0 crossrefitem: fix terminal name sorting for power contacts
The previous sort used QString::toInt() to order terminal names,
which returns 0 for any string containing a non-numeric prefix
(e.g. "R1", "R2", "L1", "L2"...). This caused undefined sort order
and incorrect pole pairing in the Xref contact mirror.

Example: a 4-pole NC power contact with terminals R1..R8 was
displaying R1/R3, R5/R7, R2/R4, R6/R8 instead of the correct
R1/R2, R3/R4, R5/R6, R7/R8.

Fix: extract the trailing numeric part of each terminal name and
compare prefixes separately. If both names share the same prefix
and both have a trailing number, sort numerically on that number;
otherwise fall back to full string comparison.

This covers all naming conventions: "1"/"2"/"3", "R1"/"R2"/"R3",
"L1"/"L2"/"L3", etc.

Applied in both drawContact() and setUpCrossBoundingRect().
2026-05-23 15:50:11 +02:00
Laurent Trinques d949e6eb8c crossrefitem: fix SIGSEGV when dropping power NC contact on diagram
Three bugs were causing a crash (SIGSEGV in QRegion::begin) when
a power NC slave element was placed on a folio, even before linking
it to a master element.

1. m_drawing (QPicture) was never reset between updateLabel() calls.
   QPicture accumulates paint commands — calling qp.begin() on an
   existing QPicture appends to it rather than replacing its content.
   After several updates (load, move, hover...) the picture became
   corrupted and crashed on play().
   Fix: reset m_drawing = QPicture() at the start of updateLabel().

2. m_drawed_contacts was only initialized to 0 in drawAsContacts(),
   but not in drawAsCross(). When drawing in Cross mode, fillCrossRef()
   called drawContact() with an uninitialized m_drawed_contacts value,
   producing a garbage offset. The NC contact symbol uses drawPolyline()
   with a sub-pixel Y coordinate (offset+2.5); with a random offset Qt
   generated an invalid QRegion and crashed.
   This explains why NC contacts crashed but NO contacts did not: the
   NO symbol only uses drawLine() which is more tolerant of bad coords.
   Fix: add m_drawed_contacts = 0 at the start of drawAsCross().

3. setUpCrossBoundingRect() used QRectF() (null rect) as the reference
   rect for painter.boundingRect(), which can return invalid dimensions.
   Additionally, height was accumulated incorrectly: united() + setHeight()
   doubled the height at each iteration, causing an exponentially growing
   bounding rect with multiple contacts.
   Fix: use QRectF(0, 0, 500, 20) as reference rect and accumulate
   height and width independently.
2026-05-23 15:32:28 +02:00
Laurent Trinques dbda958261 terminaldata: add No, Nc, Common types for SW contacts
Extend TerminalData::Type enum with three new semantic values:
- No     : Normally Open terminal of a switch (SW) contact
- Nc     : Normally Closed terminal of a switch (SW) contact
- Common : Common terminal of a switch (SW) contact

Update typeToString() and typeFromString() accordingly.
Fully backward compatible: existing Generic/Inner/Outer types
are unchanged. Elements without typed terminals fall back
to the previous behavior (first 2 named terminals).

terminal: expose terminalType() as public accessor

Add Terminal::terminalType() returning the TerminalData::Type
of this terminal. This allows crossrefitem and other consumers
to filter terminals by semantic role (No, Nc, Common) without
accessing TerminalData internals directly.

terminaleditor: add No, Nc, Common entries to type combobox

Expose the three new TerminalData types (No, Nc, Common) in
the element editor UI so users can assign a semantic role to
each terminal of a SW contact element.

Also fix a pre-existing bug in updateForm() where m_type_cb
was incorrectly using m_orientation_cb->findData() instead
of m_type_cb->findData(), preventing the type from being
restored correctly when selecting a terminal.

terminaleditor: add No, Nc, Common entries to type combobox

Expose the three new TerminalData types (No, Nc, Common) in
the element editor UI so users can assign a semantic role to
each terminal of a SW contact element.

Also fix a pre-existing bug in updateForm() where m_type_cb
was incorrectly using m_orientation_cb->findData() instead
of m_type_cb->findData(), preventing the type from being
restored correctly when selecting a terminal.
2026-05-23 02:09:32 +02:00
Laurent Trinques d691489165 Update translations files 2026-05-22 10:16:24 +02:00
Laurent Trinques 202ea38e40 Merge pull request #464 from Kellermorph/makro-fix
New element: Line definition
2026-05-22 10:06:20 +02:00
Kellermorph 86dafcb576 Merge branch 'master' into makro-fix 2026-05-21 20:52:18 +02:00
Kellermorph f416c2a97e New element: Line definition 2026-05-21 20:47:44 +02:00