"Est il possible dans les raccourcis d'ajouter un pour création
automatique de conducteur ? Je n'utilise pas par défaut, mais
ponctuellement c'est très pratique." -- oc67, an electrician, on the
forum (viewtopic.php?pid=23296).
The action itself has existed for a long time: m_auto_conductor is a
checkable QAction in the Schéma toolbar and the Project menu. It was
simply never handed to ShortcutManager, so it did not appear in
Configuration > Raccourcis and there was no way to reach it from the
keyboard. This registers it.
No default sequence is set. That is the request read literally -- he
asked for it to be *in* the shortcuts list so he can bind it himself --
and it avoids spending one of the few free keys on a setting many people
never touch. The Shortcuts page already treats "no shortcut" as a normal
state: it renders an empty field and its quick filter can list actions
with and without a binding separately.
Verified on a virtual display. With shortcuts/diagrameditor.auto_conductor
set to Ctrl+Alt+A:
Configuration > Raccourcis, filtered on "conducteur", lists
"Création automatique de conducteur(s)" under "Éditeur de schémas"
showing that binding.
Mouse parked away from the toolbar, pressing it twice: the toolbar
button changes on each press and returns to its starting appearance
after the second, so the key toggles the setting exactly as clicking
the button does.
Two things that misled the first run, recorded so the next person does
not repeat them: F7 is already registered to panel.move_diagram_downx100
in the elements panel, and a screenshot taken with the pointer resting on
the button shows its hover state, not its checked state.
ctest 12/12, Qt 6.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CaKympWT3owLotCpEN2CFj
An electrician on the forum draws 400 V and 24 V circuits in the same
folio and wants the colour to be one click away
(qelectrotech.org/forum, viewtopic pid=23296). Today the quickest route
is F2, which opens a colour dialog and refuses to act unless exactly one
conductor is selected, so colouring a run means one conductor, one
dialog, at a time.
This adds a swatch button beside the auto-conductor actions. Picking a
colour does two things:
- recolours every conductor currently selected, as ONE undo step;
- becomes the colour of the next conductor drawn, through the
LastUsedStyle mechanism #888 already added and Conductor's
constructor already reads.
Either half is useful alone: with nothing selected it just sets the pen
for what comes next.
The menu lists the colours the trade names -- the three phases, neutral,
earth, and the ones used for control and extra-low-voltage circuits --
then any custom colours picked this session, then the full colour
dialog. A colour already in the standard list is not repeated under
"recently used".
Nothing is written to the project or to QSettings. That is deliberate:
it is the same session-scoped "what did I just use" idea as
LastUsedStyle, so it adds no persisted state and no file-format change.
Named presets stored per project -- what #461 actually asks for -- are a
larger feature that needs a maintainer decision first; the question is
still open on that issue since 21 June.
Verified on a virtual display against examples/Habitat-Schemas_developpes.qet,
reading colours back from the saved project rather than the screen:
select all on folio 1, pick Rouge
21 conductors {none:1, #ff5500:2, #ff0000:6, #00aa00:5, #0000ff:7}
-> all 21 #ff0000
one Ctrl+Z
-> back to the original five-colour mix, exactly
pick Marron with nothing selected, then draw a conductor
-> the new conductor is #7b3f00
ctest 12/12, Qt 6.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CaKympWT3owLotCpEN2CFj
QET had no icon theme: the 446 entries of the icon table and the 116
iconsets in .ui files each named a resource path, so an icon could only
ever be one file, and a variant for another palette or a vector source
had nowhere to go (GitHub #466, #690, #870). This adds the theme layout
without changing a single pixel; a dark variant comes in a follow-up.
The theme "qet" follows the freedesktop layout Qt's icon loader
understands. misc/make_icon_themes.py generates ico/icon-themes.qrc,
which aliases the existing ico/<size>/<name>.png files into
themes/qet/<size>/<name>.png, and ico/themes/qet/index.theme. No file
moves. The four table entries that paired a 16 pixel file with a 22
pixel file of another name (ConductorSettings, DiagramAdd,
DiagramDelete, DialogInformation) get the 22 pixel file aliased under
the 16 pixel name.
QETApp::initIconTheme() registers the theme before initIcons() and makes
it current on every platform, so a desktop icon theme cannot replace
QET's icons. Icons are then looked up by name: QIcon::fromTheme() in
qeticons.cpp and in the few places that built a QIcon from a resource
path directly, and theme="..." on the iconsets in .ui files, with the
resource path kept as fallback. Flags, color swatches, application and
MIME icons stay on their paths.
One entry does not go through the theme. The elements panel draws the
project root with ProjectFileGP in the 50 pixel slot it reserves for
element previews, and the name "project" also carries the 128 pixel
file the configuration dialog uses. On a 2x display Qt's loader picks
that file for a 50 pixel request and fills the slot. ProjectFileGP
loads the 16 and 22 pixel files directly, as before.
tests/qttest/tst_qeticons: every name in the theme resolves, the four
aliases resolve at 22 pixels, a Fusion tool button shows its icon at
3:1 with disabled weaker than enabled, and the project root icon stays
at 22 pixels or less when asked for 50 at 2x while the configuration
dialog still gets its 128 pixel file. The rendering helpers shared
with tst_qetpalette moved to tests/qttest/inkcontrast.h.
a) paste
- conductor does not move
- pressing escape does not abort
- pressing anything during the process crashes the program instead of aborting
b) similar issue with the escape not working fixed for graphics items, texxt fields (and probably others)
- Element::reloadPicture() now returns a ReloadPictureResult and never
clears the current drawing before a successful rebuild: a missing or
unreadable definition leaves the element as it was instead of blank.
- Elements whose size, hotspot or terminals (added, removed or moved)
differ from the new definition are not redrawn: the new drawing would
no longer match their bounding rect and live terminals.
- The action lists those elements and warns that they must be removed
and re-inserted, which deletes the conductors already connected to
them.
- Status tip states the action is not undoable.
Extends the scripting surface from the previous commit with exactly
the three things explicitly scoped out there, per follow-up direction:
editing geometry, undo integration, and driving the GUI -- the last
one narrowed to select/zoom/message after discussion, since "invoke
any menu action by name" would let a script trigger a modal
QDialog::exec() with nobody there to dismiss it, the same hang class
investigated for bugtracker #882.
## New capabilities
- addElement/setElementPosition/moveElement/deleteElement, through the
same undo commands the GUI itself uses: AddGraphicsObjectCommand
(the same one drag-from-collection-panel placement uses),
QPropertyUndoCommand on the standard `pos` property, and
DeleteQGraphicsItemCommand (refuses a non-deletable terminal, same
as the Delete key).
- undo/redo/canUndo/canRedo against the project's real QUndoStack --
the same one QETDiagramEditor's Ctrl+Z is wired to via
undo_group.activeStack(), not a parallel mechanism.
- selectElement/deselectAll (scene state, no view required -- works
headless), zoomFit/zoomToContent/zoomReset (need the active
DiagramView, so false headless where there is nothing to zoom), and
showMessage (a modal QET::QetMessageBox::information -- safe headless
because non-interactive mode is already on for the whole process
before any script runs).
## Two real bugs caught by testing this, not assumed away
1. save() was still going through the same reopen-from-disk path as
every export method: it opened a *second*, unmodified copy of the
project from its file on disk and rewrote that. addElement() and
friends operate on the live in-memory project, so nothing they did
ever reached the saved file -- an element counted correctly in
memory and then silently vanished from the output. Fixed by having
save() write m_project->toXml() directly, the only method that
touches the live instance rather than a fresh copy of the file.
2. A script calling setElementPosition() then moveElement() on the
same element produced a saved position that didn't match either
call, and undo/redo didn't step through them independently. Traced
to QPropertyUndoCommand::mergeWith() (pre-existing, not new):
consecutive commands on the same object+property merge when their
text() also matches, and both calls build the identical "Déplacer
%1" text for a given element -- exactly the same collapsing
dragging an item repeatedly gets. Not a bug in the new code; a
wrong assumption in the first test. Re-verified against the
correct, merge-aware expectation: add -> merged move -> undo (back
to first position) -> undo (element removed) -> redo (element back)
-> redo (merged move reapplied) landed at the exact predicted final
position, read back from the saved XML.
## Verified
Qt6, build clean from a fresh reconfigure, ctest 6/6.
- Headless: addElement returns a real uuid and the count updates;
select/set-position/move all report correctly; the merge-aware
undo/redo/save round trip above, confirmed against the saved file's
actual XML, not just in-memory counters.
- Corpus: the existing read-model smoke script re-run against all 24
shipped example projects on the fixed binary, 0 failures.
- zoomFit correctly returns false headless (no view to act on),
confirming the "narrowed GUI-driving" scope holds in code, not just
in the doc comment.
- GUI: running the add-only script via "Exécuter un script..." marked
the project [modifié] in the title bar, the same change-tracking
path a manual edit goes through -- consistent with the undo command
actually being pushed onto the project's real stack rather than some
side channel invisible to the rest of the application.
Refs #162.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Following up on my own comments there: a deliberately small, mostly
read-only scripting surface, exposed to scripts as a single global
`qet` object (QetScriptApi) built on QJSEngine rather than an embedded
Python interpreter -- no new toolchain to package (QJSEngine ships in
every Qt SDK QET already targets, via the Qml module), no GIL, no
version pinning, automatic reflection of the QObject-derived core
classes' own methods with no hand-written binding layer.
## What a script can do
- Read the model: project title, file path, folio count/titles,
element/conductor counts per folio.
- Trigger the same operations the --export-* CLI flags already do
(pdf/png/svg/cables/wires/bom/wiring/nets/links/info), plus
set-titleblock and save -- thin wrappers around CLIExport::run(),
reusing its already-tested logic rather than duplicating it.
Deliberately NOT in this version: creating or editing diagram
geometry, undo integration, driving the GUI. All explicitly out of
scope per the discussion on #162.
## Two entry points, both built and tested
- `qelectrotech --run script.js project.qet` -- headless/CI.
- Projet > "Exécuter un script..." -- an interactive macro against the
currently open project. Export/save calls act on the project's file
on disk (see QetScriptApi's class comment for why), so unsaved GUI
edits aren't visible to the script; save first if that matters.
## Optional dependency, not a hard requirement
Qt::Qml is probed the same way QtPdf already is in this codebase:
QUIET, non-fatal, behind a QET_HAS_SCRIPTING compile definition. A
build without it compiles and links identically; the CLI flag and
menu action are simply absent (main.cpp) or compile to a clear
"not available" stderr message rather than silently disappearing
(qetscripting.cpp), matching the existing QtPdf pattern rather than
introducing a new one.
One real bug caught building this, not assumed away: my first pass
conditionally excluded the new source files from QET_SRC_FILES behind
`if(QET_HAS_SCRIPTING)` inside qet_compilation_vars.cmake -- but that
file is included before QET_HAS_SCRIPTING is set in the top-level
CMakeLists.txt, so the variable didn't exist yet at that point and the
files were silently never compiled, only caught by an undefined-symbol
link error. Fixed by following the QtPdf file's own precedent:
compile the files unconditionally, guard their Qt::Qml-dependent
content internally instead.
## Verified
Qt6, build clean, ctest 6/6.
- Headless: a script reading project/folio/element/conductor counts,
calling exportInfo() and exportPdf() against a real project --
correct JSON, a real single-page PDF confirmed with `file`.
Error paths: a thrown script exception reports file:line:message and
exit 1; missing script/project arguments exit 2 (matching
CLIExport's own usage-error convention); a missing project file is
reported and does not hang.
- Corpus: the same read-model script run against all 24 shipped
example projects, 0 failures.
- GUI: "Exécuter un script..." opens a real file dialog filtered to
*.js, running the picked script against the live open project
produced the exact expected JSON export file, and the application
was still fully responsive afterward.
Refs #162.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A placed element is drawn once from its definition at construction --
buildFromXml() only turns terminal/input/dynamic_text tags into live
child objects, every other primitive (line, rect, ellipse, polygon,
arc, text) is pre-rendered into a QPicture by ElementPictureFactory,
cached forever under the element's uuid with no invalidation path
anywhere in the codebase. Edit and save a symbol's drawing and every
already-placed instance keeps showing the old one until the project
is closed and reopened.
Fix, scoped to what is safe to do without ever risking a conductor or
a dynamic text's per-instance state:
- ElementPictureFactory::dropCache(location) forgets the cached
drawing for one location, so the next fetch rebuilds it from the
definition's current content.
- Element::reloadPicture() re-fetches and repaints one instance.
- Projet > "Recharger les dessins des éléments": walks every diagram,
drops each distinct location's cache once, then reloads every placed
instance.
Deliberately does not touch terminals or dynamic texts -- a definition
whose terminal positions moved still needs the existing remove-and-
reinsert workflow, since terminals are what conductors are attached to
and a wrong guess there would silently misconnect wires.
Verified: build clean, ctest 6/6. Triggered the new action on a real,
densely-wired project (76 elements) via exact keyboard-menu navigation
cross-checked against the menu's own addAction order -- ran to
completion, correct confirmation dialog, no crash, diagram unchanged
and uncorrupted afterward. Could not complete a live edit-and-watch-
it-update trace: opening the element editor on a selected item via
GUI automation was unreliable in this environment (same class of
friction as PR #888), and this sandbox has no file-based (common://)
element to mutate on disk as a shortcut -- every example project
embeds its elements. The mechanism itself is traced correct:
ElementsLocation::xml() for an embed:// location reads the project's
live in-memory collection DOM on every call, so a dropped cache
rebuilds from whatever was most recently saved.
Refs #802 (own analysis comment, 2026-08-31).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ctrl+V pasted in place, which put the copy exactly on top of the original.
Nothing appeared to happen: the only clue was a doubled outline, and the
copy had to be dragged off the original to be seen at all. The cursor was
ignored entirely.
Ctrl+V now starts a placement. The items appear under the cursor and follow
it until a left click or Return drops them; Escape or a right click takes
them away again. That is the same interaction as placing a new element, so
paste behaves like every other way of putting something on a folio, and the
copy lands where the user is looking.
Implemented as a DiagramEventInterface beside the existing add-element and
add-macro tools. The pasted items are the real ones from the start rather
than a preview: Diagram::fromXml creates them exactly as before, this class
moves them, and PasteDiagramCommand is pushed only once they are dropped.
PasteDiagramCommand's first redo() deliberately does not add items to the
scene -- it assumes fromXml already did -- so pushing it on commit adopts
them rather than duplicating them. One copy of the paste logic, and a
cancelled paste leaves nothing on the undo stack.
Conductors are not moved directly; they are drawn from their terminals and
follow the elements they attach to. On cancel they are removed before the
elements, so none is left in the scene holding a pointer to a freed
terminal.
Verified by counting elements in the saved file rather than by eye:
56 to start, 56 after paste-then-Escape, 57 after paste-then-drop, and 56
again after undo. Save determinism run against this build: pass, no
regressions against baseline. Tests 5/5 on Qt 6.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The nine "Ajouter" actions -- text field, image, PDF, line, rectangle,
ellipse, polyline, curve, terminal strip -- were only ever added to
m_add_item_tool_bar, and the automatic conductor break only to
diagram_tool_bar. None carried a shortcut. A toolbar button has no key,
so someone working without a mouse could not add anything at all to a
folio.
They now appear in an "Ajouter" submenu under Édition, and the conductor
break beside m_auto_conductor in Projet, the setting it pairs with. The
actions themselves are untouched: a QAction can sit in a menu and a
toolbar at once, which is what m_depth_action_group -- created a few lines
away, and added to both its toolbar and menu_edition -- has always done.
That contrast is why this reads as an oversight rather than a decision.
Verified by driving the menus with the keyboard alone under Xvfb: Alt+F
opens the File menu, Down then Right crosses to Édition, and Right again
opens the Ajouter submenu with all eight actions this build compiles
(add_pdf is behind QET_HAS_QTPDF and absent on Qt 5).
Found with tools/keyboard-audit in the qelectrotech-docker harness, which
reports these ten and now reports none.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This branch was cut on 31 July, one day before ShortcutManager landed
in 5275fb44f, so the two actions it adds were written before the
convention existed and are the only members of the selection group not
registered: select_all, select_nothing and select_invert all are.
Without this they never appear in the shortcuts configuration page, so
a user cannot bind a key to either of them.
Registered with an empty default sequence. They are menu actions and
neither has an obvious default worth claiming; the point of registering
them is that a user can bind one if they want. ShortcutManager stores
an empty default without setting a shortcut, and the conflict checker
already skips empty sequences.
Master merged in first, because ShortcutManager does not exist at this
branch's original base.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Implements the second pillar of #574: keyboard-driven selection on the
diagram canvas.
Tab / Shift+Tab select the next / previous item on the current
diagram, cycling through items() (z-order) and wrapping at either
end. If nothing is selected, Tab selects the first item and
Shift+Tab the last. Skipped while a text item has focus, for the
same reason arrow-key movement already guards on !focusItem().
Candidates use the same "what counts as a real selectable diagram
item" filter (QetGraphicsItem / DiagramTextItem / Conductor) already
established by Diagram::invertSelection(), so the cycling order
always matches what a user could reach by clicking.
Getting Tab to actually reach the scene needed two separate fixes,
each independently discovered by empirical testing rather than
assumption:
- QWidget (DiagramView) intercepts Tab/Backtab for widget focus-chain
traversal before generating a key event at all. Overriding
DiagramView::focusNextPrevChild() to return false disables that.
- QGraphicsScene (Diagram) has its own, separate item-focus-chain
traversal, checked before keyPressEvent() is ever reached. The
obvious fix -- overriding Diagram::focusNextPrevChild() the same
way -- silently does nothing on Qt 5, because
QGraphicsScene::focusNextPrevChild() only becomes virtual in Qt 6
(guarded by the QT6_VIRTUAL macro); a compile error surfaced this
immediately when attempted directly, rather than shipping a fix
that worked on Qt 6 and silently no-opped on Qt 5. Intercepting
QEvent::KeyPress in Diagram::event() instead is virtual on every Qt
version and sidesteps the scene's internal traversal entirely.
Also adds Diagram::selectAllConductors() / selectAllTextFields(),
wired up as two new actions in the existing select_all /
select_nothing / select_invert action group in
qetdiagrameditor.cpp, so they appear in the Edit menu and go through
the same QAction -> data() -> selectGroupTriggered() dispatch as the
existing selection commands.
Verified end-to-end in a real running session (Xvfb + xdotool) with
a multi-transistor schematic: Tab/Shift+Tab correctly move a single
selection forward/backward through elements and text fields
(confirmed via the properties panel updating to each new item and
the visual selection box moving on canvas); Tab/Shift+Tab from no
selection correctly select the first/last item; "Select all
conductors" and "Select all text fields" each correctly select every
matching item and deselect everything else.
See discussion #574.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The File > Recently-opened submenu was filled once, at editor construction,
by copying the QActions that RecentFiles' menu happened to hold at that
moment:
recentfile->addActions(QETApp::projectsRecentFiles()->menu()->actions());
RecentFiles::buildMenu() runs on every fileWasOpened(), clears its menu and
creates fresh QActions. The editor's copy therefore never gained an entry,
and the list only ever looked correct after a restart.
The submenu is now the RecentFiles menu itself. QMenu::addMenu() adds the
submenu's menuAction() rather than reparenting it, so several editor windows
can share the one live menu, which is what an application-wide recent-files
list should do anyway.
Measured with a temporary probe comparing the live menu against what the
File menu actually shows, after one file had been opened in the same
session:
without the fix live=1 shownInFileMenu=0
with the fix live=1 shownInFileMenu=1
ctest 4/4, GUI starts clean with the menu bar intact. Qt 5.15.18.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
- Remove dead #if QT_VERSION conditionals (both branches were identical)
- Add settings.remove() guard on restoreState() failure consistently
across all three editors (now safe since all run after show())
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.
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
Slice 4 of discussion #503, on top of slice 3 (#629): the smallest
surface that makes wiring_list_view visible, plus the diagnostic the
view needs to be honest about what it is missing.
Projet > "Liste de câblage (base de données)" opens a read-only table of
wiring_list_view, headed by a line stating how many conductors are
listed and, when non-zero, how many were excluded and why.
Deliberately not another exporter. QET already ships a wiring-list CSV
export (Projet > Exporter le plan de câblage, and --export-cables) which
walks the project XML; measured on the same projects it produces a row
per conductor and resolves labels correctly when the project has them.
Adding a second, competing CSV would be worse, not better -- the
database path's value is what it unlocks (terminal plans, BOM joins),
not replacing that export.
projectDataBase::excludedConductorCount() counts, from the live scene,
the conductors deliberately absent from the conductor table because a
terminal has no uuid. Counted from the scene precisely because the
database is where those conductors are not. Verified: 671 on
examples/industrial.qet (which has 1794 terminals and no terminal uuids
at all, so its list is empty and now says so), 0 on a project whose
elements do carry terminal uuids.
KNOWN GAP, not fixed here and the reason this is opened for discussion
rather than merge: after a save/reload the component columns are blank
for slave elements. populateElementTable()/populateElementInfoTable()
only insert Simple|Terminal|Master|Thumbnail, so slave elements -- relay
contacts, i.e. a large share of real wire endpoints -- have no row in
element_info for the view to read a label from. Measured on a two-slave-
contact project after reload: element rows 0, element_info rows 0,
terminal rows 2, conductor rows 1; the wire is listed (slice 3's LEFT
JOIN keeps it) but both component names are empty, where the existing
CSV export shows K1 -> K2 for the same file.
Closing that gap means widening a filter shared with the nomenclature
and summary views, which would change what those existing, shipped
features contain. That is a maintainer decision, not one to take
unilaterally inside an additive slice.
a) using a system provided KF6
b) downloading and compiling KF6
c) using the vendored-in re-creation of the functionality
The behaviour for both Qt5 and Qt6 is steered with the same two variables which were renamed to become version agnostic:
a) BUILD_WITH_KF=ON BUILD_KF=OFF
b) BUILD_WITH_KF=ON BUILD_KF=ON
c) BUILD_WITH_KF=OFF
The version is automatically derived from the chosen Qt major version.
QETDiagramEditor::openBackupFiles() deleted the just-constructed
QETProject when it failed to reach ProjectState::Ok, but had no
continue/else after the delete - so addProject(project) ran
unconditionally on the now-dangling pointer, and addProject()
immediately dereferences it (new ProjectView(project), etc.).
This matches the report exactly: clicking Cancel on the restore-files
dialog (which just deletes the stale markers directly, never calling
openBackupFiles()) works fine, while clicking OK crashes whenever any
listed backup fails to open cleanly. Because the crash happens mid-
loop, cleanup for that file (and any later ones in the same batch)
never completes, which also explains the reporter's second complaint
that the restore list kept growing across sessions.
Fix: add the missing `continue` so a failed project is skipped
instead of being passed use-after-free to addProject().
Verified: clean rebuild, only the intended object file recompiled
and linked successfully. I attempted a live repro by crafting a
malformed stale-file marker to force ProjectState != Ok and clicking
OK under Xvfb, but this local build links against real KDE Frameworks
(BUILD_WITH_KF5=ON, confirmed via CMakeCache.txt) rather than the
in-tree nokde/kautosavefile.cpp reimplementation I initially targeted,
which uses a different marker directory/naming scheme
(~/.local/share/stalefiles/<app>/ via real KF5::KAutoSaveFile) that
I wasn't able to reverse-engineer well enough in the time available
to produce a matching malformed marker. Confidence in the fix instead
rests on the code being an unambiguous, textbook use-after-free (this
exact object is deleted on the line immediately above the missing
continue) with a single-line, side-effect-free fix.
etc.), these three are ambiguous on the *slot* side:
activateProject(QETProject*)/activateProject(ProjectView*),
closeProject(ProjectView*)/closeProject(QETProject*), and
showError(const QETResult&)/showError(const QString&) each have two declarations on QETDiagramEditor. &QETDiagramEditor::activateProject
etc. alone won't compile with two candidates present; qOverload<T>() picks the one matching the actual signal's argument type, same as
the old SIGNAL()/SLOT() macro text did implicitly.