Bug #10692
Numeric FILL-IN: Problems with formats using debit/credit sign placeholders
90%
Related issues
History
#1 Updated by Vladimir Tsichevski 10 months ago
Numeric formats support three methods for displaying the sign of a value:
- Using
+or-placeholders, either before or after the numeric part (e.g.,->>9.99,+>>9.99,>>9.99+,>>9.99-). - Using opening and closing parentheses (e.g.,
((>>9.99)). - Using
CR(credit), orDRorDB(debit) as exact suffixes (e.g.,>>9.99DB,+>>9.99CR,>>9.99Dr,>>9.99dB).
The CR, DB, and DR modifiers:
- Are case-insensitive (e.g.,
DR,Dr,dR,drare equivalent). - Must match exactly as the suffix (e.g., recognized in
>>9.99dRbut ignored in>>9.99abcdR,>>9.99dRabc, or>>9.99dRdR). - Are interchangeable; all indicate a negative value.
- Are inserted as defined in the format, preserving case (e.g.,
-1with>>9.99dRformats as1.00dR). - Can coexist with other sign placeholders:
- Pre-numeric sign (
+/-): Both apply simultaneously (e.g.,-1with->>9.99dRformats as-1.00dR). - Post-numeric sign (
+/-) or parentheses: Modifier is ignored (e.g.,1with>>9.99-dRformats as1.00dR).
- Pre-numeric sign (
- For input: Deleting either character of the two-character modifier removes both (but the modifier is restored if the value is negative due to a pre-numeric sign).
Issue 1¶
For non-negative values:
- In OE: The modifier is removed (e.g.,
1with->>9.99dRformats as1.00with no trailing spaces). - In FWD: The modifier is replaced by spaces (e.g.,
1with->>9.99dRformats as1.00with two trailing spaces).
Issue 2¶
If the modifier is present (regardless of pre-numeric sign) and the caret is positioned after the last digit:
- In OE: Entering
+or-changes the screen value accordingly. - In FWD: Entering
+or-does nothing.
Issue 3¶
- In OE: Deleting either character of the two-character modifier in any way (with
DELETE-CHARACTER,BACKSPACEkey, orCUToperation) removes the modifier. - In FWD: The modifier cannot be removed by deleting the modifier or a part of it; it can only be removed by pressing
+.
#2 Updated by Vladimir Tsichevski 6 months ago
- Status changed from New to WIP
I've created ABLUnit test cases for formatting with STRING. Special care was taken to protect all spaces from trimming:
USING OpenEdge.Core.Assert.
ROUTINE-LEVEL ON ERROR UNDO, THROW.
CLASS unittests.base.numeric.NumericFormattingTest:
@Before.
METHOD PUBLIC VOID BeforeClass():
SESSION:SET-NUMERIC-FORMAT(",",".").
END METHOD.
// ... other tests
@Test.
METHOD PUBLIC VOID TestCRDB():
test( 123.45, ">>9.99CR", "123.45 ").
test(-123.45, ">>9.99CR", "123.45CR").
test( 123.45, ">>9.99DB", "123.45 ").
test(-123.45, ">>9.99DB", "123.45DB").
test( 123.45, ">>9.99DR", "123.45 ").
test(-123.45, ">>9.99DR", "123.45DR").
test(-123.45, ">>9.99cr", "123.45cr").
test(-123.45, ">>9.99dR", "123.45dR").
test(-123.45, ">>9.99Dr", "123.45Dr").
test(-123.45, "->>9.99CR", "-123.45CR").
test(-123.45, "+>>9.99DB", "-123.45DB").
test(-123.45, ">>9.99+CR", "123.45-CR").
test(-123.45, "(>>9.99)DB", "(123.45)DB").
test(0, ">>9.99CR", " 0.00 ").
END METHOD.
/**
* Execute the test, compare result with the expected value.
*/
METHOD PRIVATE VOID test(INPUT v AS DECIMAL, INPUT fmt AS CHARACTER, INPUT expectedResult AS CHARACTER):
DEFINE VARIABLE rc AS CHARACTER NO-UNDO.
rc = STRING(v, fmt).
Assert:Equals(expectedResult, rc).
Assert:Equals(LENGTH(expectedResult), LENGTH(rc)).
END METHOD.
END CLASS.
#4 Updated by Vladimir Tsichevski 6 months ago
Vladimir Tsichevski wrote:
Issue 1¶
For non-negative values:
- In OE: The modifier is removed (e.g.,
1with->>9.99dRformats as1.00with no trailing spaces).- In FWD: The modifier is replaced by spaces (e.g.,
1with->>9.99dRformats as1.00with two trailing spaces).
This issue rejected: more careful testing shows trailing spaces are necessary, so FWD behaves correctly.
#5 Updated by Vladimir Tsichevski 6 months ago
Numeric Formats Using Debit/Credit Sign Placeholders¶
Numeric formats support three ways to display the sign of a value:
- Using
+or-placeholders, either before or after the numeric part
(e.g.->>9.99,+>>9.99,>>9.99+,>>9.99-).
- Using opening and closing parentheses
(e.g.((>>9.99),(>>9.99)).
- Using
CR(credit),DBorDR(debit) as exact suffixes
(e.g.>>9.99DB,+>>9.99CR,>>9.99Dr,>>9.99dB).
Recognition of CR/DB/DR suffixes¶
The CR, DB, and DR modifiers:
- Affect formatting only — they are not validated during format parsing.
- Must appear exactly as the suffix (nothing after them).
→** Recognized in>>9.99dR
**→ Ignored in>>9.99abcdR,>>9.99dRabc,>>9.99dRdR.
- Are case-insensitive during recognition (
DR,Dr,dR,drare equivalent).
- Are case-preserving in the output (the case you write is the case you get).
Formatting behavior with CR/DB/DR¶
- For negative values: the suffix is inserted exactly as written in the format, preserving case
(e.g.-1with>>9.99dR→" 1.00dR").
- For positive values: the suffix is replaced by two spaces
(these spaces are not trimmed from the output).
- The three modifiers (
CR,DB,DR) are interchangeable — all indicate a negative value.
- They can coexist with other sign placeholders:
Pre-numeric sign (
+/-): both are applied
(e.g.-1with->>9.99dR→" -1.00dR").Post-numeric sign (
+/-) or parentheses: the CR/DB/DR suffix is ignored
(e.g.1with>>9.99-dR→" 1.00dR";
-1with(>>9.99)CR→"(123.45)").
- CR/DB/DR cannot be used for space reuse (sign position reuse)
(unlike ordinary-or+placeholders).Example (fails):
STRING(12345.456, ">>>9.99<CR")→ Value 12345.46 cannot be displayed using >>>9.99<CR.Example (succeeds):
STRING(12345.456, "->>>9.99<")→"12345.46"(ordinary sign is reused).
#6 Updated by Vladimir Tsichevski 6 months ago
FWD Defects (GUI mode only, verified after detailed testing)
Issue 1 – Suffix not removed (replaced by spaces) for non-negative values¶
Format example: ->>9.99dR, value = 1 (non-negative)
- OE: suffix completely removed →
1.00 - FWD: suffix replaced by two spaces →
1.00(incorrect)
Issue 2 – + / - keys ignored when caret is after last digit (suffix visible)¶
Suffix visible (negative value), caret positioned after the last digit, immediately before the suffix, or at the decimal delimiter:
- OE: typing
+or-toggles sign correctly - FWD: typing
+or-is ignored (no effect)
Issue 3 – Suffix cannot be removed by deleting its characters¶
When no pre-numeric minus placeholder is used:
- OE: Deleting the first character of the suffix (via BACKSPACE, DELETE-CHARACTER, or CUT) removes the entire suffix
- FWD: Deleting any part of the suffix has no effect; suffix can only be removed by typing
+
OE-specific glitch (do not replicate in FWD)¶
In both CHARACTER and GUI modes, when using a format with leading plus placeholder (e.g. +>>9.99dR) and entering any value other than ?:
- OE intermittently shows error dialogs:
- "Invalid character in numeric input ?."
- sometimes followed by "** Value 251658241 cannot be displayed using <format>" (the number can be arbitrary and unrelated)
- After dismissing the dialogs, the correct value is displayed in the FILL-IN
This is an internal OE bug (likely memory misinterpretation).
FWD must not reproduce this error behaviour.
#8 Updated by Vladimir Tsichevski 6 months ago
- % Done changed from 0 to 30
Fix for Issue 1 – Suffix not removed for non-negative values in GUI mode¶
The screen-value formatting logic for numeric FILL-IN widgets is implemented in: NumberBuf.renderScreen().
This method is not overridden in the mode-specific subclasses:
NumberBufChar(ChUI)NumberBufGui(GUI)
Therefore the same implementation is used in both GUI and ChUI modes.
Inside NumberBuf.renderScreen() the following steps occur:
- The internal state (
digits,scale,negative) is converted to adecimalvalue. - This
decimalis formatted usingdecimal.toString(format), which:
- Applies the full numeric format string
- Handles CR/DB/DR suffix insertion (only for negative values)
- Appends trailing spaces for non-negative values when a debit/credit suffix is defined in the format
The trailing spaces for non-negative values are correct and required when the formatting result is used in:
- ABL
STRING(value, "format")function - CHARACTER mode screen rendering
Modifying decimal.toString() or the underlying formatting logic would break these use cases.
Proposed solution¶
Keep decimal.toString(format) unchanged (preserve correct behaviour for STRING and ChUI).
Instead, post-process the result only in GUI mode:
final String untrimmed = screenBuf.toString();
screen = Utils.isChUI()
? untrimmed
: StringHelper.safeTrimTrailing(untrimmed);
The 10692a rev. 16376 contains the fix.
#10 Updated by Vladimir Tsichevski 6 months ago
Vladimir Tsichevski wrote:
FWD Defects (GUI mode only, verified after detailed testing)
Issue 2 – + / - keys ignored when caret is after last digit (suffix visible)¶
Suffix visible (negative value), caret positioned after the last digit, immediately before the suffix, or at the decimal delimiter:
- OE: typing
+or-toggles sign correctly- FWD: typing
+or-is ignored (no effect)
This problem is not specific to CR/DB/DR suffixes.
The + / - keys are ignored when the caret is positioned immediately before a group delimiter if the format contains no decimal point for both integer and decimal variables.
This behavior was first reported for integer variables in #7794-2.
#11 Updated by Vladimir Tsichevski 6 months ago
- % Done changed from 30 to 50
Fix for Issue 2 – + / - keys ignored for some caret positions in GUI mode¶
The problematic logic is in NumberBufGui.input(char):
if (presCursorPos < screen.length() && presCursorPos >= 0)
{
...
ScreenCharInfo currPos = screenInfo[presCursorPos];
int digitPos = currPos.digitPos;
...
final char formatSymbol;
final String digitsLeft = fs.digitsLeft;
final String digitsRight = fs.digitsRight;
if (digitPos >= 0)
{
formatSymbol = digitsLeft.charAt(digitsLeft.length() - 1 - digitPos);
}
else
{
if (digitsRight.length() + digitPos < 0)
{
return false; // <--- this is obviously wrong!!!
}
formatSymbol = digitsRight.charAt(-digitPos - 1);
}
... modify the presInsertMode field based on formatSymbol and other data
}
else
... modify the presInsertMode field based on other data
return super.input(ch);
}
finally
{
presInsertMode = saveMode;
}
What this code does¶
- Obtains character type and digit position for the caret location
- Determines the corresponding format placeholder symbol (
formatSymbol) - Temporarily sets
presInsertModeflag based on that symbol - Calls
super.input(ch) - Restores original
presInsertModevalue
Root cause (when format has no decimal point)¶
When there is no fractional part in the format:
digitPosis only valid when caret is on a digit or decimal separator- If caret is on a group separator (comma) or other non-digit position →
digitPosleads to -1 value, which is still used in calculation, but must never be used for types other than digit and decimal separator. - Code hits this guard:
if (digitsRight.length() + digitPos < 0) { return false; } - Method returns early →
super.input(ch)is never called →+/-are ignored
Why this is incorrect¶
- In this situation, we should still allow sign toggle (no need to calculate
formatSymbolor changepresInsertMode) presInsertModeis not used when processing+/-keyspresInsertModeappears to be relevant only for CHARACTER mode insertion/overwrite behaviour — it is very likely irrelevant in GUI mode entirely
Proposed fix¶
Bypass the problematic logic when caret is on a non-digit position that should still allow sign input:
Add this early return before the digitPos calculation block:
if (type == ScreenCharInfo.GROUP_SEP ||
type == ScreenCharInfo.STR_LEFT ||
type == ScreenCharInfo.STR_RIGHT)
{
return super.input(ch);
}
This ensures:
+and-are processed correctly at group separators and literal prefixes/suffixes.- No change to existing
presInsertModelogic for digit positions - No risk to ChUI behavior
- Sign toggle now works at any caret position where digit position cannot be meaningfully calculated
Patch is implemented in 10692a rev. 16378.
#12 Updated by Vladimir Tsichevski 6 months ago
Issue 1 fix is incomplete: caret position is not adjusted after suffix removal
The current fix for Issue 1 does not adjust the caret position correctly in the following scenario:
- Format includes a debit/credit suffix
- Current value is negative → suffix is visible on screen
- Caret is positioned inside the suffix or immediately after the suffix
- User presses
+to change value to positive → suffix is removed
Observed (incorrect) behavior:
After suffix removal and right-trimming of spaces:
- Caret remains at its previous absolute screen position
- This places the caret one or two characters to the right of the new valid input end (i.e. after the last digit or decimal point)
#13 Updated by Hynek Cihlar 6 months ago
Vladimir, please make sure to check in any test cases that are still unchecked.
#14 Updated by Vladimir Tsichevski 6 months ago
- File NumericFormattingCRDBTest.cls added
Hynek Cihlar wrote:
Vladimir, please make sure to check in any test cases that are still unchecked.
Attached: NumericFormattingCRDBTest.cls (improved version of the one in #10692-2).
#15 Updated by Vladimir Tsichevski 5 months ago
- Copied to Bug #11192: Numeric FILL-IN: Caret position is not adjusted when value sign changes added
#16 Updated by Vladimir Tsichevski 5 months ago
Vladimir Tsichevski wrote:
Issue 1 fix is incomplete: caret position is not adjusted after suffix removal
The issue is broader: caret position is never adjusted on sign change (any sign specifier, any initial position).
Registered as separate task #11192.
#17 Updated by Vladimir Tsichevski 5 months ago
Issue 4: Wrong caret position after digit input in non-negative CR/DB/DR format¶
Scenario¶
- Any mode (GUI or CHARACTER).
- Format includes valid CR/DB/DR specifier.
- Screen value shows a non-negative number.
- Caret is positioned on the last digit.
- User enters a new digit.
Observed behavior¶
- OE: the digit under caret is replaced, and caret moves one position right (past the entered digit).
- FWD: the digit under caret is replaced (correct), but caret moves two spaces right after the entered digit (incorrect).
#18 Updated by Vladimir Tsichevski 5 months ago
Issue 3 Update: Deleting any sign specifier in the string value (other than minus sign) does nothing in FWD¶
When the screen value contains any sign specifier (e.g. CR/DR/DB, parentheses) other than a simple minus sign:
- In OE, deleting (via BACKSPACE, DELETE-CHARACTER, or CUT) the sign specifier (or the first character of CR/DR/DB suffix) makes the value non-negative.
- In FWD: Attempting the similar operation has no effect.