Commit Graph

9084 Commits

Author SHA1 Message Date
Laurent Trinques bc06f7d444 macOS: follow symlinks when looking for Qt translations
Homebrew's share/qt/translations is a symlink to the qttranslations keg;
find without -L did not descend into it and found no qtbase_*.qm.
2026-09-11 12:01:15 +02:00
Laurent Trinques 2620d34b59 macOS: look for Qt translations in the qttranslations Homebrew formula 2026-09-11 11:49:58 +02:00
Laurent Trinques 4b675dda1b CI/Windows: bundle Qt's own translations (qtbase) as lang/qt_XX.qm
windeployqt runs with --no-translations, so standard buttons (OK/Cancel)
and dialogs stayed in English. Copy each qtbase_XX.qm from the MSYS2 Qt
translations into files/lang/qt_XX.qm, where QETApp::setLanguage() looks,
with aliases for QET languages Qt only ships with a region (pt, zh).
2026-09-11 11:40:10 +02:00
Laurent Trinques e982778526 macOS: bundle Qt's own translations (qtbase) as lang/qt_XX.qm
Standard buttons (OK/Cancel) and dialogs are translated by qtbase_XX.qm,
which macdeployqt does not deploy. QETApp::setLanguage() falls back to
lang/qt_XX.qm, so copy each qtbase_XX.qm there, with aliases for QET
languages Qt only ships with a region (pt -> pt_PT, zh -> zh_CN).
2026-09-11 11:35:17 +02:00
Laurent Trinques 10e5cd00f4 macOS: rewrite absolute Homebrew refs and install ids left by macdeployqt
macdeployqt kept /opt/homebrew paths (e.g. libbrotlicommon's install id).
Rewrite them to @rpath/libX.dylib, copying the library into Frameworks
if needed, over 3 passes to handle chained dependencies.
2026-09-11 11:01:05 +02:00
Laurent Trinques 6bc53277ec macOS: bundle Homebrew @rpath deps macdeployqt cannot resolve
Recent Homebrew bottles (brotli, webp, sharpyuv) reference their deps as
@rpath/libX.dylib, which macdeployqt skips. Copy them from /opt/homebrew/lib
into Contents/Frameworks after macdeployqt, and abort if any @rpath or
/opt/homebrew reference remains unresolved. Drop the ineffective -libpath.
2026-09-11 10:50:48 +02:00
Laurent Trinques 7d4cbc30f1 cmake: add qet_ko.ts to TS_FILES
qet_ko.qm was tracked in git but qet_ko.ts was never listed in TS_FILES,
so Korean was no longer built after #751 removed the tracked .qm files.
2026-09-11 10:45:24 +02:00
Laurent Trinques 2fcf3540dd macOS: pass -libpath=/opt/homebrew/lib to macdeployqt, abort on unresolved rpath
Homebrew libs (brotli, webp, sharpyuv) now reference their deps via @rpath,
which macdeployqt could not resolve, leaving them out of the bundle.
2026-09-11 10:23:17 +02:00
Laurent Trinques a45a984b32 CI/Windows: use find instead of compgen -G to locate .qm files
$GITHUB_WORKSPACE is a Windows path under MSYS2 (D:\a\...); compgen -G
treats its backslashes as escapes, so the generated .qm were not found.
2026-09-11 10:00:35 +02:00
Laurent Trinques 1f647fa229 CI/Windows-build: copy generated .qm from build/lang after #751 2026-09-11 09:40:35 +02:00
Laurent Trinques c4d2f0c4fb MacQetDeploy_arm64_cmake.sh: take .qm from build/lang (#751), fail if translations are missing 2026-09-11 09:37:44 +02:00
Laurent Trinques ac47f52eb0 Merge pull request #751 from arummler/translation_file_cleanup
Compiled translation file proposal
2026-09-11 09:29:16 +02:00
Andre Rummler d2e75b4195 Removing the qm translation files as by default they are rebuild by CMake anyhow. Changing the output directory which pointed to the source directory. That avoids
polluting the source directory during out-of-source builds and it is standard that these files should be located inside the build directory during the build step.
2026-09-11 08:24:43 +02:00
Laurent Trinques bbc995c91e Merge pull request #835 from ispyisail/fix/wiring-list-numeric-order
Wiring list: numeric wire-number order, UTF-8 BOM and atomic write
2026-09-11 08:01:58 +02:00
ispyisail 2322e6fd12 Write the wiring list CSV atomically, with a UTF-8 byte order mark
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>
2026-09-11 12:52:19 +12:00
ispyisail b5722c3f2a Sort the wiring list by wire number as a number, not as text
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>
2026-09-11 12:43:07 +12:00
Laurent Trinques 2926ca7306 Doxyfile fix version name 2026-09-10 23:31:52 +02:00
Laurent Trinques c7893c8229 Merge pull request #630 from ispyisail/feature-wiring-list-export
Wiring list dialog + excluded-conductor count (discussion #503, slice 4)
2026-09-10 22:45:22 +02:00
Laurent Trinques 412bc7f71f Merge pull request #629 from ispyisail/feature-wiring-list-view
Add wiring_list_view: from-to wiring list over the conductor tables (discussion #503, slice 3)
2026-09-10 22:44:27 +02:00
Laurent Trinques c147e6562d snap: add libcups2-dev to build-packages
Qt6 PrintSupport records Cups::Cups as a third-party dependency
(qprint_p.h includes <cups/ppd.h>), so find_package(Qt6 PrintSupport)
runs FindCups at configure time and fails without the CUPS headers.
Build-time only, nothing is staged.
2026-09-10 21:49:02 +02:00
ispyisail bee25a4ca9 Merge pull request #661 from ispyisail/fix-cli-modal-dialog-hang
Fix command-line tools hanging forever on a modal message box
2026-09-11 07:10:15 +12:00
Laurent Trinques 6d09041dce Merge pull request #831 from ispyisail/feature/advisory-slave-limit
Make the slave limit advisory rather than a refusal
2026-09-10 14:50:56 +02:00
ispyisail 1a12d440b2 Merge pull request #834 from ispyisail/fix/qlabel-pixmap-deprecation
Use QLabel::pixmap()'s non-deprecated by-value form on Qt5
2026-09-10 16:51:55 +12:00
ispyisail 85f46f2b48 Use QLabel::pixmap()'s non-deprecated by-value form on Qt5
#824 read the pixmap through the pointer overload, which Qt 5.15
deprecates, so the fix it introduced compiled with two deprecation
warnings of its own. Qt 5.15 offers the by-value form behind
Qt::ReturnByValue, so both branches can take the same overload and the
difference reduces to the argument.

Equivalent: the pointer overload returns nullptr when no pixmap is set,
which the old expression turned into a null QPixmap; pixmap(
Qt::ReturnByValue) returns a null QPixmap directly. It also drops the
null check, so the Qt5 branch is now a single expression.

Verified both arms of the #if, since a preprocessor-branched change is
only half tested otherwise:

 - Qt 5.15.18: deprecation warnings for this file 2 -> 0, builds clean,
   binary runs
 - Qt 6.10.2: builds clean, 488/488, links
 - 22 example projects load and export with no crash or hang

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 16:50:49 +12:00
Laurent Trinques 9637420756 Update Links to Doygen documentation and qch file 2026-09-10 05:27:57 +02:00
Laurent Trinques 6c68c461b1 Set Doxyfile version to 0.200.1 2026-09-10 05:24:31 +02:00
Laurent Trinques c830101ba6 Update CMakeLists.txt set version to 0.200.1 2026-09-10 02:33:31 +02:00
Laurent Trinques a1c0907811 Set QT_VERSION_MAJOR to 6
https://github.com/qelectrotech/qelectrotech-source-mirror/pull/824#issuecomment-5610090520
2026-09-10 02:30:53 +02:00
ispyisail ffd829bb69 Make the slave limit advisory rather than a refusal
max_slaves records how many contacts a part is expected to carry. It was
enforced as a rule the drawing had to obey, which obstructs the way both
@scorpio810 and @IBSYSLevi described working in #819: draw the schematic
first, choose the physical hardware afterwards. A limit that refuses the
link forces the hardware decision up front, which is exactly what they
said gets in the way.

Two changes, both in the UI rather than in isFull(), which stays the
query it always was:

 - MasterPropertiesWidget::on_link_button_clicked() now says the limit
   is reached and asks whether to link anyway, defaulting to yes,
   instead of refusing outright.

 - LinkSingleElementWidget no longer removes a full master from the
   candidate list. That was the worse half: a master at its limit simply
   was not there, indistinguishable from one that does not exist, with
   nothing to say why. It now stays selectable and the user decides.

PLC masters are deliberately left alone. Their limit is the number of
declared IO slots, which is structural rather than advisory -- a link
past it would have no IO index to map to -- and PlcLinkWidget already
tells the user when it hides one, via m_hidden_masters_label.

Only coils that opt into a limit are affected: max_slaves defaults to
-1, and no project in examples/ sets it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 11:54:52 +12:00
Laurent Trinques 957bbe5edb macOS: drop obsolete lang1/ copy step
lang1/ was a leftover from the pre-Qt6 translation pipeline.
Qt6/CMake now produces all .qm files directly into lang/, which
is already copied above, making this step dead code.
2026-09-09 16:02:02 +02:00
Laurent Trinques ce0ba4a681 Merge pull request #829 from jp2images/fix-macos-bundle-identifier
Set a bundle identifier so macOS file dialogs work
2026-09-09 15:57:21 +02:00
Laurent Trinques 8295083f05 misc: align macOS bundle identifier with app's settings domain
CFBundleIdentifier was "org.qelectrotech", but Qt derives
"org.qelectrotech.QElectroTech" from setOrganizationDomain()
and setApplicationName() for the app's own preferences file
(~/Library/Preferences/org.qelectrotech.QElectroTech.plist).

Align the two so the shipped bundle and the CMake target (see
CMakeLists.txt MACOSX_BUNDLE_GUI_IDENTIFIER) use the same
identifier regardless of build path.

Note: this changes the bundle's LaunchServices identity, so
users may need to redo "Open With QElectroTech" file
associations once after updating.
2026-09-09 15:54:28 +02:00
Jeff Patterson a2441a6f81 Set a bundle identifier so macOS file dialogs work
CMakeLists.txt marks the macOS target as MACOSX_BUNDLE but never sets
MACOSX_BUNDLE_GUI_IDENTIFIER, so CMake's default Info.plist template
substitutes an empty string for CFBundleIdentifier.

An .app with an empty identifier is never registered by LaunchServices
(`lsappinfo info` reports bundleID="" and bundle path=[NULL]). AppKit
runs the open/save panel in an XPC service keyed on the client's bundle
identifier: the service is spawned on each request but presents no
window, so QFileDialog::getOpenFileName() and getSaveFileName() return
an empty string without a panel ever appearing. In QET this means
File > Open and File > Save as silently do nothing -- openProject()
receives an empty path and returns at its `if (filepath.isEmpty())`
guard. Every macOS CMake build has been affected since the target
became a bundle.

Fill in the identifier along with the other bundle metadata CMake's
template expects. org.qelectrotech.QElectroTech is the identifier Qt
already derives from setOrganizationDomain("qelectrotech.org") and
setApplicationName("QElectroTech") for the app's own preferences file,
so the bundle now agrees with what the app writes at runtime.

Verified on macOS 27 with Qt 6.11: before the change File > Open and
File > Save as present nothing; after it both panels open normally. No
code signing step is needed -- the linker's ad-hoc signature still
reports the executable name as its identifier, and the panels work
regardless once the plist is correct.
2026-09-09 05:16:50 -05:00
Laurent Trinques c1f9af8544 Merge pull request #822 from enesgursoy6110/fix/report-link-picker
Show folio identity first in report link picker
2026-09-09 07:49:42 +02:00
Laurent Trinques 033c2f93a8 Merge pull request #827 from ispyisail/feature/per-type-contact-budget
Show used against declared capacity where a master declares contact groups
2026-09-09 07:29:39 +02:00
Laurent Trinques 83623a0fa6 Merge pull request #826 from ispyisail/feature/general-tab-contact-count
Show the NO/NC/SW contact breakdown in a master's General tab
2026-09-09 07:29:07 +02:00
Laurent Trinques c85f80bbcf Merge pull request #825 from ispyisail/fix/contact-usage-counting-v2
Count master contacts in one place, and count contacts not elements
2026-09-09 07:28:15 +02:00
ispyisail f18eda845b Merge branch 'feature/general-tab-contact-count' into feature/per-type-contact-budget
# Conflicts:
#	sources/ui/elementpropertieswidget.cpp
2026-09-09 11:47:26 +12:00
ispyisail 73e9473db4 Keep the slave total in slots, and label the breakdown as contacts
Two units were being stacked in the same block. The line above reports
max_slaves, which is a number of slots, so reporting the line below in
contacts made a coil with one 4 pole slave read "maximum 4 / used 4"
while three slots were still free.

The total goes back to counting linked elements, matching the unit of
the line above it and restoring the original behaviour of that line.

The per-type breakdown keeps the pole multiplier, because that is the
question it answers -- how many contacts an auxiliary block must
provide -- and is now prefixed "Contacts :" so the two units are not
mistaken for each other.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 11:46:34 +12:00
ispyisail 7307128fc3 Merge branch 'fix/contact-usage-counting-v2' into feature/general-tab-contact-count 2026-09-09 11:45:49 +12:00
ispyisail 799ff5573f Revert the isFull() change: max_slaves counts slots, not contacts
The earlier commit changed MasterElement::isFull() to compare the
contacts in use against max_slaves. That was wrong, and this restores
the original comparison against the number of linked elements.

max_slaves is a number of slots, not of contacts:

 - it sizes the contact group table in the element editor, one row per
   slot (ElementPropertiesEditorWidget::populateSlaveGroupsTable)
 - a group must match the slave's own contact count before it can be
   chosen, so a 4 pole slave needs a group declaring 4 and occupies
   that single group (ContactGroupSelectionDialog)
 - each slave stores exactly one group index
   (Element::setGroupIndexForElement)

So a coil declaring 4 slots accepts 4 slaves, whatever their pole
count. Counting contacts made one 4 pole slave fill a 4 slot coil on
its own and refuse three further links that should have been allowed.

ContactUsage stays, and its per-type tally is still what the General
tab needs: how many contacts an auxiliary block must provide is a
different question from how many slots are occupied, and only the
former wants the pole multiplier. The header now says so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 11:45:36 +12:00
ispyisail 6f2c66afef Show used against declared capacity where a master declares contact groups
Second half of #819: where a coil declares what contacts it provides, the
General tab now reports each type as used against declared rather than as
a bare count.

    NO : 3/4, NC : 1/2, inverseurs : 0/1, autres : 0/0

MasterElement::contactCapacity() sums contactCount over the element's
SlaveContactGroup list, per type, reusing the same ContactUsage tally the
used count is built on. The mapping from ElementData::SlaveState onto the
tally's own type is factored into one helper so the used count and the
declared capacity cannot classify a contact differently.

Falls back to the plain count from the previous commit when an element
declares no groups, which is every element in the standard collection
today -- nothing in the corpus declares slaveContactGroups, so this
changes no existing display.

A type used beyond what is declared reads as e.g. "1/0". That is
deliberate: it says this contact does not fit the part.

Display only. Whether a declared capacity should also feed
MasterElement::isFull() is the open question in #819 and is not touched
here.

Verified end to end against a purpose-built fixture, since no existing
element exercises this path: a coil declaring two NO groups of two, one
NC group of two and one changeover group of one parses and reports
NO=4 NC=2 SW=1 other=0 total=7, matching the declaration exactly.
tst_contactusage gains a case covering capacity summed across groups
(10 cases, all passing).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 10:49:16 +12:00
ispyisail c39c7414cf Show the NO/NC/SW contact breakdown in a master's General tab
Requested in #819: after drawing a schematic you need to know how many
NO, NC and changeover contacts a coil ended up using, so you can pick an
auxiliary block that satisfies it. Until now the General tab reported
only a single total, and counting the contacts by type meant counting
rows on the cross reference by hand.

Three changes to that block:

 - the used count now counts contacts rather than linked elements. The
   label already said "contacts" while the value was
   linkedElements().count(), so a slave standing for several contacts
   was under-reported. It reads MasterElement::contactUsage(), the
   same count isFull() uses.

 - a breakdown line is added below it, printed only when the master
   actually has contacts to break down.

 - a declared limit of -1 means "no limit set" rather than a real
   limit, so it is printed as such instead of showing "-1", which
   reads as a bad value.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 10:36:25 +12:00
ispyisail c33f250910 Count master contacts in one place, and count contacts not elements
MasterElement::isFull() decided whether a coil had room left with

    connected_elements.size() >= max_slaves

which counts linked *elements*. A slave stands for as many contacts as
its "number" kind information declares, so a 4 pole contact consumed a
single contact from the coil's budget instead of four. 36 elements in
the standard collection declare a number between 2 and 4, so this is
reachable, not theoretical.

Add ContactUsage, a header-only tally holding the two rules that are
easy to get wrong:

 - a slave counts once per contact it declares, not once per element
 - a changeover is counted once, as sw, and never as one NO plus one
   NC. CrossRefItem::NOElements() and NCElements() both return
   changeovers, so a count built by adding those two lists together
   reports one changeover as two contacts.

The upcoming per-type displays (the used count in the element's General
tab, and the per-type budget on the cross reference) need exactly this
count, so it lives in one place rather than being written out three
times, and isFull() now reads it too.

The header carries no graphics dependency, so the counting rules are
unit tested on their own in tests/qttest/tst_contactusage.cpp,
following the same pattern as diagramsortkeys.h.

Verified: all 9 unit tests pass, and both rules were mutation checked
(counting elements instead of contacts fails 2 tests, counting a
changeover as both NO and NC fails 3). The 23 example projects still
load and export without crash or hang, and qet-lint reports no
regressions against its baseline.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 10:08:00 +12:00
ispyisail c265f0206c Fix Qt5 build: QLabel::pixmap() returns a pointer, not a value
ClickableImageLabel::mousePressEvent() calls pixmap().isNull() and
pixmap().width(). That is the Qt6 signature; in Qt5 QLabel::pixmap()
returns const QPixmap * and the code does not compile:

  error: request for member 'isNull' in '...QLabel::pixmap()',
  which is of pointer type 'const QPixmap*'

CMakeLists.txt defaults QT_VERSION_MAJOR to 5 when it is not specified,
so a default configuration of master has not built since 6b577ee75.

Read the pixmap once into a local, guarded the way the rest of the
codebase handles this split, which also drops four repeated pixmap()
calls in the same expression.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 09:52:06 +12:00
enesgursoy6110 36dd1624d2 Show folio identity first in report link picker 2026-09-08 21:02:46 +03:00
Laurent Trinques a583b3c43c Merge pull request #688 from IBSYSLevi/fix/saving-coil-master
Fix: saving coil master
2026-09-08 08:35:00 +02:00
Laurent Trinques 1738c3ad6c Merge pull request #771 from Kellermorph/spinbox-crossref
Add configurable distance between label and slave XRef
2026-09-08 08:20:33 +02:00
Laurent Trinques 82026d8f7c Merge pull request #818 from qelectrotech/revert-804-feature/terminal-potential-grouping
Revert "Feature: Terminal potential grouping"
2026-09-07 15:47:08 +02:00
Laurent Trinques 1793dcb9a8 Revert "Feature: Terminal potential grouping" 2026-09-07 15:44:12 +02:00