Commit Graph

10467 Commits

Author SHA1 Message Date
Laurent Trinques fb226d435e Terminal strip: add an anti-parallel diodes terminal type
Add ElementData::TTAntiParallelDiodes (xml value "antiparallel_diodes"),
selectable in the element editor, the terminal strip editor and the free
terminal editor, and drawn in the terminal strip plan as two diodes wired
in opposite directions between the top and the bottom of the terminal.
2026-10-10 10:01:12 +02:00
ispyisail 5b98f1a1e9 Skip the folio-deletion test where --run is not built
CI builds without Qt Qml, so --run is not compiled in and the test's
QElectroTech opened the project and waited until the 180 s timeout.
The test now skips when QET_HAS_SCRIPTING is not defined, as the other
--run tests are left out of such builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Wga9B92BNurDEtxxtCDxf
2026-10-10 20:56:25 +13:00
ispyisail 8d8a998f75 Merge pull request #1445 from ispyisail/fix/db-stale-after-edits
Fix the project database going stale after folio, symbol and wire edits
2026-10-10 20:54:01 +13:00
Laurent Trinques daa648099b Terminal strip: save the layout (font, cell sizes...) in the project
The default terminal strip layout was rebuilt at every project load,
so the font size set in the layout editor was reset to 15 px.
Add TerminalStripLayoutPattern::toXml/fromXml and
TerminalStripLayoutsHandler::toXml/fromXml, write a
<terminal_strip_layout> element in QETProject::toXml() and read it
before the diagrams are loaded. Projects without it keep the defaults.
2026-10-10 09:49:42 +02:00
plc-user da31e93b1f Merge pull request #1447 from ispyisail/fix/imagedrop-lupdate-warning
Fix the lupdate warning on the dropped-picture texts (#1446)
2026-10-10 09:47:22 +02:00
Kellermorph 3f23e3dd2b Create the folder of the cable types file before writing into it
The catalogue is written with QSaveFile, which cannot write into a
folder that is not there. A fresh profile has no documents folder, and a
path typed into the settings may name a folder which was never created,
so the first write failed with "No such file or directory" and no way
for the user to see that the folder was the problem rather than the file
(non-blocking review comment by ispyisail).

writeFile() makes the folder first, which covers every writer: creating
the template, appending a type and editing one all go through it.

Covered by tst_cabletypelist::aMissingFolderIsCreated, writing into
<tmp>/not/there/yet/qet_cable_types.csv. Verified in both directions:
without the fix the test fails with 'createFile(path, &error) returned
FALSE. (No such file or directory)', with it the file is created and
reads back.
2026-10-10 09:42:59 +02:00
Kellermorph a2880ad79e Write the cable XML only where it has something to carry
Two pieces of cable XML went into every file the program saved, whether
the project had cables or not (non-blocking review comment by
ispyisail). Resaving one of the example projects added both of them.

- <cable_autonums> is now written only when it holds something: a named
  rule, an axis other than the default, the numbering question answered
  with no, or a rule of its own. When it is missing, the reader falls
  back to exactly the defaults a project which never touched cable
  numbering has, so nothing changes for those files.

  That is deliberately not "only when the project has cables", which
  would cost data: a rule configured before the first cable is drawn and
  an axis chosen before it are answers only this element can carry, and
  the question answered with no has to survive even if the cable which
  prompted it was cancelled again.

- the font attribute of <xref> is now written only when there is one.
  Only the cable cross-reference has a font of its own; writing it
  unconditionally put font="" on every cross-reference type of every
  project, and an absent attribute reads back as no font, which is what
  all the others are.

Verified by resaving examples/741.qet, examples/Projet_vierge.qet and
examples/affuteuse_250h.qet: before, cable_autonums=1 and font="" on
each; after, none of them. A cable project of the reviewer's own keeps
<cable_autonums axis_priority="y" current_autonum="Cable"> with its rule
and its real fonts, and only loses the four empty font attributes.
ctest 92/93, the one failure being the pre-existing headless
tst_menubarkeyboard.
2026-10-10 09:42:54 +02:00
plc-user c4e69602d0 Merge pull request #1448 from plc-user/master
shorten some German texts
2026-10-10 09:41:29 +02:00
plc-user bd50e17297 shorten some German texts 2026-10-10 09:36:42 +02:00
Kellermorph 0743546542 Take the right button away from the cable tool only, not from every tool
The cable feature suppressed the quick command ring for every running
tool, so drawing a line or placing an element no longer got the ring a
right drag shows -- a far wider change than the feature needed, and one
nobody asked for (blocking review comment by ispyisail).

The condition is now the cable tool alone. Diagram::cableToolIsRunning()
says whether that is the running interface, and while it is, the right
click cancels the line being drawn and opens neither the ring nor a
context menu, neither QET's own nor the platform's -- which is the
behaviour the cable tool needs and the only part that was ever intended.

Everything else in mousePressEvent is upstream's original again: a
gesture is tracked whatever else is running, a running tool sets
m_gesture_over_tool so the press carries on to the scene and a drag ends
the tool before the ring appears, and only the click which neither draws
nor selects swallows the platform's menu. A structural diff of
mousePressEvent against the commit before the cable feature shows three
added conditions and nothing else.
2026-10-10 09:35:47 +02:00
ispyisail 8c6ac0aeec Fix the lupdate warning on the dropped-picture error texts
lupdate printed "Class 'ImageDrop' lacks Q_OBJECT macro" at
imagedrop.cpp:77 on every "update_translations" run (#1446).
ImageDrop is a namespace, not a class, and the file routed its texts
through a local tr() helper; lupdate reads tr() inside an ImageDrop::
function as a member of a class without Q_OBJECT.

Call QCoreApplication::translate("ImageDrop", ...) directly instead,
which lupdate reads without a class. The context and the four source
texts are unchanged, so the existing translations still apply.

Closes #1446

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 20:27:01 +13:00
Kellermorph ed52f76840 elements: take upstream's submodule state again
Our branch still carried elements at b50bdd8 while upstream/master has
moved to b88197c, so pulling this branch would have rolled the element
library back by 13 commits (blocking review comment by ispyisail).

b50bdd8 is an ancestor of b88197c, so this is a fast-forward and nothing
of ours is lost: the 13 commits are upstream's own element fixes and its
repeated-terminal-name fixes. The pointer now matches upstream/master
exactly, so the branch no longer differs from master on this file at all.
2026-10-10 09:24:41 +02:00
Kellermorph a16964c055 Fix the double free when a deleted cable is undone and edited again
Deleting a cable and pressing Ctrl+Z twice leaves the cable out of the
project while AddCableCommand still stands and still thinks it has to
clean that cable up. The next edit of any kind makes the stack throw the
undone commands away: ~RemoveCableCommand frees the cable, and
~AddCableCommand frees the same memory again. A plain build hides it,
AddressSanitizer reports it as a heap-use-after-free in
addcablecommand.cpp (blocking review comment by ispyisail).

AddCableCommand now holds the cable as a QPointer, which is what
RemoveCableCommand already did: whoever of the two runs first frees it,
the other one sees a null pointer and has nothing left to do, in either
order of destruction. The destructor also stopped dereferencing
project() without checking it, which it did on that very line.

Covered by tst_cableundointegration, a probe linked against the
application's objects the way the other integration probes are. It draws
a cable, deletes it, undoes twice and pushes a further edit -- the
sequence which used to crash. Verified in both directions: with the raw
pointer the probe dies with SIGSEGV inside ~AddCableCommand called from
QUndoStack::push, with the QPointer it prints its PASS line.
2026-10-10 09:24:15 +02:00
ispyisail 9a4a303503 Merge remote-tracking branch 'upstream/master' into fix/table-chain-deleted-folio 2026-10-10 20:08:03 +13:00
ispyisail 36024aecac Merge remote-tracking branch 'upstream/master' into fix/db-stale-after-edits 2026-10-10 20:08:03 +13:00
ispyisail 44b2129d5a Fix a crash opening a project whose folio report arrow has no terminal
A folio report arrow's text looks for a wire to show: on the arrow
itself, else on the arrow it is linked to, through that arrow's first
terminal. Some report symbols have no terminal -- ref_voyant_2_h.elmt in
the collection, and older collections' arrows -- so a project linking an
arrow with no wire to one of them crashed QElectroTech as it opened.
The other arrow's terminals are now checked first, as the arrow's own
already were.

Found on a project attached to the forum (saved by 0.70), which crashed
on opening.

Test: tst_resaveunchanged::reportArrowWithoutTerminalOpens builds the
case from Projet_vierge.qet's own symbols; it crashes without the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Wga9B92BNurDEtxxtCDxf
2026-10-10 20:05:58 +13:00
ispyisail d4352b72c1 Merge pull request #1443 from ispyisail/fix/linked-elements-sorted-copy
Fix master's failing link order test (#1441 + #1442)
2026-10-10 20:02:01 +13:00
ispyisail 727188f564 Fix master's failing link order test: sort a copy in linkedElements()
Element::linkedElements() sorted the element's own list of linked
elements by position before returning it, so any caller reordered what
is saved. #1441 restores the file's order after linking; #1442 fills the
link table through linkedElements(), which sorted it again, so on master
a coil's contacts are saved in position order and
tst_resaveunchanged::savedLinkOrderKept fails.

linkedElements() now returns a sorted copy. Callers still get the list
by position; the saved order is left alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Wga9B92BNurDEtxxtCDxf
2026-10-10 19:33:06 +13:00
ispyisail 5e6677ebec Keep the project database current when folios, symbols and wires change
The project database is kept up to date edit by edit, and a script's
qet.query() and the folio tables read it without a full rebuild. Three
edits left it out of date until the next rebuild:

- adding or removing a folio: the folios after it kept their old
  position and folio number, and a removed folio's diagram_info row
  stayed;
- moving a symbol: its folio cell (element.pos) stayed where the symbol
  was added;
- deleting a wire: its two ends stayed in the terminal table, which
  lists the terminals a wire ends on.

Positions and folio numbers are now written again after a folio is
added, removed or moved (one function for the three), the removed
folio's diagram_info row goes, a moved symbol's cell is written when
the database is next read (as drawing items are), and a deleted wire's
ends go unless another wire ends there.

Found by comparing the tables after random scripted edits with those
a fresh open of the saved project gives. Left alone: labels and wire
numbers made from a folio formula, which the drawing itself keeps until
the project is reopened.

Tests (tst_databasefromdocument): folioAddedAndRemoved,
movedElementCell, deletedWireTerminals; each fails without its part of
the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Wga9B92BNurDEtxxtCDxf
2026-10-10 19:07:03 +13:00
ispyisail ee164f1bf1 Fix a split table losing its data and crashing after a folio is deleted
A summary or parts-list table split over several folios saves its data
with its first part only; each later part names the part before it.
Deleting a folio keeps its tables in memory for undo, still in the
chain, so saving then named the deleted part as the previous table of
the next one. On reopening, every part after the gap had no data, and
closing the project crashed: the first orphaned part, destroyed, handed
its missing data on to the next part through a null model.

toXml() now names the nearest previous part still in the project, or
saves the data if there is none. setPreviousTable() no longer copies a
null model, so files already saved this way open and close.

Tests (tst_resaveunchanged): missingPreviousTableOpens,
deletedFolioKeepsTableChain; both fail without the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Wga9B92BNurDEtxxtCDxf
2026-10-10 19:03:50 +13:00
ispyisail 13dbacef1e Merge pull request #1442 from ispyisail/feat/db-link-table
Add a link table to the project database
2026-10-10 18:19:57 +13:00
ispyisail e2363eb9e4 Merge pull request #1441 from ispyisail/fix/f101-link-order
Fix a coil's contacts being saved in a different order each time
2026-10-10 18:19:42 +13:00
ispyisail 3089408b19 Add a link table to the project database
One row per element and element it is linked to -- a coil and its
contacts, a pair of folio reports -- from each side, with the contact
group the element saved for it. Nothing reads it yet: cross-references
are the main thing one folio needs from another, and this is what lets
them be answered without building every folio.

Filled like the other tables: from the document when it can be read
exactly (a link only one side lists, between kinds that cannot link, or
giving a contact a second coil is left to the folios), from the folios
otherwise. A link made or undone afterwards rewrites that element's rows
when the database is next read, as drawing items are, since the contact
group is set after the link is made.

Test: tst_databasefromdocument compares the link table both ways on
every example; linksAreListed checks a coil and contact (with a group)
in m_000.qet, oneSidedLinkFallsBack the refusal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Wga9B92BNurDEtxxtCDxf
2026-10-10 17:22:56 +13:00
ispyisail 5441e2ae76 Keep a coil's contacts in the order the file saved them
On opening a project, a coil and its contacts are linked in the order
the folios' items are visited. When contacts are on an earlier folio
than the coil they link first, so the coil's list followed the folio
order instead of the file's, and contacts on one folio swapped places
from run to run. Saving the same project twice could then give two
different files.

After linking, Element::initLink() now puts the linked elements back in
the order the file listed them. Elements linked but not in that list
keep their place after it.

Test: tst_resaveunchanged::savedLinkOrderKept reverses a coil's two
contacts in m_000.qet and checks a resave keeps that order; it fails
without the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Wga9B92BNurDEtxxtCDxf
2026-10-10 16:54:26 +13:00
ispyisail 613f05a05e Merge pull request #1433 from bhangart/i18n/fr-image-drop-texts
Linux build and tests / Build and test (Qt 6, Debug) (push) Failing after 1m39s
Translate the texts of dropping pictures on a folio
2026-10-10 07:52:12 +13:00
ispyisail 82b3232d59 Merge pull request #1430 from bhangart/fix/refused-files-colon
Write the list of refused dropped files with an English colon
2026-10-10 07:52:08 +13:00
ispyisail 4c7ea90c51 Merge pull request #1429 from bhangart/fix/image-missing-size
Load a picture without a usable size at size 1, not 0
2026-10-10 07:52:03 +13:00
ispyisail 4b99c73c03 Merge pull request #1428 from bhangart/fix/free-text-nonfinite-position
Load a free text's non-finite position or rotation as 0
2026-10-10 07:51:59 +13:00
ispyisail 82716f6291 Merge pull request #1427 from bhangart/test/menubar-wait-active
Wait for the window to be active in the menu bar keyboard tests
2026-10-10 07:51:55 +13:00
ispyisail ce3a4d82ea Merge pull request #1437 from ispyisail/fix/genericdevice-test-font-height
Fix tst_genericdevice failing in the Linux CI
2026-10-10 07:50:08 +13:00
Kellermorph 69eb071f45 Merge upstream/master: translation wave plus generic device
Upstream moved 56 commits ahead of the last merge. Six files conflicted,
all of them files where upstream's French -> English tr() translation wave
touched lines we had also touched with the cable feature. Resolution rule
applied everywhere: take upstream's English source strings, keep our cable
additions.

Resolved:

- sources/ui/xrefpropertieswidget.ui : kept our structure (m_labels_gb
  pulled out of the display group, m_slave_row, the m_font_pb "Police..."
  button of the cable cross-reference) and mechanically applied upstream's
  20 English string replacements on top of it.

- sources/ui/xrefpropertieswidget.cpp : our version plus upstream's 7
  translated combo entries; the tr("Cable") item we add for the cable
  cross-reference type stays.

- sources/autoNum/ui/numparteditorw.cpp : upstream's English part names
  ("number format 1", "Sheet no.", "Plant", "Location", ...) for the
  number-format list, with our comment explaining why type 3 (cable) takes
  the conductor kinds of variable.

- sources/ui/configpage/configpages.cpp : upstream's English tab titles
  (Conductors / Elements / Sheets) plus our Cables tab.

- sources/ui/configpage/projectconfigpages.cpp : upstream's "Sheets" tab
  title plus our Cables tab block (single-rule SelectAutonumW(3)).

- sources/qetdiagrameditor.cpp : union of both sides - upstream's new
  "Add a generic device" action (icon, status tip, data id) and its
  English menu names ("File"/"Edit"/"Project"/"Display"), together with our
  cable action, the Numbering and Lists menus, the cable list actions and
  the CSV export in the Project menu.

Kept French: our own cable tr() source strings stay French for now. That
is the smaller change and the translation pass can follow separately.

Verified: full build 1065/1065, ctest 91/92 (only the pre-existing
headless tst_menubarkeyboard fails: no window manager, so Alt+F and F10
cannot open a menu bar), smoke start exit 124, no conflict marker left in
the tree.
2026-10-09 20:44:58 +02:00
ispyisail 2d5a249039 Fix tst_genericdevice failing on machines without Liberation Sans
edgeCases() expected an empty device to be exactly MinHeight (30) tall.
The sizing rule is max(MinHeight, 2 x label height) rounded up to the
grid, so with a taller fallback font the body is 40 and the test fails.
The Linux CI image has no Liberation Sans; fontconfig substitutes Nimbus
Sans (fonts-urw-base35), whose line height gives 40.

Compute the expected height from the label font's metrics, as the
layout does.

Reproduced locally with a fontconfig file listing only the urw-base35
fonts: the old test fails with the CI's exact message (40 vs 30), the
new one passes. Doubling the label factor to 3 in genericdevice.cpp
still makes the new check fail, with Liberation and with Nimbus.

Reported by bhangart on #1418.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 07:28:03 +13:00
Kellermorph d55a3c7881 Fix cable numbering rule questions: per project, and a first rule counts
Two defects found while re-testing the cable management after the
upstream merge, plus one change of intent for the numbering question.

The question "define a cable numbering rule now?" kept its answer in
the program settings, so saying no once silenced every project of the
program -- the exact opposite of what it should do. The answer now
travels with the project itself, stored on the <cable_autonums>
element as ask_numbering_rule="false"; a file which does not hold the
answer asks again, and taking the rule away in the project properties
or in the numbering window brings the question back for that project
alone. Read-only projects are no longer asked at all, since there is
nowhere in them to define a rule.

The numbering window could not hand out the first rule of a project:
it drew the rule, worked the numbers out with it, and only wrote the
rule into the project together with those numbers -- while the
planning refused to run on a project which had no rule saved yet.
The counters of a cable rule are kept under its fixed name anyway, so
planning now falls back to that name when the project holds no rule
yet: a rule which is being drawn in the window counts from the moment
it is complete, and the first renumbering of a project works.
2026-10-09 20:22:45 +02:00
Beat Hangartner e1cb6006c6 Load a picture without a usable size at size 1, not 0
DiagramImageItem::fromXml() read the size attribute with a plain
toDouble(). A picture whose size was missing or not a number got size
0, so it was invisible on the folio, left out of the SVG export, and
a resave wrote size="0" back, which then stayed 0 on every load. "nan"
was kept and written back as such. The <transform> child, which newer
files carry, already defaults its scale to 1.

Read the size with an ok flag and use 1, the size a picture is added
with, when it is missing, not a number, not finite, or 0.

No file-format change for usable sizes. A picture that an earlier save
left at size="0" shows again, at size 1, after this change.

Tests: tst_imagemissingsize runs the binary's --resave and --export-svg
on a fixture with six small pictures: size missing, "0", "nan", "big",
"0.5" and "2". The first four fail on master (saved as 0, 0, nan, 0)
and the export draws only 3 of the 6 pictures there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Beat Hangartner <beat@hangartners.ch>
2026-10-09 15:58:49 +02:00
Beat Hangartner 9136c605f4 Load a free text's non-finite position or rotation as 0
"nan", "inf" and "-inf" parse as numbers, and IndependentTextItem::
fromXml() used them as they came for x, y and rotation. A project with
such a value kept it: --resave wrote x="nan" back, and the SVG export
drew the text at matrix(1,0,0,1,nan,95), which is not valid SVG.
Conductors and element texts already load a non-finite position as 0.

Load a non-finite x, y or rotation of a free text as 0, the same way.

No file-format change: finite values load and save as before.

Tests: tst_freetextnonfinite runs the binary's --resave and --export-svg
on a fixture with x="nan", y="inf", x="-inf", rotation="nan" and a
finite text (61.7, 61.3, 37 degrees, kept as they are). The four
non-finite cases and the export check fail on master.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Beat Hangartner <beat@hangartners.ch>
2026-10-09 15:58:44 +02:00
Beat Hangartner c52cd3b2fc Keep a line's pivot at its centre when one of its ends is dragged
A shape's pivot follows its centre when it is resized, unless it was
placed by hand: setLine() and setRect() do that, and so did dragging a
rectangle's or an ellipse's handles, which goes through setRect().
Dragging an end of a line moved the end directly and left the pivot
where it was, so the next rotation turned the line around a point
beside it. Undo and redo already re-centred it, through setLine().

The line's handle drag now applies the same rule.

New tst_linepivotresize, on a real folio with scene mouse events: the
pivot is at the new centre after an end is dragged (fails without the
change: it stays at the old centre), and after undo and redo; a pivot
placed by hand stays; a rectangle's pivot follows as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:47:53 +02:00
Beat Hangartner 448a82fae6 Test Escape during a picture's handle drag
tst_imagehandleescape covers #1414 through the real editor: a picture's
resize, rotate and pivot handle are pressed and dragged with scene mouse
events, Escape goes to the DiagramView, then the rest of the gesture.
Each time the picture is back as it was at the press, still selected,
and no undo step is recorded; without a drag, Escape still clears the
selection. The three drag cases fail with #1414 reversed (Escape cleared
the selection under the drag).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:47:52 +02:00
Beat Hangartner eab557d9af Test that Space on a picture turns the rotation its file saves
The first test that runs a real QETApp, offscreen (qetapptest.h): it
links qelectrotech_objects, keeps its settings, configuration and data
in a temporary folder, and triggers the editor's own actions.

tst_rotateselectionimage covers #1413: Space ("rotate_selection") turns
a picture's rotationAngle, not QGraphicsItem's rotation, in place, and a
picture read back from its XML has the angle; undo and redo, twice; and
a group turn ("rotate_group_selection") moves each picture's pivot a
quarter turn around the group's centre. All three fail with the code
from before #1413.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:47:52 +02:00
Beat Hangartner 3dd977a040 Build the application's code once as an object library
The executable compiled every source file itself, so a test could only
reach the application's classes by listing their .cpp files one by one,
which stops working as soon as a class needs a folio, its view or the
editor window -- that pulls in nearly everything.

The sources (except main.cpp) and the two .qrc files now build once as
qelectrotech_objects, an OBJECT library; the executable is main.cpp
linked with it. Its link libraries and include folders are PUBLIC, and
it passes on this directory's compile definitions, so a target in
tests/ that links it compiles and links like the application.
lupdate's targets scan the library (main.cpp has no tr() text).

The executable, its compile flags and what it saves do not change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:47:52 +02:00
Beat Hangartner d996426e8a Translate the texts of cropping a picture on the folio
The French of the six new texts (the crop mode's name and hints, "Crop on
the folio", "Reset crop", "Properties..."), as lupdate's own entries,
inserted where lupdate places them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:46:46 +02:00
Beat Hangartner 05131d1238 Show crop bars instead of handle points while cropping
Black bars on a white outline, an L at each corner and a short bar in
the middle of each side, at the same size on screen at any zoom, with
the matching resize cursor over each. The handles underneath still
take the drags but are no longer drawn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:46:46 +02:00
Beat Hangartner d86f2d5461 Crop a picture directly on the folio
Double-clicking a picture, or "Crop on the folio" in its context
menu, crops it in place: the whole original is shown, dimmed outside
the region kept, and eight handles move the crop's edges; a drag inside
the frame moves the crop window over the original. Enter, a double-click
or a click elsewhere applies the crop as one undo step, keeping the
kept region where it is on the folio; Escape drops it. Rotated and
scaled pictures are cropped along their own sides.

While cropping, the picture is the folio's keyboardItem (see the
Escape commit before this one), so the view hands it Enter and Escape
before its own shortcuts: Enter does not repeat the last placing
command, and Escape does not clear the selection, which would apply
the crop.

The context menu gains "Reset crop", which shows the
whole original again, and "Properties...", since double-click no
longer opens them. The crop dialog stays available.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:46:46 +02:00
Beat Hangartner 95fe56527d Translate the texts of dropping pictures on a folio
The texts added with dropping picture files on a folio (#1416) had no
entry in the translation files yet, so the French interface showed them
in English, and the English one wrote "Add 1 image(s)".

- qet_fr.ts: the French of all nine texts (the eight of #1416 and the
  "%1: %2" of the list of refused files), "%1 : %2" with the French
  space before the colon.
- qet_en.ts: the singular and plural of "Add %n image(s)".

The entries are lupdate's own, inserted where lupdate places them, so a
later refresh of the .ts files moves nothing; lupdate run over sources/
finds them all as existing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:46:45 +02:00
Beat Hangartner 0fc5963793 Write the list of refused dropped files with an English colon
The message listing the files a drop could not add wrote each line as
"name : reason", with the space French puts before a colon, and as a
fixed string that no translation could change. It is now a tr() text,
"name: reason", so each language can write it its own way.

Suggested in the review of #1416.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:46:45 +02:00
Laurent Trinques 5f6e74918e Merge pull request #1418 from ispyisail/feature/generic-device
Add a generic device: a box symbol with terminals on any side
2026-10-09 14:35:21 +02:00
Laurent Trinques 88f8c260ab Merge pull request #1425 from bhangart/ci/windows-tests-on
CI: build and run the unit tests in the Windows job again
2026-10-09 14:34:29 +02:00
Beat Hangartner 7866a37f14 Wait for the window to be active in the menu bar keyboard tests
tst_menubarkeyboard sends Alt+F and F10 right after the test window is
exposed, then sleeps 300 ms and checks. Menu mnemonics and the F10
shortcut (a Qt::WindowShortcut) only fire in the active window, and
being exposed does not mean being active: on a loaded Xvfb, or on macOS
with another application in front, activation arrives later and the key
is dropped. The sleep comes after the key and cannot help. This made
shortcutOpensMenuBar fail on #1420's Linux CI ("F10 did not activate the
menu bar") while the same base passed on #1421 and #1422, and made the
Alt+F control fail in 1 of about 33 local runs with the cocoa platform.

Every test now waits for the window to be active before pressing a key
(qWaitForWindowActive, with its own failure message), and the two tests
that expect a menu poll for it with QTRY_VERIFY2 instead of a fixed
sleep. plainF10DoesNothingInQt keeps its 300 ms: it checks that nothing
happens, which cannot be polled for; with the window now active first,
that check can no longer pass merely because the key went nowhere.

Test-only change. Checked: with a second window active, F10 sent to the
exposed but inactive window does not activate its menu bar (offscreen
and cocoa); once it is active, it does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:30:27 +02:00
Laurent Trinques cbcdcf88ba Merge pull request #1422 from bhangart/fix/lang-pl-update
Update qet_pl.ts: 61 new strings and term corrections
2026-10-09 14:29:39 +02:00
Laurent Trinques bdd623ea47 Merge pull request #1421 from bhangart/fix/lang-de-update
Update qet_de.ts: 61 new strings and the SPS wording
2026-10-09 14:29:23 +02:00
Laurent Trinques fb847c8fc5 Merge pull request #1420 from bhangart/fix/lang-fr-plurals
Give the French plural messages real singular and plural forms
2026-10-09 14:28:45 +02:00