6490753: JComboBox doesn't look as native combobox in different states of component
authoralexsch
Mon, 06 Mar 2017 17:03:26 +0300
changeset 44153 43fac9627342
parent 44152 af74e15ef830
child 44154 e60bcc49ba1b
6490753: JComboBox doesn't look as native combobox in different states of component Reviewed-by: serb, alexsch Contributed-by: Martin Mraz <mraz.martin.dev@gmail.com>
jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/AnimationController.java
jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/TMSchema.java
jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java
jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java
jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/XPStyle.java
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/AnimationController.java	Mon Mar 06 08:06:54 2017 +0300
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/AnimationController.java	Mon Mar 06 17:03:26 2017 +0300
@@ -36,7 +36,6 @@
 import javax.swing.*;
 
 
-
 import com.sun.java.swing.plaf.windows.TMSchema.State;
 import static com.sun.java.swing.plaf.windows.TMSchema.State.*;
 import com.sun.java.swing.plaf.windows.TMSchema.Part;
@@ -383,18 +382,25 @@
             updateProgress();
             if (! isDone()) {
                 Graphics2D g = (Graphics2D) _g.create();
-                skin.paintSkinRaw(g, dx, dy, dw, dh, startState);
-                float alpha;
-                if (isForward) {
-                    alpha = progress;
+                if (skin.haveToSwitchStates()) {
+                    skin.paintSkinRaw(g, dx, dy, dw, dh, state);
+                    g.setComposite(AlphaComposite.SrcOver.derive(1 - progress));
+                    skin.paintSkinRaw(g, dx, dy, dw, dh, startState);
                 } else {
-                    alpha = 1 - progress;
+                    skin.paintSkinRaw(g, dx, dy, dw, dh, startState);
+                    float alpha;
+                    if (isForward) {
+                        alpha = progress;
+                    } else {
+                        alpha = 1 - progress;
+                    }
+                    g.setComposite(AlphaComposite.SrcOver.derive(alpha));
+                    skin.paintSkinRaw(g, dx, dy, dw, dh, state);
                 }
-                g.setComposite(AlphaComposite.SrcOver.derive(alpha));
-                skin.paintSkinRaw(g, dx, dy, dw, dh, state);
                 g.dispose();
             } else {
                 skin.paintSkinRaw(_g, dx, dy, dw, dh, state);
+                skin.switchStates(false);
             }
         }
         boolean isDone() {
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/TMSchema.java	Mon Mar 06 08:06:54 2017 +0300
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/TMSchema.java	Mon Mar 06 17:03:26 2017 +0300
@@ -121,6 +121,12 @@
 
         LBP_LISTBOX(Control.LISTBOX, 0),
 
+        LBCP_BORDER_HSCROLL  (Control.LISTBOX, 1),
+        LBCP_BORDER_HVSCROLL (Control.LISTBOX, 2),
+        LBCP_BORDER_NOSCROLL (Control.LISTBOX, 3),
+        LBCP_BORDER_VSCROLL  (Control.LISTBOX, 4),
+        LBCP_ITEM            (Control.LISTBOX, 5),
+
         LVP_LISTVIEW(Control.LISTVIEW, 0),
 
         PP_PROGRESS (Control.PROGRESS, 0),
@@ -343,6 +349,12 @@
             stateMap.put(Part.HP_HEADERSORTARROW,
                          new State[] {SORTEDDOWN, SORTEDUP});
 
+            State[] listBoxStates = new State[] { NORMAL, PRESSED, HOT, DISABLED};
+            stateMap.put(Part.LBCP_BORDER_HSCROLL, listBoxStates);
+            stateMap.put(Part.LBCP_BORDER_HVSCROLL, listBoxStates);
+            stateMap.put(Part.LBCP_BORDER_NOSCROLL, listBoxStates);
+            stateMap.put(Part.LBCP_BORDER_VSCROLL, listBoxStates);
+
             State[] scrollBarStates = new State[] { NORMAL, HOT, PRESSED, DISABLED, HOVER };
             stateMap.put(Part.SBP_SCROLLBAR,    scrollBarStates);
             stateMap.put(Part.SBP_THUMBBTNVERT, scrollBarStates);
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java	Mon Mar 06 08:06:54 2017 +0300
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java	Mon Mar 06 17:03:26 2017 +0300
@@ -41,6 +41,7 @@
 import sun.swing.DefaultLookup;
 import sun.swing.StringUIClientPropertyKey;
 
+import com.sun.java.swing.plaf.windows.WindowsBorders.DashedBorder;
 
 /**
  * Windows combo box.
@@ -97,6 +98,9 @@
                 } else if (source instanceof XPComboBoxButton) {
                     rv = ((XPComboBoxButton) source)
                         .getWindowsComboBoxUI().comboBox;
+                } else if (source instanceof JTextField &&
+                        ((JTextField) source).getParent() instanceof JComboBox) {
+                    rv = (JComboBox) ((JTextField) source).getParent();
                 }
                 return rv;
             }
@@ -149,6 +153,8 @@
             //is initialized after installListeners is invoked
             comboBox.addMouseListener(rolloverListener);
             arrowButton.addMouseListener(rolloverListener);
+            // set empty border as default to see vista animated border
+            comboBox.setBorder(new EmptyBorder(0,0,0,0));
         }
     }
 
@@ -224,6 +230,9 @@
             state = State.DISABLED;
         } else if (isPopupVisible(comboBox)) {
             state = State.PRESSED;
+        } else if (comboBox.isEditable()
+                && comboBox.getEditor().getEditorComponent().isFocusOwner()) {
+            state = State.PRESSED;
         } else if (isRollover) {
             state = State.HOT;
         }
@@ -242,7 +251,7 @@
             skin = xp.getSkin(c, Part.CP_READONLY);
         }
         if (skin == null) {
-            skin = xp.getSkin(c, Part.CP_COMBOBOX);
+            skin = xp.getSkin(c, Part.CP_BORDER);
         }
         skin.paintSkin(g, 0, 0, c.getWidth(), c.getHeight(), state);
     }
@@ -368,7 +377,7 @@
     }
 
     protected ComboPopup createPopup() {
-        return super.createPopup();
+        return new WinComboPopUp(comboBox);
     }
 
     /**
@@ -414,8 +423,10 @@
 
     @SuppressWarnings("serial") // Superclass is not serializable across versions
     private class XPComboBoxButton extends XPStyle.GlyphButton {
+        private State prevState = null;
+
         public XPComboBoxButton(XPStyle xp) {
-            super(null,
+            super(comboBox,
                   (! xp.isSkinDefined(comboBox, Part.CP_DROPDOWNBUTTONRIGHT))
                    ? Part.CP_DROPDOWNBUTTON
                    : (comboBox.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT)
@@ -428,18 +439,33 @@
         @Override
         protected State getState() {
             State rv;
+
+            getModel().setPressed(comboBox.isPopupVisible());
+
             rv = super.getState();
             XPStyle xp = XPStyle.getXP();
             if (rv != State.DISABLED
-                && comboBox != null && ! comboBox.isEditable()
-                && xp != null && xp.isSkinDefined(comboBox,
-                                                  Part.CP_DROPDOWNBUTTONRIGHT)) {
+                    && comboBox != null && ! comboBox.isEditable()
+                    && xp != null && xp.isSkinDefined(comboBox,
+                            Part.CP_DROPDOWNBUTTONRIGHT)) {
                 /*
                  * for non editable ComboBoxes Vista seems to have the
                  * same glyph for all non DISABLED states
                  */
                 rv = State.NORMAL;
             }
