Summary
When a range filter with an integer-typed value (Degree, In/Out-Degree, Mutual Degree, integer attribute ranges, edge weight when integer, etc.) is displayed after the filter panel has been rebuilt (e.g., select another filter then click back, or any code path going through JRangeSliderPanel.setRange), the slider handles snap to the track extremes even though the labels still show the correct selected lower/upper values. Visually it looks like the slider's bounds shrank to the user's selection.
Steps to reproduce
- Open a graph (e.g., Les Misérables).
- Drag the Degree Range filter into the queries panel. The slider correctly shows e.g. min=1, max=36.
- Move the lower handle to the middle (e.g. lower=11). Slider looks correct.
- Click Filter.
- Add another filter (e.g. Ego Network), so the Degree Range panel is unmounted.
- Click back on Degree Range.
The slider now shows both handles pinned to the extremes, with labels still reading "11" and "36". The underlying Range model is still correct (min=1, max=36); only the slider rendering is wrong.
Root cause
JRangeSliderPanel.Range.refreshSlider() normalizes the lower/upper bounds with:
double normalizedLow = (lowerBoundBigDecimal.subtract(minBigDecimal))
.divide(maxBigDecimal.subtract(minBigDecimal), RoundingMode.HALF_UP)
.doubleValue();
BigDecimal.divide(BigDecimal, RoundingMode) returns a result with the dividend's scale. For integer-typed ranges both operands have scale 0, so the result is rounded to an integer (0 or 1). Examples for min=1, max=36:
- lower=11 →
(10).divide(35, HALF_UP) = 0 → handle at left edge
- upper=36 →
(35).divide(35, HALF_UP) = 1 → handle at right edge
The bug only shows after the panel is rebuilt, because:
- The first time the filter is shown, lower==min and upper==max, so the divisions yield exactly 0 and 1 (no rounding error).
- While dragging,
refreshBounds() runs instead and uses double arithmetic, which is not affected.
setRange() → refreshSlider() (called when a new RangePanel is built) is the only path that hits the truncating divide.
Fix
Use MathContext.DECIMAL64 (or any explicit scale) so the division preserves precision regardless of operand scale.
Affected filters
All RangeFilter implementations whose range type is integer (Integer, Long, Short, Byte, BigInteger): Degree Range, In/Out-Degree Range, Mutual Degree Range, integer attribute ranges, integer edge weight ranges, etc. Float/Double ranges were unaffected because their BigDecimals have non-zero scale.
Summary
When a range filter with an integer-typed value (Degree, In/Out-Degree, Mutual Degree, integer attribute ranges, edge weight when integer, etc.) is displayed after the filter panel has been rebuilt (e.g., select another filter then click back, or any code path going through
JRangeSliderPanel.setRange), the slider handles snap to the track extremes even though the labels still show the correct selected lower/upper values. Visually it looks like the slider's bounds shrank to the user's selection.Steps to reproduce
The slider now shows both handles pinned to the extremes, with labels still reading "11" and "36". The underlying
Rangemodel is still correct (min=1, max=36); only the slider rendering is wrong.Root cause
JRangeSliderPanel.Range.refreshSlider()normalizes the lower/upper bounds with:BigDecimal.divide(BigDecimal, RoundingMode)returns a result with the dividend's scale. For integer-typed ranges both operands have scale 0, so the result is rounded to an integer (0or1). Examples for min=1, max=36:(10).divide(35, HALF_UP)=0→ handle at left edge(35).divide(35, HALF_UP)=1→ handle at right edgeThe bug only shows after the panel is rebuilt, because:
refreshBounds()runs instead and usesdoublearithmetic, which is not affected.setRange()→refreshSlider()(called when a newRangePanelis built) is the only path that hits the truncating divide.Fix
Use
MathContext.DECIMAL64(or any explicit scale) so the division preserves precision regardless of operand scale.Affected filters
All
RangeFilterimplementations whose range type is integer (Integer, Long, Short, Byte, BigInteger): Degree Range, In/Out-Degree Range, Mutual Degree Range, integer attribute ranges, integer edge weight ranges, etc. Float/Double ranges were unaffected because their BigDecimals have non-zero scale.