Second of @scorpio810's review notes on #630:
exportWiring() follows the existing CLI exporters (QTextStream, plain
QFile). On Qt6 the output is UTF-8, so encoding is fine. Once #830 is
in, it could optionally reuse BomExport::writeCsv() to get a BOM,
which Excel needs to detect UTF-8 when opening the file directly, and
an atomic write.
Done directly rather than waiting on #830, since neither half depends on
it and both are small.
The bytes were already UTF-8; what was missing is the mark that tells
Excel so. Opening a .csv without one, Excel falls back to the local
8-bit codepage and mangles any accented element label -- the common case
for this project's users.
QSaveFile replaces QFile so a failure part-way through leaves the
previous file intact instead of a truncated one. QSaveFile is already the
codebase's pattern for this (QET::writeToFile, qet.cpp:664).
Verified on perceuse.qet: output now starts ef bb bf, the header follows
intact, all 156 rows are preserved, and the file parses as utf-8-sig.
Pointing the exporter at a missing project leaves an existing target file
untouched, where before it would have been truncated.
Left the other CLI exporters alone. They share the same pattern, but
changing exportBom() would add a BOM to output that existing scripts
already consume, which is a behaviour change outside the scope of this
review note.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Follows @scorpio810's review note on merging #630:
ORDER BY diagram_position, wire_number sorts wire numbers as text,
so "10" comes before "9".
Confirmed against the corpus: perceuse.qet put 111 before 12, and
affuteuse_250h.qet put 45 before 5. industrial.qet happened to look
correct only because its wire numbers are all the same width.
Wire numbers are free text and are not always numeric -- perceuse.qet
also carries an unresolved "%sequ_1" -- so the ordering has to cope with
both. Numeric values come first, ordered by value; anything else follows,
ordered as text. The trailing wire_number keeps ties stable.
Fixed in both places the query appears: the CLI exporter and the wiring
list dialog. They had the same ORDER BY, so fixing only one would have
made the dialog and --export-wiring disagree about the order of the same
data.
Verified on perceuse, affuteuse_250h, industrial and tremie_vibrante:
zero out-of-order numeric pairs afterwards, row counts unchanged, and
"%sequ_1" now sorts after the numbers rather than among them. Folio 3 of
perceuse.qet reads 0 1 2 3 4 4 5 5 6 6 7 7 12 12 where it previously
interleaved 111 before 12.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The wiring_list_view added by this slice was only reachable through the GUI,
which meant the one thing worth proving about it -- that it still describes
the project -- could not be checked without a person clicking. This is the
same shape as the existing --export-bom, which reads
element_nomenclature_view, and it makes the view verifiable in CI.
It also makes this slice useful on its own: a from-to wiring list is a thing
people want as a CSV, and it no longer waits on the dialog in the next slice.
There is deliberately an overlap with --export-cables, which produces the same
logical list from the document XML rather than the database. Keeping both is
the point: running them and diffing them is a direct check that the cache and
the document still agree, which nothing else in the codebase can do.
Measured on the example corpus, the two also differ in what they can actually
fill in. Rows carrying any endpoint data:
--export-cables --export-wiring
industrial.qet 0 / 671 541 / 671
m_000.qet 0 / 457 362 / 457
affuteuse_250h.qet 0 / 263 197 / 263
tremie_vibrante.qet 0 / 77 61 / 77
tableau_domestique.qet 58 / 130 104 / 130
Both return a row per conductor; the XML-derived one leaves the component and
terminal columns empty on the older projects, and emits an unresolved "%id"
in its folio column. That is not an argument for removing it -- it carries
columns the view does not, and it is the independent second opinion -- but it
does mean the database path is the one with the data on the projects people
actually have.
The terminal-name columns come back empty on most projects. That is absent
source data, not a loss in transit: tableau_domestique.qet has no terminal
name on 457 of 457 terminals, and industrial.qet stores the "_" placeholder
on 1421 of 1790.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Terminal::paint() draws the red terminal stroke, the blue docking dot
and the terminal name whenever the diagram's drawTerminals() /
drawTerminalNames() flags are set, and both default to true. The GUI
export dialog clears them through Diagram::applyProperties(), but the
headless CLI export (--export-pdf/--export-png/--export-svg) never
did, so every terminal shipped as coloured editor UI in otherwise
finished drawings.
Toggle both flags off around the render in renderDiagram(), exactly
like the existing grid/guides handling, and restore them afterwards.
Three deprecated APIs have replacements that only exist in newer Qt6:
- QLocale::nativeCountryName() -> nativeTerritoryName() (Qt 6.2)
- QDomDocument::setContent() overload -> ParseResult (Qt 6.5)
- qt_ntfs_permission_lookup -> QNtfsPermissionCheckGuard RAII (Qt 6.6)
Each is wrapped in QT_VERSION_CHECK so Qt5 keeps the old path. Clears
4 -Wdeprecated-declarations warnings.
The first write-to-project CLI command, aimed at CI / revision workflows:
stamp title-block metadata onto every folio (and the project default),
then save. Each argument is key=value:
qelectrotech --set-titleblock in.qet out.qet revision=B date=today
Standard keys map to the documented title-block fields (title, author,
date, plant, location, revision, version, filename); date=today uses the
current date and an explicit date forces UseDateValue mode; any other key
is stored as a custom title-block field. Assignments are parsed up front
so a malformed one fails before writing.
Addresses the 'saving' side of the CLI-for-scripts request (#162).
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.
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.
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).
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>
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".
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.