+            if (rv == State.NORMAL && (prevState == State.HOT || prevState == State.PRESSED)) {
+                /*
+                 * State NORMAL of combobox button cannot overpaint states HOT or PRESSED
+                 * Therefore HOT state must be painted from alpha 1 to 0 and not as usual that
+                 * NORMAL state is painted from alpha 0 to alpha 1.
+                 */
+                skin.switchStates(true);
+            }
+            if (rv != prevState) {
+                prevState = rv;
+            }
+
             return rv;
         }
 
@@ -484,6 +510,39 @@
         }
     }
 
+    @SuppressWarnings("serial") // Same-version serialization only
+    protected class WinComboPopUp extends BasicComboPopup {
+        private Skin listBoxBorder = null;
+        private XPStyle xp;
+
+        public WinComboPopUp(JComboBox<Object> combo) {
+            super(combo);
+            xp = XPStyle.getXP();
+            if (xp != null && xp.isSkinDefined(combo, Part.LBCP_BORDER_NOSCROLL)) {
+                this.listBoxBorder = new Skin(combo, Part.LBCP_BORDER_NOSCROLL);
+                this.setBorder(new EmptyBorder(1,1,1,1));
+            }
+        }
+
+        protected KeyListener createKeyListener() {
+            return new InvocationKeyHandler();
+        }
+
+        protected class InvocationKeyHandler extends BasicComboPopup.InvocationKeyHandler {
+            protected InvocationKeyHandler() {
+                WinComboPopUp.this.super();
+            }
+        }
+
+        protected void paintComponent(Graphics g) {
+            super.paintComponent(g);
+            if (this.listBoxBorder != null) {
+                this.listBoxBorder.paintSkinRaw(g, this.getX(), this.getY(),
+                        this.getWidth(), this.getHeight(), State.HOT);
+            }
+        }
+    }
+
 
     /**
      * Subclassed to highlight selected item in an editable combo box.
@@ -498,6 +557,7 @@
         protected JTextField createEditorComponent() {
             JTextField editor = super.createEditorComponent();
             Border border = (Border)UIManager.get("ComboBox.editorBorder");
+
             if (border != null) {
                 editor.setBorder(border);
             }
@@ -524,6 +584,31 @@
         private static final Object BORDER_KEY
             = new StringUIClientPropertyKey("BORDER_KEY");
         private static final Border NULL_BORDER = new EmptyBorder(0, 0, 0, 0);
+
+        // Create own version of DashedBorder with more space on left side
+        private class WindowsComboBoxDashedBorder extends DashedBorder {
+
+            public WindowsComboBoxDashedBorder(Color color, int thickness) {
+                super(color, thickness);
+            }
+
+            public WindowsComboBoxDashedBorder(Color color) {
+                super(color);
+            }
+
+            @Override
+            public Insets getBorderInsets(Component c, Insets i) {
+                return new Insets(0,2,0,0);
+            }
+        }
+
+        public WindowsComboBoxRenderer() {
+            super();
+
+            // correct space on the left side of text items in the combo popup list
+            Insets i = getBorder().getBorderInsets(this);
+            setBorder(new EmptyBorder(0, 2, 0, i.right));
+        }
         /**
          * {@inheritDoc}
          */
