8188081: Text selection does not clear after focus is lost
authorssadetsky
Tue, 24 Oct 2017 08:37:11 -0700
changeset 47503 2cd2d387fcd2
parent 47502 d64ae7c1d70f
child 47504 58ce36f43f1a
8188081: Text selection does not clear after focus is lost Reviewed-by: serb, psadhukhan
src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java
test/jdk/javax/swing/JTextPane/bug8025082.java
test/jdk/javax/swing/text/DefaultCaret/HidingSelection/HidingSelectionTest.java
--- a/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java	Mon Oct 23 13:06:04 2017 -0700
+++ b/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java	Tue Oct 24 08:37:11 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -352,6 +352,7 @@
                 setVisible(true);
             }
             setSelectionVisible(true);
+            updateSystemSelection();
         }
     }
 
@@ -365,7 +366,9 @@
      */
     public void focusLost(FocusEvent e) {
         setVisible(false);
-        setSelectionVisible(ownsSelection || e.isTemporary());
+        setSelectionVisible((e.getCause() == FocusEvent.Cause.ACTIVATION ||
+                e.getOppositeComponent() instanceof JRootPane) &&
+                (ownsSelection || e.isTemporary()));
     }
 
 
@@ -866,7 +869,6 @@
                     Highlighter.HighlightPainter p = getSelectionPainter();
                     try {
                         selectionTag = h.addHighlight(p0, p1, p);
-                        updateOwnsSelection();
                     } catch (BadLocationException bl) {
                         selectionTag = null;
                     }
@@ -877,7 +879,6 @@
                     Highlighter h = component.getHighlighter();
                     h.removeHighlight(selectionTag);
                     selectionTag = null;
-                    updateOwnsSelection();
                 }
             }
         }
@@ -1119,7 +1120,6 @@
                     if (selectionTag != null) {
                         h.removeHighlight(selectionTag);
                         selectionTag = null;
-                        updateOwnsSelection();
                     }
                 // otherwise, change or add the highlight
                 } else {
@@ -1130,7 +1130,6 @@
                             Highlighter.HighlightPainter p = getSelectionPainter();
                             selectionTag = h.addHighlight(p0, p1, p);
                         }
-                        updateOwnsSelection();
                     } catch (BadLocationException e) {
                         throw new StateInvariantError("Bad caret position");
                     }
@@ -1181,7 +1180,6 @@
         if (this.dot != dot || this.dotBias != dotBias ||
             selectionTag != null || forceCaretPositionChange) {
             changeCaretPosition(dot, dotBias);
-            updateOwnsSelection();
         }
         this.markBias = this.dotBias;
         this.markLTR = dotLTR;
@@ -1189,7 +1187,6 @@
         if ((h != null) && (selectionTag != null)) {
             h.removeHighlight(selectionTag);
             selectionTag = null;
-            updateOwnsSelection();
         }
     }
 
@@ -1940,13 +1937,6 @@
         }
     }
 
