ElementQueryWidget::queryStr() reads FROM element_nomenclature_view, and that
view already excludes flagged elements in its own WHERE clause (see
createElementNomenclatureView() in projectdatabase.cpp). This widget then
added a second condition on top: "exclude_from_bom IS NULL OR
exclude_from_bom != '1'" -- but nothing anywhere ever writes the literal
string "1" to this key (the only writer stores "true"/"false"), so the
clause was true for every row that could possibly reach this point and did
nothing.
Confirmed dead three separate ways while reviewing qelectrotech#765: reading
the value only ever comes back "true" or "false" (never "1"), an
exclude_from_bom="1" element still appeared in --export-bom output on a test
fixture, and the surrounding filter_ construction shows this AND'd clause
cannot change the query's result set regardless of what filter_ already
holds. Confirmed it a fourth way once already, by initially misreading this
same clause as evidence the feature was broken -- it was reading the WHERE
without the FROM three lines above, which is exactly the trap being removed
here for the next reader.
ElementQueryWidget backs the BOM export dialog and the diagram table
properties widget; neither has a headless CLI equivalent, so this could not
be verified end-to-end through --export-bom the way the case-insensitivity
fix could. Verified instead: the file compiles clean, and a
load/resave/--export-bom smoke test on examples/tremie_vibrante.qet shows no
change in app behaviour (98 components, matching the pre-change baseline --
expected, since --export-bom does not go through this widget at all).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Windows Qt5 build is going to be removed from CI/CD soon (Qt6/KF6
is becoming the sole supported track). Replace the 'experimental'
warning wording on the nightly download page and in the nightly
release body with a call to action inviting users to switch to Qt6
now and report issues, ahead of the Qt5 removal.
QPdfDocument::pagePointSize() (used for PDF page import) requires
Qt >= 6.4, and the QtPdf module itself is missing entirely on some
Qt6 distributions (e.g. the Flatpak org.kde.Platform runtime), since
it ships from the qtwebengine source tree rather than Qt6 core.
CMake: probe Pdf with find_package(... QUIET) instead of REQUIRED,
mirroring the existing GuiPrivate pattern. Define QET_HAS_QTPDF
only when the module is found AND Qt >= 6.4.
Replace the ad-hoc QT_VERSION_CHECK(6, 0, 0) / (6, 4, 0) guards in
qetdiagrameditor.cpp, diagrameventaddpdf.{h,cpp} and
pdfpagesdialog.{h,cpp} with #ifdef QET_HAS_QTPDF, so version and
module-availability checks live in one place.
Fixes the Flatpak build (missing Qt6Pdf) and the Windows/Debian CI
failures (QPdfDocument::pagePointSize undeclared on Qt < 6.4). The
PDF import toolbar action is now silently unavailable wherever
QtPdf isn't usable, instead of breaking the whole build.
Compiled into the binary but never instantiated -- searching the tree
for any reference outside its own three files finds nothing, and this
still holds on current master. Contains a latent bug that would be
user-visible if the widget were ever reachable
(on_tableDiagram_customContextMenuRequested compares QMenu::exec()'s
return value against one action but falls through to "select all" on
both the other action and on a plain dismiss, since exec() returns
nullptr on Escape/click-away and that's not equal to either QAction*),
which supports genuine disuse rather than temporary disconnection.
Removed the three files and their three explicit entries in
cmake/qet_compilation_vars.cmake (qelectrotech.pro globs sources/ui/*
so needs no change). Builds clean; no other file references
diagramselection.
Fixes#756.
m_jump_to_element was the only action in the tree that set its
QKeySequence directly instead of going through
ShortcutManager::registerAction() -- of 98 actions carrying a runtime
shortcut, 95 matched a registerAction() call, 2 were Qt built-ins, and
this was the sole exception (verified by dumping every QAction from a
running instance and cross-checking against a static scan of the
source; the only other setShortcut() call in the tree clears a
shortcut rather than setting one).
Bypassing the registry meant the binding didn't appear on the
Shortcuts preferences page (so it couldn't be discovered or rebound),
and checkConflicts() couldn't see it either, so assigning Ctrl+G to
another action there would silently collide at runtime instead of
being flagged.
Fixes#758.
- Add DPI selection (150/300/600) to the page selection dialog
- Add live page preview in the selection dialog
- Conditionally compile PDF import only for Qt6 (#if QT_VERSION)
- Add custom pdf-import icon (PDF document with + symbol)
- Register new icon in qelectrotech.qrc
- Qt5 builds: PDF import action is hidden, everything else works as before
The conductor table keyed on Terminal::uuid(), which comes from the catalog
.elmt definition and is empty for every element authored before that field
existed. A conductor was dropped unless *both* its terminals had one, so the
tables this slice adds were empty on almost every project in existence:
examples corpus conductor rows in the database
industrial.qet 0 of 671
affuteuse_250h.qet 0 of 263
tremie_vibrante.qet 0 of 77
741.qet 0 of 67
Across the 23 example projects, 16 of the 20 that contain conductors have
zero terminal uuids -- 2366 of 3002 conductors -- and overall coverage is
7.3%. Meanwhile --export-cables, already on master, lists all 671 conductors
of industrial.qet from the document. A feature that only works on newly
authored elements is not one users can rely on.
Terminal::stableUuid() returns the terminal's own uuid when it has one and
otherwise derives one from its local position and orientation inside its
element. That is not an invented scheme: it is what the project format
already does. TerminalData::fromXml() says so where it parses the field --
"if the attribute not exists, means, the element is created with an older
version of qet. So use the legacy approach to identify terminals" -- and the
legacy approach is the terminal's position. m_pos is read from the definition
and is not touched by moving the element on a folio, so the identity survives
loads, saves and folio moves. Derived values are UUID v5 in a fixed namespace,
so they are reproducible without being stored, and cannot collide with the v4
uuids the element editor generates.
Every project in the corpus now has exactly as many conductor rows as the
document has conductors -- 20 of 20 measured, 0 mismatches. (schema_indus.qet
is excluded: it blocks on a modal dialog at zero CPU under any CLI flag, the
pre-existing hang PR #661 addresses.)
Two things this deliberately does not key on:
- The terminal name. It is not stable: QET rewrites a terminal named "_" as
unnamed, which would have silently changed the identity of 1421 of
industrial.qet's 1790 terminals on their first resave. Measured across the
corpus, dropping it costs nothing -- geometry alone yields exactly the same
three collisions -- and it means renaming a terminal no longer changes what
it is.
- Uniqueness in the face of a definition that declares two terminals at the
same point and orientation. Three cases exist in the whole corpus. They
merge to a single terminal row, which is harmless: two terminals identical
in position and orientation are indistinguishable in every observable
respect, and every conductor on either still resolves to the right element
and terminal name. Both affected projects (industrial, perceuse) return
their full conductor count.
The only conductor still skipped is one whose terminal has no parent element,
which has no identity to key on at all.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three fixes to the tables added by this slice.
A conductor's text was written once at insert and never again. Renaming a
wire left the database holding the old number, so the wiring list showed a
stale value until the next full repopulate -- elements have
elementInfoChanged() for exactly this and conductors had nothing.
Conductor::setProperties() has around a dozen call sites (auto-numbering,
the properties dialog, element moves, the delete command's re-links), so
rather than adding a call to each and missing the ones added later, listen
to the propertiesChange() signal it already emits. Qt::UniqueConnection
means a repeated insert or a full repopulate cannot double-subscribe, and
the connection is established on both insert paths because conductors read
from a file never pass through addConductor().
addConductor() and populateConductorTable() each carried their own copy of
the same seven bindValue() lines. They had not drifted yet, but that is the
same duplication the element paths had before bindElementValues(), where
they had drifted -- one binding kindInformations()["type"] and the other
masterTypeToString(). One bindConductorValues() for both.
Finally, index the conductor columns that get looked up per element rather
than per conductor. element_nomenclature_view counts the wires touching each
element with a correlated subquery, so without an index every element row
full-scans the conductor table and the cost grows as elements x conductors.
Measured on a standalone SQLite harness at 2000 elements x 5000 conductors:
2134 ms unindexed, 10 ms indexed. diagram_uuid is indexed too, since the
wiring list view joins on it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Slice 2 of discussion #503 (from-to wiring list built on projectDataBase),
building on the conductor uuid from slice 1 (#625). Pure plumbing: two
new additive tables plus their populate/add/remove hooks. No view, no UI,
no visible behavior change yet -- the wiring-list view is slice 3.
Follows the existing shape of the class throughout: same table/column
naming, same prepared-statement idiom in prepareQuery(), same
bind/exec/qDebug-lastError error handling, same DELETE-then-loop
populate pattern.
- `terminal (uuid, element_uuid, name)` and
`conductor (uuid, diagram_uuid, terminal1_uuid, terminal1_element_uuid,
terminal2_uuid, terminal2_element_uuid, text)` created alongside the
existing tables in createDataBase().
- populateConductorTable() added as a fifth populate* call in updateDB().
Terminal population is folded into it, since a terminal only matters
here in the context of a conductor referencing it.
- addConductor()/removeConductor() hooked into the already-existing
Conductor::Type branch of Diagram::addItem()/removeItem(), mirroring
the Element::Type branch directly above.
Two things the original schema sketch in the discussion got wrong, found
by testing rather than inspection:
1. Terminal::uuid() is NOT unique per placed terminal. It is the
terminal-position id baked into the catalog .elmt definition ("the
top terminal"), so every placed instance of the same catalog element
shares it. A terminal instance is only uniquely identified by
(uuid, element_uuid) together, so that pair is the terminal table's
primary key and the conductor table carries both halves for each
endpoint. With uuid alone as PK, the second placed instance of any
element silently lost its terminals to the INSERT OR IGNORE.
2. Conductors whose terminals predate terminal uuids are omitted rather
than given a fabricated identity, as agreed in the discussion. This
turns out to matter far more than expected in practice -- see below.
Testing (all live, in the running app):
- Incremental add: fresh project, two vertically aligned contacts placed
so autoconnect creates a conductor -> 2 terminals, 1 conductor.
- Incremental remove: deleting that conductor -> conductor count 1 -> 0.
- Undo: ctrl+Z after the delete -> back to 1, no duplicate-primary-key
error (the same Conductor object keeps its uuid).
- Bulk populate: examples/weneedpolonez-Polonez_MR89_wiring_diagram.qet
(366 conductors) -> 478 terminals, 280 conductors; the 86 conductors
touching legacy terminals correctly omitted.
- Join correctness: conductor -> terminal (composite key) -> element_info
resolves real from-to rows with real element labels.
- Legacy-only project: examples/industrial.qet has 1794 terminals and
*zero* terminal uuids, so all 671 of its conductors are omitted. Loads
and renders fine, no crash, no spurious rows -- but worth stating
plainly that a from-to wiring list for that project would be empty
today. This is a property of the element catalog definitions, not of
the project file, and is the strongest argument for surfacing an
"N conductors excluded" count to the user when the view lands.
- No SQL errors logged in any of the above.
Known limitation, consistent with existing behavior: removeDiagram()
does not cascade-delete the conductor rows of that diagram, exactly as
it already does not cascade to element/element_info. A full updateDB()
rebuild clears them, and the future wiring-list view INNER JOINs from
conductor, so orphan terminal rows never surface.
ElementsPanelWidget::duplicateDiagram() round-trips the folio through XML
and then gives the copied *elements* fresh uuids, because element.uuid is
the primary key of the project database and a duplicate silently fails to
insert. Conductors now have the same problem and needed the same loop:
conductor.uuid is likewise a primary key, its insert is a plain INSERT
rather than INSERT OR IGNORE, and a failure only reaches qDebug(). Without
this, every wire on a duplicated folio is missing from the wiring list and
from the per-element wire count, with nothing shown to the user.
Verified against the real schema: inserting the same conductor uuid for a
second folio fails with "UNIQUE constraint failed: conductor.uuid", leaving
one row where two were expected.
Also harden the uuid read in Conductor::fromXml(). The default argument of
QDomElement::attribute() is evaluated whether or not the attribute exists,
so a uuid was minted for every conductor on every load and thrown away; and
the default only applies when the attribute is *absent*, so a present but
empty or malformed uuid="" parsed to a null QUuid rather than a fresh one --
and null uuids collide with each other exactly as duplicates do.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
During an ESEvent, the mouse position was used without format with
`snapToGrid` to display the coordinates. However, since the `helpCross`
is positioned using `snapToGrid` during these events, the displayed
coordinates did not match the `helpCross` position.
The command for sending the coordinates has been moved to the
`ESEventInterface` to function 'updateHelpCross' and now transmits the
position of the intersection point of the helpCross lines.
Replace the flat QTableWidget with a QTreeWidget that groups actions under
one collapsible top-level node per category. Fix the search box so it also
matches the current key sequence (exactly), accepts multi-keyword queries
(AND, any word order) and is accent-insensitive, auto-expands matching
groups and shows an "N actions" count. Add a quick filter (all / bound /
unbound / conflicts) that combines with the text query. Conflict detection,
per-row reset, reset-all and persistence are preserved.
Co-Authored-By: Claude <noreply@anthropic.com>