JDK-7083457 : Incomplete specification for javax/swing/text/DefaultCaret.html#setVisible(boolean)
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 7
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2011-08-25
  • Updated: 2013-11-13
  • Resolved: 2013-09-25
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8 b110Fixed
Related Reports
Relates :  
Description
Platforms: reproduced - Windows, Solaris
JDK: 6, 7

Assertions in the specification of the following method are not satisfied
http://download.oracle.com/javase/7/docs/api/javax/swing/text/DefaultCaret.html#setVisible(boolean)

Specification says:
 Setting it to false turns it completely off. 
 To determine whether the blinking is active, you should call isActive. 
 In effect, isActive is an appropriate corresponding "getter" method for this one.

Here's a list showing the potential return values of both isActive and isVisible after calling this method:
 setVisible(true):
    isActive(): true
    isVisible(): true or false depending on whether or not the caret is blinked on or off
 setVisible(false):
    isActive(): false
    isVisible(): false 


The latter statement is not satisfied always. The code sample below shows that setVisible(false) behaves more like setVisible(true)


import javax.swing.*;
import javax.swing.text.DefaultCaret;
import javax.swing.text.JTextComponent;
import java.lang.reflect.InvocationTargetException;

public class CaretInvisible {

    public static void main(String[] args) throws InvocationTargetException, InterruptedException {
        final DefaultCaret caret = new DefaultCaret();
        final JFrame[] jFrame = new JFrame[1];

        SwingUtilities.invokeAndWait(new Runnable() {
            @Override
            public void run() {

                JTextComponent comp = new javax.swing.JTextArea(10, 10);
                jFrame[0] = new JFrame();
                jFrame[0].getContentPane().add(comp);

                jFrame[0].pack();
                jFrame[0].setVisible(true);
                jFrame[0].toFront();


                comp.setCaret(caret);

                caret.setBlinkRate(300);
                caret.setVisible(false);
            }
        });

        for (int i=0; i<20; i++) {
            Thread.sleep(100);
            System.out.println("caret.isVisible() = " + caret.isVisible());
            System.out.println("caret.isActive() = " + caret.isActive());
        }

        SwingUtilities.invokeAndWait(new Runnable() {
            @Override
            public void run() {
                jFrame[0].dispose();
            }
        });

    }
}

The output will be:

caret.isVisible() = false
caret.isActive() = false
caret.isVisible() = true
caret.isActive() = true
caret.isVisible() = true
caret.isActive() = true
caret.isVisible() = true
caret.isActive() = true
caret.isVisible() = false
caret.isActive() = true
caret.isVisible() = false
caret.isActive() = true
caret.isVisible() = false
caret.isActive() = true
caret.isVisible() = true
caret.isActive() = true
caret.isVisible() = true
caret.isActive() = true
caret.isVisible() = true
caret.isActive() = true
caret.isVisible() = false
caret.isActive() = true
caret.isVisible() = false
caret.isActive() = true
caret.isVisible() = false
caret.isActive() = true
caret.isVisible() = true
caret.isActive() = true
caret.isVisible() = true
caret.isActive() = true
caret.isVisible() = true
caret.isActive() = true
caret.isVisible() = false
caret.isActive() = true
caret.isVisible() = false
caret.isActive() = true
caret.isVisible() = false
caret.isActive() = true
caret.isVisible() = true
caret.isActive() = true


It could be seen that isActive() always return true, while isVisible() is dependant of the caret blinking state.
Looks like the specification misses some important assertions.
Specification says:
 In effect, isActive is an appropriate corresponding "getter" method for this one [setVisible()].

This is not satisfied as well, the following code will print out:

        final DefaultCaret caret = new DefaultCaret();
        caret.setVisible(true);
        System.err.println("caret.isActive() = " + caret.isActive());

caret.isActive() = false

Comments
The DefaultCaret.setVisible(boolean e) should always update the getActive() state. See the suggested fix: http://cr.openjdk.java.net/~alexsch/7083457/webrev.01/
24-09-2013

since we have failed tck test it should be addressed in 8
05-09-2013

we will not defer it in the bulk request, but may be individually later
05-09-2013

It is not a high priority issue, because this feature is used rarely and the fix is not safe. This is expected behavior: - when the focus is lost the caret is invisible - when the focus is gained the caret is visible again
05-09-2013

It is not a specification issue. The reason is that the text component gains focus after the Runnable is finished and the setVisible(true) is called on this event. Use the following patch to fix the test: caret.setBlinkRate(300); + } + }); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { caret.setVisible(false);
05-09-2013