-    /**
-     * Updates ownsSelection based on text selection in the caret.
-     */
-    private void updateOwnsSelection() {
-        ownsSelection = (selectionTag != null)
-                && SwingUtilities2.canAccessSystemClipboard();
-    }
 
     private class DefaultFilterBypass extends NavigationFilter.FilterBypass {
         public Caret getCaret() {
--- a/test/jdk/javax/swing/JTextPane/bug8025082.java	Mon Oct 23 13:06:04 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @key headful
- * @bug 8025082
- * @summary The behaviour of the highlight will be lost after clicking the set
- * button.
- * @run main bug8025082
- */
-import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.InputEvent;
-import javax.swing.*;
-
-public class bug8025082 {
-
-    private static JButton button;
-    private static JFrame frame;
-
-    public static void main(String[] args) throws Exception {
-        Robot robo = new Robot();
-        robo.delay(500);
-
-        SwingUtilities.invokeAndWait(new Runnable() {
-            public void run() {
-                createUI();
-            }
-        });
-
-        robo.waitForIdle();
-        Point point = getButtonLocationOnScreen();
-        robo.mouseMove(point.x, point.y);
-        robo.mousePress(InputEvent.BUTTON1_MASK);
-        robo.mouseRelease(InputEvent.BUTTON1_MASK);
-        robo.waitForIdle();
-
-        SwingUtilities.invokeAndWait(new Runnable() {
-            public void run() {
-                frame.dispose();
-            }
-        });
-    }
-
-    private static void createUI() {
-        frame = new JFrame();
-        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-        frame.setSize(500, 500);
-        JTextPane textpane = new JTextPane();
-        textpane.setText("Select Me");
-        textpane.selectAll();
-
-        JPanel panel = new JPanel(new BorderLayout());
-        panel.add(textpane, BorderLayout.CENTER);
-        button = new JButton("Press Me");
-        panel.add(button, BorderLayout.SOUTH);
-
-        button.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                if (!textpane.getCaret().isSelectionVisible()) {
-                    throw new RuntimeException("Highlight removed after "
-                            + "button click");
-                }
-            }
-        });
-
-        frame.getContentPane().add(panel);
-        frame.setLocationRelativeTo(null);
-        frame.setVisible(true);
-    }
-
-    private static Point getButtonLocationOnScreen() throws Exception {
-        final Point[] result = new Point[1];
-
-        SwingUtilities.invokeAndWait(new Runnable() {
-            @Override
-            public void run() {
-                Point point = button.getLocationOnScreen();
-                point.x += button.getWidth() / 2;
-                point.y += button.getHeight() / 2;
-                result[0] = point;
-            }
-        });
-        return result[0];
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/swing/text/DefaultCaret/HidingSelection/HidingSelectionTest.java	Tue Oct 24 08:37:11 2017 -0700
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.InputEvent;
+import java.awt.image.BufferedImage;
+
+/**
+ * @test
+ * @bug 8188081
+ * @summary  Text selection does not clear after focus is lost
+ * @run main HidingSelectionTest
+ */
+
+public class HidingSelectionTest {
+
+    private static JTextField field1;
+    private static JTextField field2;
+    private static JFrame frame;
+    private static Rectangle bounds;
+    private static JMenu menu;
+    private static JTextField anotherWindow;
+    private static Point menuLoc;
+    private static JFrame frame2;
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(() -> {
+            frame = new JFrame();
+            field1 = new JTextField("field1                       ");
+            field2 = new JTextField("field2                       ");
+            field1.setEditable(false);
+            field2.setEditable(false);
+            frame.getContentPane().setLayout(new FlowLayout());
+            frame.getContentPane().add(field1);
+            frame.getContentPane().add(field2);
+            JMenuBar menuBar = new JMenuBar();
+            menu = new JMenu("menu");
+            menu.add(new JMenuItem("item"));
+            menuBar.add(menu);
+            frame.setJMenuBar(menuBar);
+            frame.pack();
+            frame.setVisible(true);
+        });
+
+        Robot robot = new Robot();
+        robot.waitForIdle();
+        robot.delay(200);
+        SwingUtilities.invokeAndWait(() -> {
+            bounds = field2.getBounds();
+            bounds.setLocation(field2.getLocationOnScreen());
+        });
+        BufferedImage nosel = robot.createScreenCapture(bounds);
+
+        SwingUtilities.invokeAndWait(field2::requestFocus);
+        SwingUtilities.invokeAndWait(field2::selectAll);
+        robot.waitForIdle();
+        robot.delay(200);
+        BufferedImage sel = robot.createScreenCapture(bounds);
+
+        SwingUtilities.invokeAndWait(() -> {
+            menuLoc = menu.getLocationOnScreen();
+            menuLoc.translate(10, 10);
+        });
+        robot.mouseMove(menuLoc.x, menuLoc.y);
+        robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+        robot.delay(50);
+        robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+        robot.waitForIdle();
+        robot.delay(200);
+        if (!biEqual(robot.createScreenCapture(bounds), sel)) {
+            throw new RuntimeException("Test fails: menu hides selection");
+        }
+
+        SwingUtilities.invokeAndWait(
+                      MenuSelectionManager.defaultManager()::clearSelectedPath);
+        SwingUtilities.invokeAndWait(field1::requestFocus);
+        robot.waitForIdle();
+        robot.delay(200);
+        if (!biEqual(robot.createScreenCapture(bounds), nosel)) {
+            throw new RuntimeException(
+                    "Test fails: focus lost doesn't hide selection");
+        }
+
+        SwingUtilities.invokeAndWait(field2::requestFocus);
+        robot.waitForIdle();
+        SwingUtilities.invokeAndWait(() ->{
+            frame2 = new JFrame();
+            Point loc = frame.getLocationOnScreen();
+            loc.translate(0, frame.getHeight());
+            frame2.setLocation(loc);
+            anotherWindow = new JTextField("textField3");
+            frame2.add(anotherWindow);
+            frame2.pack();
+            frame2.setVisible(true);
+        });
+        robot.waitForIdle();
+        SwingUtilities.invokeAndWait(anotherWindow::requestFocus);
+        robot.waitForIdle();
+        robot.delay(200);
+        if (biEqual(robot.createScreenCapture(bounds), nosel)) {
+            throw new RuntimeException(
+                    "Test fails: switch window hides selection");
+        }
+
+        SwingUtilities.invokeAndWait(anotherWindow::selectAll);
+        robot.waitForIdle();
+        robot.delay(200);
+        if (biEqual(robot.createScreenCapture(bounds), sel)) {
+            throw new RuntimeException(
+                "Test fails: selection ownership is lost selection is shown");
+        }
+
+        SwingUtilities.invokeLater(frame2::dispose);
+        SwingUtilities.invokeLater(frame::dispose);
+    }
+
+    static boolean biEqual(BufferedImage i1, BufferedImage i2) {
+        if (i1.getWidth() == i2.getWidth() &&
+                                         i1.getHeight() == i2.getHeight()) {
+            for (int x = 0; x < i1.getWidth(); x++) {
+                for (int y = 0; y < i1.getHeight(); y++) {
+                    if (i1.getRGB(x, y) != i2.getRGB(x, y)) {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+}