@@ -542,7 +627,7 @@
                 if (index == -1 && isSelected) {
                     Border border = component.getBorder();
                     Border dashedBorder =
-                        new WindowsBorders.DashedBorder(list.getForeground());
+                        new WindowsComboBoxDashedBorder(list.getForeground());
                     component.setBorder(dashedBorder);
                     //store current border in client property if needed
                     if (component.getClientProperty(BORDER_KEY) == null) {
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java	Mon Mar 06 08:06:54 2017 +0300
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java	Mon Mar 06 17:03:26 2017 +0300
@@ -672,7 +672,7 @@
             "ComboBox.buttonHighlight", ControlHighlightColor,
             "ComboBox.selectionBackground", SelectionBackgroundColor,
             "ComboBox.selectionForeground", SelectionTextColor,
-            "ComboBox.editorBorder", new XPValue(new EmptyBorder(1,2,1,1),
+            "ComboBox.editorBorder", new XPValue(new EmptyBorder(1,4,1,1),
                                                  new EmptyBorder(1,4,1,4)),
             "ComboBox.disabledBackground",
                         new XPColorValue(Part.CP_COMBOBOX, State.DISABLED,
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/XPStyle.java	Mon Mar 06 08:06:54 2017 +0300
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/XPStyle.java	Mon Mar 06 17:03:26 2017 +0300
@@ -479,6 +479,7 @@
 
         private final String string;
         private Dimension size = null;
+        private boolean switchStates = false;
 
         Skin(Component component, Part part) {
             this(component, part, null);
@@ -513,6 +514,14 @@
             return (insets != null) ? insets : new Insets(0, 0, 0, 0);
         }
 
+        boolean haveToSwitchStates() {
+            return switchStates;
+        }
+
+        void switchStates(boolean b) {
+            switchStates = b;
+        }
+
         private int getWidth(State state) {
             if (size == null) {
                 size = getPartSize(part, state);
@@ -689,7 +698,7 @@
 
     @SuppressWarnings("serial") // Superclass is not serializable across versions
     static class GlyphButton extends JButton {
-        private Skin skin;
+        protected Skin skin;
 
         public GlyphButton(Component parent, Part part) {
             XPStyle xp = getXP();