Project

General

Profile

Bug #10692

Numeric FILL-IN: Problems with formats using debit/credit sign placeholders

Added by Vladimir Tsichevski 10 months ago. Updated 5 months ago.

Status:
WIP
Priority:
Normal
Assignee:
Vladimir Tsichevski
Target version:
-
Start date:
Due date:
% Done:

90%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
16212
version_resolved:
reviewer:
production:
No
env_name:
topics:

NumericFormattingCRDBTest.cls (1.79 KB) Vladimir Tsichevski, 02/05/2026 03:35 PM


Related issues

Related to User Interface - Bug #7794: FILL-IN: editing numbers issues WIP
Copied to User Interface - Bug #11192: Numeric FILL-IN: Caret position is not adjusted when value sign changes New

History

#1 Updated by Vladimir Tsichevski 10 months ago

Numeric formats support three methods for displaying the sign of a value:

  1. Using + or - placeholders, either before or after the numeric part (e.g., ->>9.99, +>>9.99, >>9.99+, >>9.99-).
  2. Using opening and closing parentheses (e.g., ((>>9.99)).
  3. Using CR (credit), or DR or DB (debit) as exact suffixes (e.g., >>9.99DB, +>>9.99CR, >>9.99Dr, >>9.99dB).

The CR, DB, and DR modifiers:

  1. Are case-insensitive (e.g., DR, Dr, dR, dr are equivalent).
  2. Must match exactly as the suffix (e.g., recognized in >>9.99dR but ignored in >>9.99abcdR, >>9.99dRabc, or >>9.99dRdR).
  3. Are interchangeable; all indicate a negative value.
  4. Are inserted as defined in the format, preserving case (e.g., -1 with >>9.99dR formats as 1.00dR).
  5. Can coexist with other sign placeholders:
    1. Pre-numeric sign (+/-): Both apply simultaneously (e.g., -1 with ->>9.99dR formats as -1.00dR).
    2. Post-numeric sign (+/-) or parentheses: Modifier is ignored (e.g., 1 with >>9.99-dR formats as 1.00dR).
  6. 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:

  1. In OE: The modifier is removed (e.g., 1 with ->>9.99dR formats as 1.00 with no trailing spaces).
  2. In FWD: The modifier is replaced by spaces (e.g., 1 with ->>9.99dR formats as 1.00 with two trailing spaces).

Issue 2

If the modifier is present (regardless of pre-numeric sign) and the caret is positioned after the last digit:

  1. In OE: Entering + or - changes the screen value accordingly.
  2. In FWD: Entering + or - does nothing.

Issue 3

  1. In OE: Deleting either character of the two-character modifier in any way (with DELETE-CHARACTER, BACKSPACE key, or CUT operation) removes the modifier.
  2. 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.

#3 Updated by Vladimir Tsichevski 6 months ago

Additional tests for ignoring modifiers with post-numeric sign (+/-) or parentheses:

      test(123.45, ">>9.99+CR", "123.45+CR").
      test(123.45, ">>9.99-CR", "123.45 CR").
      test(123.45, "(>>9.99)DB", " 123.45 DB").      

#4 Updated by Vladimir Tsichevski 6 months ago

Vladimir Tsichevski wrote:

Issue 1

For non-negative values:

  1. In OE: The modifier is removed (e.g., 1 with ->>9.99dR formats as 1.00 with no trailing spaces).
  2. In FWD: The modifier is replaced by spaces (e.g., 1 with ->>9.99dR formats as 1.00 with 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), DB or DR (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, dr are 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. -1 with >>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. -1 with ->>9.99dR" -1.00dR").

    Post-numeric sign (+/-) or parentheses: the CR/DB/DR suffix is ignored
    (e.g. 1 with >>9.99-dR" 1.00dR";
    -1 with (>>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.

#7 Updated by Vladimir Tsichevski 6 months ago

I created the 10692a branch to address this issue.

#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:

  1. The internal state (digits, scale, negative) is converted to a decimal value.
  2. This decimal is formatted using decimal.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.

#9 Updated by Vladimir Tsichevski 6 months ago

  • Related to Bug #7794: FILL-IN: editing numbers issues added

#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

  1. Obtains character type and digit position for the caret location
  2. Determines the corresponding format placeholder symbol (formatSymbol)
  3. Temporarily sets presInsertMode flag based on that symbol
  4. Calls super.input(ch)
  5. Restores original presInsertMode value

Root cause (when format has no decimal point)

When there is no fractional part in the format:

  • digitPos is only valid when caret is on a digit or decimal separator
  • If caret is on a group separator (comma) or other non-digit position → digitPos leads 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

  1. In this situation, we should still allow sign toggle (no need to calculate formatSymbol or change presInsertMode)
  2. presInsertMode is not used when processing + / - keys
  3. presInsertMode appears 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 presInsertMode logic 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

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

  1. Any mode (GUI or CHARACTER).
  2. Format includes valid CR/DB/DR specifier.
  3. Screen value shows a non-negative number.
  4. Caret is positioned on the last digit.
  5. 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.

#19 Updated by Vladimir Tsichevski 5 months ago

  • % Done changed from 50 to 90

10692a rev. 16413 fixes issues 1,2,3 (completely) and issue 4 (for GUI mode only).

Also available in: Atom PDF