Commit Graph

8650 Commits

Author SHA1 Message Date
Laurent Trinques 98c56fcc7b Merge pull request #590 from ispyisail/feature-folio-undo-redo
Add undo/redo support for folio add, delete, and reorder
2026-08-01 07:09:57 +02:00
ispyisail 55886e5e8a Add undo/redo support for folio add, delete, and reorder (#575)
Three new QUndoCommand subclasses (AddDiagramCommand, RemoveDiagramCommand,
MoveDiagramCommand) pushed onto the project's existing (already
project-scoped) undo stack, so folio structure edits are undoable
alongside every item-level edit already on that stack.

- QETProject::addDiagram()/detachDiagram() are the shared attach/detach
  primitives: they mutate the diagram list, connect/disconnect the two
  per-diagram signals set up at add time, and emit diagramAdded/
  diagramRemoved. AddDiagramCommand and RemoveDiagramCommand call these
  (via friend access) for both redo and undo, so a removed diagram is
  parked rather than destroyed -- it's only actually deleted if the
  command itself falls out of undo history while still detached.
- ProjectView reacts to diagramRemoved the same way it already reacted to
  diagramAdded (tearing down/rebuilding the tab), so both directions of
  both commands go through the same reactive path every other diagram
  listener (project database, cross-references, generic panel) already
  relies on.
- MoveDiagramCommand wraps a new ProjectView::setDiagramPosition(), which
  performs the tab move and the project's diagramOrderChanged() list
  reorder synchronously in one step, instead of relying on the queued
  tabMoved connection (needed for interactive drag-and-drop) to catch up
  later -- avoiding a second, redundant reorder from that queued call.
- Multi-folio delete and multi-folio move (QETDiagramEditor::removeDiagrams()
  and the moveDiagram*(QList<Diagram*>) batch slots) wrap their per-diagram
  loop in QUndoStack::beginMacro()/endMacro(), so a multi-select action is
  one undo step, matching current UX.
- Softened the delete confirmation's "this change is irreversible" wording
  now that it no longer is.

Verified headlessly (Xvfb + xdotool + scrot): add/undo/redo, delete/undo/
redo (single and multi-select, single undo step for the batch), and
move/undo/redo all behave correctly against a 7-folio project.
2026-08-01 17:03:39 +12:00
Laurent Trinques c772e1d3ea Merge pull request #589 from ispyisail/feature-element-editor-coord-readout
Add live cursor-coordinate readout to the element editor status bar
2026-08-01 05:59:23 +02:00
ispyisail 9637f0ff9e Add live cursor-coordinate readout to the element editor status bar (#580)
Displays the cursor's scene position (same grid units as the parts'
X/Y property spinboxes) in a permanent status bar label, updated on
every mouse move. Addresses the overlapping-node mis-click case from
the originating forum report: with a live readout, precise pointing
no longer requires guessing against nearby z-ordered points.

ElementScene::mouseMoveEvent already computed the (optionally
grid-snapped) scene position on every move; it now also emits it via
a new mouseMoved(QPointF) signal, which QETElementEditor's status bar
label subscribes to.
2026-08-01 15:12:44 +12:00
Laurent Trinques 031441884a Merge pull request #584 from ispyisail/fix-potential-selector-cancel
Fix: potential-selector dialog can't actually be cancelled (#581)
2026-07-31 10:49:54 +02:00
ispyisail 68e75b4c55 Fix: potential-selector dialog can't actually be cancelled (#581)
PotentialSelectorDialog::chosenProperties() built an OK-only dialog
and discarded exec()'s return value entirely:

    dialog.exec();
    for (QRadioButton *b : H.keys()) {
        if (b->isChecked()) return H.value(b);
    }
    return ConductorProperties();

Escape and the window close button already trigger QDialog::reject()
on a plain QDialog, but since the result was never checked, dismissing
the dialog without picking anything just silently returned blank
ConductorProperties() -- the same value returned when a real potential
was chosen but happened to produce empty properties. There was no way
to distinguish "the user cancelled" from "the user chose an empty
potential", so the caller always proceeded as if a choice had been
made.

