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.
Cables are drawn line objects (toolbar button next to the auto
break/reconnect button, click-move-click, right click cancels), not
components. The type comes from a CSV catalog following the material
list pattern (designation, cores, core colours, editable through the
entry dialog with "Nouvelle entrée" / "Modifier l'entrée").
Each core is bound to the wire its colour label stands on, and the
cable reference is generated per core and written into the Conductor
entry via Conductor::setCableReference(label, cable uuid, slot). The
conductor entry is where it has to live because the terminal strip
plan (Klemmenplan) consumes it in the next step.
Numbering: "Cables" rule under Programmeinstellungen/Neues
Projekt/Nummerierung auto (mirrored in project properties), literal
"W" fallback without a rule, French gate dialog when no rule exists,
Nummerierung menu with the renumber dialog (preferred axis, per-folio
counter, rule and counter state written back, hand-typed names ask,
whole-project scope).
Also included: label block and under-line texts with per-text font and
alignment plus the material-list cell margins, free-core placement and
right-click removal, claim questions for wires of other cables,
multi-selection drag as one undo step, type change with confirmation,
cross-references for type "Cable" (%f-%l%c, own font, clickable links
in exported PDFs), report propagation of the cable definition,
Listes menu (table of contents, material list, terminal strip manager,
terminal generator plugin, cable list), cable list with freely
selectable columns (installation/localisation of cable, start and end,
Blatt start/end, length, used cores...), CSV export dialog with column
pick and preview in the Projekt menu, script API (addTable kind
"cable_list", exportCableList) and a unit test for the type catalog.
Every tr() source string in the code and the forms is now the English
text, and French is a translation (qet_fr.ts) like the other languages.
Generated, not hand-edited: master ef795a21e5 converted by
qet-en-source (harness 4c4ddc9).
3144 messages get an English source, 665 already had one, 0 left French; 8 shared-wording pairs disambiguated.
C++: 2904 literals in 233 files. Forms: 809 strings in 65 files. All 34 .ts files re-keyed; qet_fr.ts filled.
lupdate check: PASS. What each of 38 languages shows, old vs new: same 118266, English instead of French 38433, comment fallback 51, differences 0.
A cyclic part could only ever be rendered at its natural width, which is
fine for one of @scorpio810's two real layouts and wrong for the other:
April 5000/2000, 32-point cards %IX0.0 .. %IX0.31, then %IX1.0
Schneider M340, 64-point cards I1.00 .. I1.63, then I2.00
The first wants no padding, the second wants two digits. Since the two
conflict, the width cannot be derived from the modulus or from the part
type -- it has to be the user's to set.
Add a format field holding a run of zeros, the same convention a
spreadsheet uses for integer padding: "00" renders 7 as 07, "000" as 007.
The field's length is the minimum number of digits. It applies to every
numeric part type, not only cyclic ones, so "Chiffre 01" can be widened
past two digits without inventing another type for it.
An empty mask means the part type's own natural width, so it reproduces
exactly what every existing context does today -- Chiffre 1 stays 7,
Chiffre 01 stays 07, Chiffre 001 stays 007. That is what makes this safe
for existing projects: absent is the default, and absent changes nothing.
Stored as a sixth field on the context part and as an XML attribute
written only when set, following how modulus was added: readers guard on
size() and treat a short item as "no format". All seven places that
rebuild a part while incrementing it now carry the format through --
missing one would have silently dropped the padding on the second element
numbered.
The editor field is restricted to zeros by a validator, and is enabled
only for types that render as a number.
Measured:
April, mask empty %IX0.29 %IX0.30 %IX0.31 %IX1.0 %IX1.1
M340, mask "00" I1.00 I1.01 ... I1.62 I1.63 I2.00 I2.01
no mask unit 7,8,9 ten 07,08,09 hundred 007,008,009
ten with mask "0000" 0007 0008 0009
Turning the default "Chiffre 1" part into a "Cyclique (modulo)" one left
the modulus spin box at 0, and a modulus of 0 means "no cycle" -- so the
part counted upward forever instead of wrapping, which is the whole point
of the type. Reported on #593 against a modulus-7 test and, more usefully,
against a real April 5000 PLC layout addressed %IX0.0..%IX0.31 per card.
setType() defaulted the modulus to 8 inside the block that installs numeric
behaviour, and that block runs only when the *previous* type was
non-numeric. Switching from one numeric type to another skips it. Since a
fresh part starts out as "Chiffre 1", the ordinary way to reach this
feature -- change the type of the part in front of you -- was exactly the
path that skipped the default. Going the long way round, via "Texte", set
the modulus to 8 and worked, which is why the feature tests fine when you
build the context some other way.
Moved the default out of that block so it applies whatever the part was
before, and made it fire only when the current modulus is unusable, so a
value the user picked on purpose survives switching type away and back.
The wrap/carry arithmetic itself was already correct: with a carry target
in front of it, a modulus-32 part yields %IX0.0..%IX0.31, %IX1.0 as asked.
Saved configurations are untouched -- a stored modulus, including a 0 left
behind by this bug, still loads and round-trips exactly as it was.
Adds a real base-26 incrementing part type to the autonumbering engine,
alongside the 14 existing NumStrategy leaves. Unlike StringNum (a fixed,
non-incrementing text segment), AlphaNum::next()/previous() carry/borrow
entirely within the part's own value -- the composition loop in
NumerotationContextCommands doesn't need to change, since (unlike #578's
wrap-and-carry) nothing here needs to signal an adjacent part.
- incrementAlpha()/decrementAlpha() implement the spreadsheet-column-name
algorithm: increment carries right-to-left on 'z'/'Z' overflow,
prepending a new leading letter if the whole value overflows (z -> aa,
az -> ba). decrement is the exact inverse, including the symmetric
shrink case (aa -> z) once every position has borrowed. A single letter
already at "a"/"A" has no representable predecessor and is clamped
rather than turned into "z" -- caught via manual testing, since the
initial implementation mutated the string in the borrow loop before
checking whether to clamp, silently discarding the original value.
- Registered in NumerotationContext::validRegExpNum() but deliberately
not in validRegExpNumber(), so addValue() doesn't force alphabetic
values through int conversion.
- New "Cyclique"-adjacent "Alphabétique" entry in numparteditorw's type
dropdown, with its own letters-only QRegularExpressionValidator; the
increase spinbox is disabled since the step is always exactly one
letter, not a configurable amount.
Also wires the new part type through to actual element/conductor labels,
which turned out to be required for the feature to do anything visible
beyond folio numbering (which applies a NumerotationContext's
represented string directly). Element and conductor numbering instead
go through a separate formula-substitution layer
(autonum::sequentialNumbers + %sequ_/%seqt_/%seqh_-style placeholders in
AssignVariables::assignSequence()) that numerotationContextToFormula()
auto-populates. Without a matching placeholder, an "alpha" part would
silently vanish from the generated formula and never reach the label,
even though the underlying counter was advancing correctly:
- sequentialNumbers gained an `alpha` QStringList member (copy ctor,
operator=, operator==, toXml/fromXml, clear()).
- numerotationContextToFormula() emits a new %seqa_N placeholder for
alpha parts, the same way %sequ_N is emitted for unit parts.
- setSequential()/setSequentialToList() populate seqStruct.alpha,
passing the raw string through as-is rather than the .toInt()-based
formatting used for the numeric part types.
- AssignVariables::assignSequence() substitutes %seqa_N from
seqStruct.alpha, mirroring the existing %sequ_N/%seqt_N/%seqh_N
substitutions.
No "alphafolio" variant was added, matching the discussion's scope (only
unit/ten/hundred have folio-anchored variants).
Verified against production code via the numbering config dialog's own
Suivant/Précédent buttons: from "a", 25 clicks reached "z"; one more
produced "aa"; 25 more reached "az"; one more produced "ba" (carry).
Reversed: "ba"->"az"->(25 clicks)->"aa"->"z" (shrink)->(25 clicks)->"a".
One more "previous" at "a" correctly stayed at "a" after the clamp fix.
Also confirmed the Formule field auto-updates to "%seqa_1" the instant
the type is switched to "Alphabétique", confirming the formula-generation
wiring works live in the UI, not just at the engine level.
Adds a configurable wrap-at-N counter type to the autonumbering engine
(NumerotationContext + NumerotationContextCommands), covering PLC/rack-style
addressing conventions like "e0.0...e0.7, e1.0...e1.7" (8 channels per
card) generally, rather than hardcoding octal specifically.
- New "wrap" part type (WrapNum, alongside the existing UnitNum/TenNum/
HundredNum strategies) stores a modulus in addition to the existing
value/increase/initialvalue fields. Its own next()/previous() only wraps
its own value modulo the configured modulus -- carrying into (or
borrowing from) the adjacent part requires visibility across parts,
which only the composition loop has.
- NumerotationContextCommands::next()/previous() gained carry()/borrow()
helpers: when a wrap part's own next() would reach/exceed its modulus
(or go below 0 on previous()), the nearest preceding numeric part is
bumped by exactly one unit, skipping non-numeric parts (e.g. a "."
string separator). Wrap parts chain correctly if adjacent (e.g. seconds
wrapping into minutes wrapping into hours).
- For the leading part of a wrap-and-carry pair to stay fixed except when
carried into (i.e. actually produce "e0.0...e0.7, e1.0..." rather than
advancing on every step under its own strategy), its own increase must
be 0. The increase spinbox's minimum was 1, which made this
configuration impossible through the UI -- lowered to 0 and documented
with a tooltip, since this wasn't obvious from the UI alone.
- NumerotationContext gained a 5th pipe-separated field (modulus) in its
serialized string form, defaulting to 0 (non-wrapping) for every
existing part type; toXml()/fromXml() persist it as a "modulus" XML
attribute the same way "initialvalue" is already persisted for
unitfolio/tenfolio/hundredfolio.
- New "Cyclique (modulo)" entry in the part-type dropdown (numparteditorw),
available for element, conductor, and folio autonumbering alike, since
all three already go through NumerotationContextCommands.
Verified in the running app via the numbering config dialog's own
Suivant/Précédent buttons (which call the production
NumerotationContextCommands::next()/previous() directly): a two-part
context (unit, increase=0 + wrap mod 8) produced exactly
e0.0→...→e0.7→e1.0→...→e1.7 on repeated "next", and the exact reverse
(with correct borrowing) on repeated "previous".