Commit Graph

8409 Commits

Author SHA1 Message Date
Shane Ringrose a219c3f587 CLI: clickable cross-reference hyperlinks in PDF export
Wire the shared PdfLinks helper into the headless --export-pdf path so
CLI-exported PDFs get the same internal cross-reference / folio-report
navigation as the GUI print export.

For each page, after rendering, the scene-to-page geometry is rebuilt
from the QPdfWriter (96 dpi, zero margins, page sized to the diagram so
the scale is ~1 with no centering) — deliberately NOT reusing the
QPrinter-based mapping — and passed to PdfLinks::injectCrossRefLinks().
After the painter closes, PdfLinks::convertUriToGoTo() rewrites the URI
annotations into native GoTo/FitR actions.

Builds on the helper extracted in the previous commit; no change to the
other CLI tools.
2026-06-11 23:48:45 +12:00
Shane Ringrose 6b3b55b0e1 PDF links: extract pdf_links.{cpp,h} shared helper
Move the PDF cross-reference hyperlink logic out of ProjectPrintWindow
into a standalone translation unit so it can be reused (the CLI PDF
export will call it next):

- injectCrossRefLinks(): emits the URI link annotations for a diagram's
  cross-references and folio reports. The scene-to-page mapping is passed
  in as a PageGeometry (transform + devToPdf + source-rect lookup) so each
  caller supplies its own correct geometry, rather than the helper assuming
  a QPrinter.
- convertUriToGoTo(): the PDF post-processor, moved verbatim.

ProjectPrintWindow stays a pure caller: it builds its PageGeometry from the
printer page layout exactly as before and calls the helper. No behavioural
change to GUI PDF export; no class-structure changes.

Per review guidance on #483.
2026-06-11 23:48:14 +12:00
Laurent Trinques 36d0121038 Merge pull request #489 from ispyisail/cli-tools
CLI: add verification & data-export tools (info, BOM, nets, links, check-elements, resave)
2026-06-11 13:42:59 +02:00
Laurent Trinques 8235ecdbc9 Merge pull request #488 from Kellermorph/master
Issues 482
2026-06-11 13:32:30 +02:00
Shane Ringrose b6e4cd4786 CLI: add --export-nets, --export-links and --resave
Three more read-only command-line tools for verifying connectivity and
cross-reference intelligence (useful for import / migration pipelines):

  qelectrotech --export-nets    <project.qet> <output.json>
  qelectrotech --export-links   <project.qet> <output.csv>
  qelectrotech --resave         <project.qet> <output.qet>

- --export-nets walks Conductor::relatedPotentialConductors() to group
  every electrically-connected terminal into a net (potential), following
  folio reports and terminal blocks across all folios. Output is JSON:
  per net, the wire number and the list of {element, terminal, folio}.
  This is the connectivity ground truth.

- --export-links reports each linkable element (master/slave/report/
  terminal), its link type and the elements it links to, flagging
  masters/slaves with no link as UNRESOLVED. Verifies coil<->contact
  cross-references. Verified on examples/industrial.qet: 436 linkable
  (76 master, 41 slave, ...), 37 unresolved.

- --resave loads the project and writes its XML back out, so an external
  diff can reveal markup QET silently normalises on load
  (tolerated-but-invalid XML). Round-trip verified: the re-saved project
  reloads with identical diagram/element/conductor counts.
2026-06-11 23:23:13 +12:00
Shane Ringrose fb35027624 CLI: add --info, --export-bom and --check-elements verification tools
Extends the headless command-line interface with three read-only tools
aimed at validating projects and element libraries (useful for batch
import / migration pipelines):

  qelectrotech --info           <project.qet> [output.json]
  qelectrotech --export-bom     <project.qet> <output.csv>
  qelectrotech --check-elements <element.elmt | directory>

- --info dumps a structural summary as JSON straight from QET's loaded
  model: per-diagram element / conductor counts, page size, and the
  number of unconnected ("free") terminals, plus project totals. Because
  it uses the real loader it reports what the editor actually sees.

- --export-bom writes a bill of materials (one row per element) as CSV,
  querying the project's own element_nomenclature_view (the same source
  as the GUI BOM export). updateDB() is called first so the database is
  populated in a headless run.

- --check-elements validates one .elmt file, or every .elmt under a
  directory (recursively), against the element schema: XML well-formed,
  root <definition type="element">, a usable bounding box, and terminal
  count. Reports OK / WARN / FAIL per file and a summary; exit code is
  non-zero if any file fails. Verified against the full bundled
  collection (8483 elements): 0 false failures, agreeing with QET's own
  loader (e.g. a negative-height element it tolerates is a WARN, not a
  FAIL).

run() is restructured to handle the differing argument arity (info takes
an optional output, check-elements takes a path rather than a project).
2026-06-11 23:23:13 +12:00
Kellermorph 08a441d1f6 Issues 482 2026-06-11 13:22:01 +02:00
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