Add a real Cancel button, check dialog.exec() == QDialog::Accepted,
and report cancellation through a new optional `bool *cancelled`
out-parameter. Also pre-select the first entry, closing a related gap
where clicking OK without ever touching a radio button hit the exact
same "silently returns blank properties" failure mode.

Thread the result through ConductorCreator::setUpPropertieToUse()
(now returning bool) so the calling constructor aborts and creates no
conductors at all when the user cancels, instead of proceeding with
blank properties.

The sibling constructor-based PotentialSelectorDialog (used for
conductor/report potential linking, a separate flow) already gates its
side effects behind on_buttonBox_accepted(), so cancelling it was
already safe -- gave it a visible Cancel button too for consistency
while touching this file, no behavior change there.

Verified with real Qt event simulation (QTest::mouseClick/keyClick)
against the exact new dialog-building logic: clicking Cancel and
pressing Escape both correctly report cancellation with empty
properties; clicking OK untouched returns the pre-selected first
entry; selecting the second option then OK returns that selection.

See discussion #581.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 20:39:04 +12:00
Laurent Trinques 46cceb328e Merge pull request #582 from DieterMayerOSS/pr/font-legacy-format
Write font descriptions in a version-stable format (#553)
2026-07-31 10:30:49 +02:00
Laurent Trinques 8793df4c86 Update translations files 2026-07-31 09:55:17 +02:00
Laurent Trinques 717c89fa66 Merge pull request #562 from Kellermorph/PLC-Manager
PLC Manager
2026-07-31 09:05:30 +02:00
Laurent Trinques 1836bce7e1 Merge pull request #583 from ispyisail/feature-project-usage-timer
Add a local, per-project time-spent tracker
2026-07-31 08:58:33 +02:00
Dieter Mayer 68ffacc9e6 Salvage font descriptions written by Qt 6.11+ when parsing fails
QFont::fromString() of Qt 5.x and Qt <= 6.10 rejects the >= 19 field
descriptions QFont::toString() emits since Qt 6.11, silently leaving a
broken font at every read site. Add QETUtils::fontFromString(): try the
native parser first, and on failure re-compose the legacy 10/11 field
form from the known Qt 6.11 field layout (OpenType weight mapped back
to the legacy scale) so no font information stored in existing files is
lost. Also salvage the 21 field double-serialized descriptions left
behind by some historical builds (a complete legacy description
embedded as the family name of a second one) by taking the embedded
leading description, matching what the lenient parser of Qt 6.11+
resolves them to. All font read sites now go through the helper; on
failure the default font of the caller is left untouched instead of a
cleared family.

Verified end to end on a Qt 5.15 build: a project whose 53 font
attributes were rewritten into the 19 field Qt 6.11 format loads and
autosaves byte-identical to the original legacy file (family, sizes,
bold/italic/underline, style name all preserved), and a mixed file
containing the exact 21 field string from the issue comes back
normalized as "Caladea,9,-1,5,75,1,0,0,0,0,Bold Italic".

See issue #553.
2026-07-31 08:10:34 +02:00
ispyisail 464d516537 Add a local, per-project time-spent tracker (#576)
Adds a ProjectUsageTracker (sources/project/) that accumulates how
long a project has been the active tab, using QElapsedTimer so the
value is computed on demand rather than via polling. It's hosted on
ProjectPropertiesHandler per that class's own stated design intent
("all new properties should be managed by this class").

The accumulated time is persisted as a new <usage time_spent="N"
enabled="true|false"/> element, a sibling of <properties> in the
project XML, written/read by new QETProject::writeUsageXml()/
readUsageXml(). It rides along on the existing autosave path for
free, since writeBackup() already serializes the full project via
toXml().

QETDiagramEditor::subWindowActivated() now pauses every open
project's tracker except the one whose tab just became current, so
switching between several open projects keeps each project's tracked
time isolated.

Surfaced in the existing Project Properties "Général" page: a
"Temps passé sur ce projet" display, a "Réinitialiser" button, and
an opt-out checkbox ("uniquement enregistré localement dans ce
fichier" - this is local-only, never transmitted anywhere).

Verified beyond compiling: full CMake build, then an actual runtime
session confirming the saved XML's time_spent value, that closing
and reopening the project round-trips and resumes timing, that the
reset button works, and - the key correctness check - that with two
projects open, the inactive one's time_spent stays frozen while the
active one accumulates real elapsed time, over the same interval.

See discussion #576.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 09:52:32 +12:00
Dieter Mayer 5da1fe5fc8 Write font descriptions in the stable Qt 5 10/11-field format
QFont::toString() is not stable across Qt versions: Qt 6.11 switched to
a 19-field format carrying OpenType weights, which QFont::fromString()
of Qt 5.x and Qt <= 6.10 rejects, leaving a broken font. Projects saved
by a Qt 6.11+ build were therefore unreadable by older builds.

Add QETUtils::fontToString() composing the legacy 10/11-field
description (weight mapped back to the legacy scale with the same
closest-match table Qt uses when parsing) and use it at every site that
stores a font description in a project, element, table config or
settings file. Every Qt version from 5.15 through 6.12-beta parses this
form correctly, so files stay readable by every QET build in
circulation.

See issue #553.
2026-07-30 21:45:36 +02:00
Laurent Trinques 120ca08209 Merge pull request #571 from DieterMayerOSS/pr/element-panel-tooltip
Element panel: show name and element information in the tooltip
2026-07-30 11:33:44 +02:00
Laurent Trinques 92f63d7b3c Merge pull request #573 from ispyisail/fix-dynamictext-drag-select
Fix #487: drag-selecting dynamic text fields silently converts their text source
2026-07-30 11:28:22 +02:00
Laurent Trinques c09a8f918f Merge pull request #572 from ispyisail/fix-titleblock-empty-var-override
Fix #531: page-level empty title block variable no longer shadows project-level value
2026-07-30 11:24:16 +02:00
ispyisail b60e73d93b Fix #487: drag-selecting dynamic text fields silently converts their text source
updateForm() called on_m_text_from_cb_activated() directly, intending
only to enable the sibling widget matching the combo box's current
index ("For enable the good widget"). But that slot also loops over
every currently selected part and pushes an undo command overwriting
textFrom on any part that doesn't match, since it's normally only
reached via the combo box's own activated(int) signal (real user
interaction, never fired by programmatic setCurrentIndex()).

updateForm() runs on every selection change, so during a rubber-band
drag over dynamic text fields with different sources, each time a new
field enters the selection, the representative part's textFrom gets
force-applied to every other selected part - converting e.g. a
UserText field to ElementInfo mid-drag, before the user has released
the mouse or interacted with the combo box at all.

Split the cosmetic widget-enable logic into updateTextFromWidgetsEnabled(),
called from updateForm(). on_m_text_from_cb_activated() keeps the
part-mutating loop, now only reached from real user activation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 19:11:25 +12:00
ispyisail f9357e269b Fix #531: page-level empty title block variable no longer shadows project-level value
BorderTitleBlock::updateDiagramContextForTitleBlock() merged the page's
"additional fields" over the project-level context unconditionally,
even when the page-level value was empty. Since #495 auto-adds every
template custom variable to the folio's Custom tab with an empty
value (so the user only has to fill in what's missing), simply
opening/confirming the Folio Properties dialog now permanently blanks
out any project-level custom variable of the same name — and it's
self-perpetuating, since the dialog re-adds the empty entry every time
it's reopened.

Skip page-level values that are empty when merging, so a real
project-level value shows through. An explicit non-empty page-level
override still takes precedence as before.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 18:32:54 +12:00
Kellermorph 3db298996a Fix 2026-07-29 16:40:17 +02:00
Dieter Mayer db514c6a25 Element panel: show name and element information in the tooltip
The element tooltip showed only the collection path - the least useful
string exactly when a long descriptive name is truncated in the tree
(qelectrotech#552). Show instead: localized name, description,
manufacturer and manufacturer reference (each only when set), with the
collection path kept as the last line. Directories and .qetmak entries
keep the plain path tooltip.

Reuses the location/context already parsed right above for the search
index, so no additional file access or parsing.

GUI-verified on a library where every element carries these fields:
hovering an element now shows e.g. name, "Hutschienennetzteil
85-264VAC auf 24VDC, 92W, Schutzklasse II", manufacturer, order number
and path on five lines.
2026-07-29 12:32:22 +02:00
Laurent Trinques 88962570a8 Merge pull request #569 from DieterMayerOSS/pr/parttext-alignment
Element editor: optional alignment for static texts
2026-07-28 17:45:43 +02:00
Laurent Trinques f3e8cce6c8 Merge pull request #567 from DieterMayerOSS/pr/factory-drop-pugixml-pass
ElementFactory: read link_type from the cached QDom, drop the pugixml pass
2026-07-28 17:43:01 +02:00
Laurent Trinques ea846cb24e Merge pull request #566 from DieterMayerOSS/pr/hash-contains
Replace hash.keys().contains(k) with hash.contains(k) (35 call sites)
2026-07-28 17:41:23 +02:00
Laurent Trinques ca8d907e70 Merge pull request #570 from DieterMayerOSS/pr/xmlcollection-linear-lookup
Fix the Qt6 load-time regression: linear child lookup in XmlElementCollection
2026-07-28 17:39:59 +02:00
Laurent Trinques b52b1d5984 Merge pull request #565 from DieterMayerOSS/pr/qt6-partslist-printdialog
Restore two more Qt5-only code paths on Qt6 (parts list, print dialog)
2026-07-28 17:38:44 +02:00
Laurent Trinques f854fe0553 Merge pull request #564 from DieterMayerOSS/pr/restore-qt6-autosave
Restore crash-recovery autosave on Qt6
2026-07-28 17:37:07 +02:00
Laurent Trinques db759344fd Merge pull request #563 from DieterMayerOSS/pr/log-handler-before-startup
Install the log message handler before the application starts
2026-07-28 17:35:11 +02:00
Laurent Trinques e7dfa4bc64 Merge pull request #568 from DieterMayerOSS/pr/qdom-invaliddata-policy
Harden QDom serialization against invalid data (CVE-2026-15037)
2026-07-28 17:33:43 +02:00
Dieter Mayer de82b2738f XmlElementCollection::child(): linear sibling walk instead of item(i)
The child lookup iterated parent_element.childNodes() via item(i), and
QDomNodeList::item() walks the sibling chain from the start on every
call - making the loop quadratic in the number of children, with an
extra QList allocation and a second pass on top. This lookup runs
several times per element instance while loading a project, against the
"import" category that holds every embedded definition, so the cost
scales with (instances x embedded definitions).

Replace it with a firstChildElement()/nextSiblingElement() walk with an
early return. Same semantics (first tag+name match in document order).

Measured on the Kaefer_1303 reference project (3.9 MB, 23 folios,
432 instances, media of 6 runs, Windows/MinGW, same GCC for both):

           before      after
  Qt5      5.116 s     5.068 s
  Qt6      6.683 s     4.640 s   (-31 %)

This removes the entire Qt6 load-time regression discussed in #553 -
Qt6 goes from +31 % slower to 8 % faster than Qt5 on the very project
that exposed it (Qt6''s QDom makes the quadratic pattern much more
expensive than Qt5''s did). Smaller projects gain too (3.4 MB example:
-9 % on Qt6).

(cherry picked from commit 0d4ef8eca27601c37ba2b75d7c058e9d8e2beea4)
2026-07-28 14:08:27 +02:00
Dieter Mayer 787335582b Element editor: optional alignment for static texts (#549)
Static texts (PartText) gain an optional alignment, exposed via the
existing AlignmentTextDialog behind a new "Alignement" button in the
static text editor:

- The horizontal part aligns the lines of a multi-line text relative
  to each other (centered block labels no longer need one hand-placed
  text per line).
- The full alignment defines the anchor: when the content or font
  changes later, the selected corner/center of the bounding rect keeps
  its place instead of always growing right/down from the top-left
  (same prepareAlignment/finishAlignment logic as DiagramTextItem).

Format: the <text> node takes the same optional Halignment/Valignment
attributes as dynamic_text, written only when they differ from the
historical top-left behaviour - existing .elmt files are untouched and
round-trip byte-identical. The saved x/y stay the baseline-left of the
text block in all cases; ElementPictureFactory only needs the line
alignment (the anchor is editor-side behaviour), so rendered elements
match the editor exactly.

German translations for the three new strings included (qet_de stays
complete, 2686/2686).

Verified headless: a project embedding a two-line text once with
Halignment=AlignHCenter and once without exports to SVG with the short
line centered under the long one (x 102.5 vs 126.5) in the aligned
block, and identical x for both lines in the legacy block. Editor-side
anchor behaviour follows the proven DiagramTextItem implementation but
was not manually exercised in the GUI yet.
2026-07-28 13:58:51 +02:00
Dieter Mayer 1caa8920ae Harden QDom serialization against invalid data (CVE-2026-15037)
Set QDomImplementation::setInvalidDataPolicy(ReturnNullNode) at startup.
Qt before 6.12 defaults to accepting invalid data when building QDom
nodes, so untrusted text inserted into comments, CDATA sections or
processing instructions could break out of its node on serialization
(XML injection, low severity). Qt 6.12 flips the default to
ReturnNullNode; opting in explicitly gives the same behavior on any
Qt 5/6 version, so no version guard is needed.

Verified: --resave of a 5-folio project produces valid XML with all
folios intact, and --export-pdf still works on the result.

(cherry picked from commit 7804ef3864a0b8643cfe13b68b8e0e6235508ab6)
2026-07-28 13:58:34 +02:00
Dieter Mayer 139c47d1ce ElementFactory: read link_type from the cached QDom, drop pugixml pass
createElement() ran a full pugixml parse of the element definition for
every instance, only to read the link_type attribute for the subclass
dispatch - on a big example project (191 instances) 49 ms of the load,
measured with temporary instrumentation. The QDom definition is already
cached and the ctor uses it anyway; reading the attribute there costs
~17 ms in total, so the net win is ~30 ms - within run-to-run noise
end-to-end, but it removes an entire redundant parser pass per element.

Behavior unchanged: an absent and an empty link_type both fell through
to SimpleElement before and still do.

(cherry picked from commit d63275971f558c8ac59f35bf4d13d7e424682342)
2026-07-28 13:58:33 +02:00
Dieter Mayer 96f6fa44ad Replace hash.keys().contains(k) with hash.contains(k) (35 call sites)
QHash/QMap::keys() allocates a list of every key on each call, then
contains() searches it linearly - an accidental O(n) plus allocation
where a direct O(1) lookup was meant. 35 occurrences across 7 files,
found while profiling project load times (context: #553/#560).

The hot one is ElementPictureFactory::getPictures(), which runs once
per element instance on project load: on the 3399 KiB example project
(191 instances, 129 cache hits) the keys() detour cost 45 ms of the
1.34 s total - measured, not estimated; the fix reproducibly shaves
~35-45 ms off that load. The remaining call sites are UI paths
(search&replace, dynamic text model, undo commands) where the waste
scales with selection/model size.

No behavior change: for QHash/QMap, keys().contains(k) and
contains(k) are equivalent by definition.

(cherry picked from commit 0a7f8f072fa68de7c01a9fc134a4bc8e16d62062)
2026-07-28 13:58:33 +02:00
Dieter Mayer 4f7340691a Restore two more Qt5-only code paths on Qt6 (parts list, print dialog)
Two further empty Qt6 guard branches found by ispyisail in
qelectrotech#553:

- Element editor parts list: the QGraphicsItem* was only stored into
  the list item on Qt5, so on Qt6 selecting a part in the list silently
  stopped selecting it on the canvas. QVariant::fromValue() works on
  both (Qt itself declares the metatype), guard removed.

- Print dialog: setEnabledOptions() is a Qt4-era API removed in Qt6;
  setOptions() is the modern spelling with the same replace-the-set
  semantics and exists on both, guard removed.

Both builds (Qt 5.15.2 and Qt 6.11.1) compile clean.

(cherry picked from commit 759d1c078e23664482850bad2e91d668b93aadcf)
2026-07-28 13:58:32 +02:00
Dieter Mayer 6d1b4cfa61 Restore crash-recovery autosave on Qt6
QETProject::writeBackup() was Qt5-only: the Qt6 branch of the guard was
an empty placeholder, so on Qt6 no backup was ever written - a silent
data-loss risk (a crash loses everything since the last manual save),
found by ispyisail in qelectrotech#553.

The Qt5-style QtConcurrent::run(function, reference-args) call did not
survive the Qt6 API change; a lambda capturing the (implicitly shared)
document copy behaves identically on both, so the version guard goes
away entirely.

Verified at runtime on the Qt6/Windows build: opening a project creates
the autosave triple (.qetautosave + .lock + .path) with valid XML
content, and a clean exit removes it again. The CLI keeps backups
disabled via setBackupEnabled(false), unchanged.

(cherry picked from commit 0f65ae8c4b2782fbfe97111bc8b369cc105ec592)
2026-07-28 13:58:31 +02:00
Dieter Mayer 9a13fef959 Install the log message handler before the application starts
qInstallMessageHandler() ran inside the startup worker thread, which is
scheduled after QETApp construction - but QETApp's constructor performs
the entire startup (collections, editor, opening projects passed on the
command line). Everything logged during that window went to the default
handler, i.e. stderr, which is invisible in a Windows GUI session: the
daily log file ended right after the machine-info block, and exactly
the interesting lines - the elements-collection timer and the project
load timer from #560 - never reached it.

Install the handler synchronously before SingleApplication instead;
the worker keeps the old-log cleanup and machine-info dump. The CLI
path returns earlier and intentionally keeps plain stderr logging.

Verified: a GUI session now logs the full timeline, e.g.
  12:37:03.623 Elements collection reload
  12:37:03.776 ... finished to be loaded in 0.151 seconds
  12:37:04.744 Project "..." (726 KiB) opened in 1.583 seconds
(cherry picked from commit 72b1a1d9ec2e3fd3787224759797978d710880bd)
2026-07-28 13:58:30 +02:00
Kellermorph b3a8ae898e PLC Manager 2026-07-27 22:16:52 +02:00
Laurent Trinques 66129fd15c Merge pull request #560 from ispyisail/feature/project-load-timing
Log project load times, split by phase
2026-07-27 17:15:02 +02:00
ispyisail 9e070f9bce Log project load times, split by phase
Requested in #553 to compare Qt5 and Qt6 builds. QET already reports how
long the elements collection takes to load (ElementsCollectionWidget::
reload); this adds the equivalent for opening a project.

The phases are reported separately rather than as a single total. Reading
the XML and building the objects is mostly independent of the Qt version,
whereas refreshing the diagrams is graphics-scene work -- a single number
would mix the two and could suggest a Qt version makes no difference when
the part that changed is simply not where the time goes. Measured on the
example projects, XML parsing is 3-7% of the total and diagram
construction 77-83%, so the distinction matters in practice.

QETProject::openFile() reports the total with the parse/build split, and
readProjectXml() reports the build phases:

  Project content built in 1.391 seconds (elements collection 0.009,
    diagrams 1.153, terminal strips 0, refresh 0.196, database 0.033)
  Project "example.qet" (3399 KiB) opened in 1.505 seconds
    (xml parsing 0.11, content 1.395)

Logged with qInfo(), matching the existing collection timer, so it lands
in the normal log without a debug build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 17:37:49 +12:00
plc-user 0608a585d6 update binary-translation-files for FR and DE 2026-07-26 18:52:08 +02:00
Laurent Trinques baf294251f Merge pull request #557 from ispyisail/fix/qmake-build-without-kf5
qmake: allow building without KDE Frameworks 5 (CONFIG+=no_kf5)
2026-07-26 18:28:50 +02:00
Laurent Trinques 80d3b17358 Update en translations files 2026-07-26 17:05:02 +02:00
Laurent Trinques 5aef8fcca5 git submodule update --remote elements 2026-07-26 16:44:39 +02:00
Laurent Trinques 72a6534a73 Update translations files 2026-07-26 16:44:02 +02:00
Laurent Trinques 0263fed6cf Merge pull request #558 from ispyisail/fix/clear-broken-stylesheet
Clear the application stylesheet when using system colors
2026-07-26 15:32:11 +02:00
Laurent Trinques 9cbd9b429c Merge pull request #559 from ispyisail/fix/554-resolve-data-paths-from-binary
Fix language (and data paths) when opening a .qet by double-click on Windows
2026-07-26 15:00:55 +02:00
Laurent Trinques c3d511cdcd Merge pull request #555 from ispyisail/feature/edz-translatable-strings
edz: make EdzArchive error strings translatable (+ German and French)
2026-07-26 14:45:43 +02:00
ispyisail 3ffa0194c7 cmake: Windows translations live in lang/, not l10n/
QET_LANG_PATH was "l10n/" for WIN32, a value that appears nowhere else in
the tree: the MSI shortcuts pass --lang-dir="[INSTALLDIR]lang/", and the
windows-build workflow copies the .qm files into files/lang/. So the
compiled-in default pointed at a directory no packaging creates, leaving
the command-line argument to do all the work.

Align it with what is actually shipped, so the binary-relative lookup
added in the previous commit can find the translations on its own.
2026-07-26 22:41:44 +12:00
ispyisail d4ec9f9c65 Resolve relative compiled-in data paths from the binary, not the CWD
commonElementsDir(), commonTitleBlockTemplatesDir() and languagesPath()
return the compile-time path verbatim when it is not marked
*_RELATIVE_TO_BINARY_PATH. On Windows those paths are relative
("./elements/", "./titleblocks/", "./lang/"), so they resolve against the
process working directory.

That only holds when QET is started from its own installation folder.
Opening a document from a file manager sets the working directory to the
document's folder, and the data is then looked for next to the user's
file. The shortcuts hide this by passing --common-elements-dir,
--common-tbt-dir and --lang-dir explicitly; anything that launches the
binary without them does not (see #554).

Add resolveConfiguredDataPath(): absolute paths are returned unchanged,
and a relative one is tried against the working directory first (so any
setup relying on the old behaviour keeps working), then next to the
executable, then in its parent -- the layout used by the Windows
packaging, where the binary sits in bin/ with the data beside it. This is
the same fallback the no-compile-option branch already performs for
issue #86, which was unreachable whenever the compile option is set.

The *_RELATIVE_TO_BINARY_PATH defines are left alone; they are only set
for macOS in qelectrotech.pro, and the CMake guard that would set them
tests a variable that is never defined.
2026-07-26 22:41:44 +12:00
ispyisail 69c595fdb8 Windows installer: pass the data directories to the .qet file association
The MSI registers both shortcuts with the arguments QET needs to find its
data ("Point directly to qelectrotech.exe with all required arguments"),
but the QElectroTech.Document\shell\open\command registry value was
written without them:

    "[INSTALLDIR]bin\qelectrotech.exe" "%1"

Launching from the Start Menu therefore works, while double-clicking a
.qet file does not: Explorer sets the working directory to the document's
folder, and the compiled-in data paths are relative, so nothing is found
there. The most visible symptom is the interface always coming up in
French, because no translation loads and the source strings are French.

Give the file association the same arguments as the shortcuts.

Reported by mr-rfh in #554, who diagnosed it and arrived at exactly this
registry value by hand.
2026-07-26 22:41:44 +12:00