From e4356f364d0eec1ad9da9dc50bcee8cdc705bd0f Mon Sep 17 00:00:00 2001 From: shirazhassan Date: Thu, 8 Jan 2026 23:41:23 +0100 Subject: [PATCH] Add regression unit test for ColorSliderUI repaint bug Fix ColorSliderUI repaint crash in fill palette --- jhotdraw-gui/pom.xml | 15 ++++++ .../org/jhotdraw/color/ColorSliderUI.java | 2 +- .../PaletteColorWheelChooser.java | 2 +- .../color/ColorSliderUIRegressionTest.java | 51 +++++++++++++++++++ .../samples/color/WheelsAndSlidersMain.java | 4 +- 5 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 jhotdraw-gui/src/test/java/org/jhotdraw/color/ColorSliderUIRegressionTest.java diff --git a/jhotdraw-gui/pom.xml b/jhotdraw-gui/pom.xml index 0c7a5da84..cb558ddac 100644 --- a/jhotdraw-gui/pom.xml +++ b/jhotdraw-gui/pom.xml @@ -9,6 +9,12 @@ jhotdraw-gui jar + + org.junit.jupiter + junit-jupiter + 5.8.1 + test + ${project.groupId} jhotdraw-utils @@ -30,5 +36,14 @@ ${project.version} + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + + jhotdraw-gui \ No newline at end of file diff --git a/jhotdraw-gui/src/main/java/org/jhotdraw/color/ColorSliderUI.java b/jhotdraw-gui/src/main/java/org/jhotdraw/color/ColorSliderUI.java index 2fca25736..6360be9c0 100644 --- a/jhotdraw-gui/src/main/java/org/jhotdraw/color/ColorSliderUI.java +++ b/jhotdraw-gui/src/main/java/org/jhotdraw/color/ColorSliderUI.java @@ -314,7 +314,7 @@ public void paintColorTrack(Graphics g, int x, int y, int width, int height, int } } if (colorTrackImage != null) { - g.drawImage(colorTrackImage, x, y, slider); + g.drawImage(colorTrackImage, x, y, null); } } diff --git a/jhotdraw-gui/src/main/java/org/jhotdraw/gui/plaf/palette/colorchooser/PaletteColorWheelChooser.java b/jhotdraw-gui/src/main/java/org/jhotdraw/gui/plaf/palette/colorchooser/PaletteColorWheelChooser.java index 1fe52d1c3..f89d69112 100644 --- a/jhotdraw-gui/src/main/java/org/jhotdraw/gui/plaf/palette/colorchooser/PaletteColorWheelChooser.java +++ b/jhotdraw-gui/src/main/java/org/jhotdraw/gui/plaf/palette/colorchooser/PaletteColorWheelChooser.java @@ -105,4 +105,4 @@ public void setColorToModel(Color color) { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JSlider brightnessSlider; // End of variables declaration//GEN-END:variables -} +} \ No newline at end of file diff --git a/jhotdraw-gui/src/test/java/org/jhotdraw/color/ColorSliderUIRegressionTest.java b/jhotdraw-gui/src/test/java/org/jhotdraw/color/ColorSliderUIRegressionTest.java new file mode 100644 index 000000000..630e1712c --- /dev/null +++ b/jhotdraw-gui/src/test/java/org/jhotdraw/color/ColorSliderUIRegressionTest.java @@ -0,0 +1,51 @@ +package org.jhotdraw.color; + +import org.junit.jupiter.api.Test; + +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; + +import static org.junit.jupiter.api.Assertions.fail; +import org.jhotdraw.color.ColorSliderModel; +import org.jhotdraw.color.DefaultColorSliderModel; +import org.jhotdraw.color.HSVColorSpace; + + +public class ColorSliderUIRegressionTest { + + @Test + void paintColorTrack_doesNotCallImageUpdate_andDoesNotCrash() throws Exception { + SwingUtilities.invokeAndWait(() -> { + // Custom slider that fails if Swing calls imageUpdate on it. + // After our fix (drawImage observer = null), this should never be called. + JSlider slider = new JSlider(JSlider.HORIZONTAL) { + @Override + public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) { + fail("imageUpdate() was called. The color track should be drawn with a null ImageObserver."); + return super.imageUpdate(img, infoflags, x, y, w, h); + } + }; + + // Install JHotDraw custom slider UI + slider.setUI((ColorSliderUI) ColorSliderUI.createUI(slider)); + + // Configure like in the real chooser panels (model + client properties) + ColorSliderModel model = new DefaultColorSliderModel(HSVColorSpace.getInstance()); + model.configureSlider(2, slider); + + // Give it a size so painting runs + slider.setSize(300, 50); + slider.doLayout(); + + // Paint into an offscreen image (headless-friendly) + BufferedImage img = new BufferedImage(300, 50, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = img.createGraphics(); + try { + slider.paint(g2); + } finally { + g2.dispose(); + } + }); + } +} diff --git a/jhotdraw-samples/jhotdraw-samples-mini/src/main/java/org/jhotdraw/samples/color/WheelsAndSlidersMain.java b/jhotdraw-samples/jhotdraw-samples-mini/src/main/java/org/jhotdraw/samples/color/WheelsAndSlidersMain.java index 4ec892321..8da0072df 100644 --- a/jhotdraw-samples/jhotdraw-samples-mini/src/main/java/org/jhotdraw/samples/color/WheelsAndSlidersMain.java +++ b/jhotdraw-samples/jhotdraw-samples-mini/src/main/java/org/jhotdraw/samples/color/WheelsAndSlidersMain.java @@ -132,10 +132,10 @@ private JPanel createColorWheelChooser(ColorSpace sys, int angularIndex, int rad w.setFlipY(flipY); w.setModel(m); JSlider s = new JSlider(JSlider.VERTICAL); + m.configureSlider(verticalIndex, s); s.setMajorTickSpacing(10); s.setPaintLabels(true); s.setPaintTicks(true); - m.configureSlider(verticalIndex, s); p.add(new JLabel("" + ColorUtil.getName(sys) + "
α:" + angularIndex + " r:" + radialIndex + " v:" + verticalIndex), BorderLayout.NORTH); p.add(w, BorderLayout.CENTER); p.add(s, BorderLayout.EAST); @@ -181,10 +181,10 @@ private JPanel createSliderChooser(ColorSpace sys, boolean vertical) { for (int i = 0; i < m.getComponentCount(); i++) { final int comp = i; JSlider s = new JSlider(JSlider.HORIZONTAL); + m.configureSlider(comp, s); s.setMajorTickSpacing(50); s.setPaintTicks(true); s.setOrientation(vertical ? JSlider.VERTICAL : JSlider.HORIZONTAL); - m.configureSlider(comp, s); if (vertical) { gbc.gridx = i; gbc.gridy = 0;