JDK-4532590 : JTextPane jTextPane.setHighlighter(null) doesn't disable highlighter.
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0,1.4.2_03
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: solaris_1,windows_2000
  • CPU: x86,sparc
  • Submitted: 2001-11-29
  • Updated: 2003-09-26
  • Resolved: 2003-09-26
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.
Other
5.0 tigerFixed
Related Reports
Duplicate :  
Relates :  
Description

Name: ddT132432			Date: 11/28/2001


d:\JBuilder\projects>java -version
java version "1.3.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-b24)
Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode)


Below is a swing applet that demonstrates problem -- on my machine.
I set the highlighter for the textpane to null expecting no highlighting
to occur when I click on text in the textpane.

But clicking on a word in the text pane partially highlights the word -- on my
machine. This error is also seen on JDk1.4beta3.

Your documentation says:

setHighlighter public void setHighlighter(Highlighter h) Sets the highlighter to
be used. By default this will be set by the UI that gets installed. This can be
changed to a custom highlighter if desired. The highlighter can be set to null
to disable it. A PropertyChange event ("highlighter") is fired when a new
highlighter is installed.


package typeintest;

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.StyleConstants;

public class TypeInTest extends JApplet
{
    boolean isStandalone = false;
    JPanel jPanel1 = new JPanel();
    BorderLayout borderLayout1 = new BorderLayout();
    JTextPane jTextPane1 = new JTextPane();
    BorderLayout borderLayout2 = new BorderLayout();
    /**Get a parameter value*/
    public String getParameter(String key, String def)
    {
        return isStandalone ? System.getProperty(key, def) :
            (getParameter(key) != null ? getParameter(key) : def);
    }

    /**Construct the applet*/
    public TypeInTest()
    {
    }
    /**Initialize the applet*/
    public void init()
    {
        try
        {
            jbInit();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
    /**Component initialization*/
    private void jbInit() throws Exception
    {
        this.setSize(new Dimension(400,300));
        this.getContentPane().setLayout(borderLayout1);
        jTextPane1.setEditable(false);
        jTextPane1.setCaretColor(Color.white);
        jTextPane1.setVerifyInputWhenFocusTarget(false);
        jTextPane1.setSelectedTextColor(Color.red);
        jTextPane1.setSelectionColor(Color.white);
        jTextPane1.setForeground(Color.white);
        jTextPane1.setText("jTextPane1");
        jTextPane1.addKeyListener(new TypeInTest_jTextPane1_keyAdapter(this));
        jTextPane1.addMouseListener(new TypeInTest_jTextPane1_mouseAdapter(this));
        jTextPane1.setHighlighter(null);
        jPanel1.setLayout(borderLayout2);
        jPanel1.setBorder(BorderFactory.createEtchedBorder());
        jPanel1.addKeyListener(new TypeInTest_jPanel1_keyAdapter(this));
        this.getContentPane().add(jPanel1, BorderLayout.CENTER);
        jPanel1.add(jTextPane1, BorderLayout.CENTER);
    }
    /**Start the applet*/
    private DefaultStyledDocument dsd = new DefaultStyledDocument();
	private SimpleAttributeSet attrs = new SimpleAttributeSet();
    private String textString = "Typein the missing word.";

    public void start()
    {
        try
        {

        StyleConstants.setFontFamily(attrs, "Serif");
		StyleConstants.setFontSize(attrs, 24);
        StyleConstants.setAlignment(attrs, StyleConstants.ALIGN_CENTER);
        StyleConstants.setBold(attrs, true);
        StyleConstants.setForeground(attrs, Color.blue);

        dsd.insertString(0, "\n" + textString + "\n\n", attrs);
        int length = dsd.getLength();
        dsd.insertString(length, textString, attrs);

        dsd.setParagraphAttributes(0, dsd.getLength(), attrs, false);
        jTextPane1.setDocument(dsd);
        Highlighter h = jTextPane1.getHighlighter();
        System.err.println("Highlighter = " + h.toString());
        }
        catch(Exception e)
        {
            System.err.println("Exception: " + e.toString());
        }


    }
    /**Stop the applet*/
    public void stop()
    {
    }
    /**Destroy the applet*/
    public void destroy()
    {
    }
    /**Get Applet information*/
    public String getAppletInfo()
    {
        return "Applet Information";
    }
    /**Get parameter info*/
    public String[][] getParameterInfo()
    {
        return null;
    }
    /**Main method*/
    public static void main(String[] args)
    {
        TypeInTest applet = new TypeInTest();
        applet.isStandalone = true;
        JFrame frame = new JFrame();
        //EXIT_ON_CLOSE == 3
        frame.setDefaultCloseOperation(3);
        frame.setTitle("Applet Frame");
        frame.getContentPane().add(applet, BorderLayout.CENTER);
        applet.init();
        applet.start();
        frame.setSize(400,320);
        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        frame.setLocation((d.width - frame.getSize().width) / 2, (d.height - frame.getSize().height) / 2);
        frame.setVisible(true);
    }

    //static initializer for setting look & feel
    static
    {
        try
        {
            //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
           
//UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
        }
        catch(Exception e)
        {
        }
    }

    void jTextPane1_keyReleased(KeyEvent e)
    {
        System.err.println("Key Released");
    }

    void jTextPane1_mouseReleased(MouseEvent e)
    {
        //e.consume();
        System.err.println("Mouse Released");
        //jTextPane1.getHighlighter().removeAllHighlights();
    }

    void jPanel1_keyReleased(KeyEvent e)
    {
        System.err.println("Key Released");
    }

    void jTextPane1_keyPressed(KeyEvent e)
    {
        System.err.println("Key Pressed");
    }

    void jTextPane1_keyTyped(KeyEvent e)
    {
        System.err.println("Key Typed");
    }

    void jTextPane1_mouseEntered(MouseEvent e)
    {

    }

    void jTextPane1_mouseClicked(MouseEvent e)
    {
        //e.consume();
        System.err.println("Mouse Clicked");
               // jTextPane1.getHighlighter().removeAllHighlights();
    }
}

class TypeInTest_jTextPane1_mouseAdapter extends java.awt.event.MouseAdapter
{
    TypeInTest adaptee;

    TypeInTest_jTextPane1_mouseAdapter(TypeInTest adaptee)
    {
        this.adaptee = adaptee;
    }
    public void mouseReleased(MouseEvent e)
    {
        adaptee.jTextPane1_mouseReleased(e);
    }
    public void mouseEntered(MouseEvent e)
    {
        adaptee.jTextPane1_mouseEntered(e);
    }
    public void mouseClicked(MouseEvent e)
    {
        adaptee.jTextPane1_mouseClicked(e);
    }
}

class TypeInTest_jPanel1_keyAdapter extends java.awt.event.KeyAdapter
{
    TypeInTest adaptee;

    TypeInTest_jPanel1_keyAdapter(TypeInTest adaptee)
    {
        this.adaptee = adaptee;
    }
    public void keyReleased(KeyEvent e)
    {
        adaptee.jPanel1_keyReleased(e);
    }
}

class TypeInTest_jTextPane1_keyAdapter extends java.awt.event.KeyAdapter
{
    TypeInTest adaptee;

    TypeInTest_jTextPane1_keyAdapter(TypeInTest adaptee)
    {
        this.adaptee = adaptee;
    }
    public void keyPressed(KeyEvent e)
    {
        adaptee.jTextPane1_keyPressed(e);
    }
    public void keyReleased(KeyEvent e)
    {
        adaptee.jTextPane1_keyReleased(e);
    }
    public void keyTyped(KeyEvent e)
    {
        adaptee.jTextPane1_keyTyped(e);
    }
}
(Review ID: 136407) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger FIXED IN: tiger INTEGRATED IN: tiger tiger-b22
24-08-2004

EVALUATION Name: pzR10082 Date: 08/01/2002 Highlighter is used to paint background of selected text only. Foreground color of selected text is controlled by selectedTextColor property. To make selection completely invisible, call textPane.setSelectedTextColor(null); ###@###.### 2002-08-01 ====================================================================== Name: pzR10082 Date: 07/21/2003 When highlighter is set to null, the background color of the selection is not altered (getSelectionColor() is ignored). However, foreground color is affected -- selected text is painted with getSelectedTextColor(). The problem is that when highlighter is null, selection is painted poorly, some of the letters may not be rendered in the selection foreground color. When selection is canceled, there's another problem: selected text is not repainted automatically. The reason is that DefaultCaret is not designed to work without a highlighter. When a highlighter is present, it calls addHighlight() and removeHightlight() on it, which effectively repaints areas that have become invalid. When there's no highlighter, DefaultCaret doesn't care to repaint those areas. For instance, when selection is canceled, the area it occupies is not repainted. ###@###.### ====================================================================== Name: pzR10082 Date: 07/23/2003 Short summary of the above: The problem is that areas occupied by selected text are not repainted properly when selection changes and highlighter is null. The reason is that when highlighter != null, it is called from DefaultCaret, and it repaints appropriate areas. When there's no highlighter, DefaultCaret does nothing to update selection display. Two ways to fix this: * Change DefaultCaret so that when highlighter == null, it handles repainting itself. We'll have to add cumbersome code like: if (highlighter != null) { highlighter.removeHighlight(); } else { Shape s = modelToView(selectionStart, selectionEnd, ...); textComponent.repaint(...); } to methods that can change selection visibility or selection itself, e.g. handleMoveDot(). * Disable selection rendering when highlighter is null. This requires two simple changes in PlainView and GlyphView. Also this is exactly what submitter of this bug has asked for. It would hardly cause incompatibilities, since by default we install a highlighter, and without one things never worked anyway. ###@###.### ======================================================================
24-08-2004

SUGGESTED FIX Name: pzR10082 Date: 09/16/2003 *** /net/crown/export1/zpm/webrev/src/share/classes/javax/swing/text/GlyphView.java- Tue Aug 12 15:59:04 2003 --- GlyphView.java Tue Aug 12 14:29:23 2003 *************** *** 371,386 **** JTextComponent tc = (JTextComponent) c; Color selFG = tc.getSelectedTextColor(); Caret caret = tc.getCaret(); ! if ((caret != null) && (! caret.isSelectionVisible())) { ! // selection currently not visible ! selFG = fg; ! } ! ! if(selFG != null && !selFG.equals(fg)) { int selStart = tc.getSelectionStart(); int selEnd = tc.getSelectionEnd(); ! if(selStart != selEnd) { // Something is selected, does p0 - p1 fall in that range? int pMin; int pMax; --- 371,388 ---- JTextComponent tc = (JTextComponent) c; Color selFG = tc.getSelectedTextColor(); Caret caret = tc.getCaret(); ! ! // paint selection only if it is currently visible, and ! if ((caret != null) && (caret.isSelectionVisible()) && ! // there's a highlighter (bug 4532590), and ! (tc.getHighlighter() != null) && ! // selected text color is different from regular foreground ! (selFG != null) && !selFG.equals(fg)) { ! int selStart = tc.getSelectionStart(); int selEnd = tc.getSelectionEnd(); ! if (selStart != selEnd) { // Something is selected, does p0 - p1 fall in that range? int pMin; int pMax; *** /net/crown/export1/zpm/webrev/src/share/classes/javax/swing/text/PlainView.java- Tue Aug 12 15:59:05 2003 --- PlainView.java Tue Aug 12 14:29:24 2003 *************** *** 91,98 **** p0-elem.getStartOffset(), p1-elem.getStartOffset()); } else { ! if (sel0 == sel1) { ! // no selection x = drawUnselectedText(g, x, y, p0, p1); } else if ((p0 >= sel0 && p0 <= sel1) && (p1 >= sel0 && p1 <= sel1)) { x = drawSelectedText(g, x, y, p0, p1); --- 91,98 ---- p0-elem.getStartOffset(), p1-elem.getStartOffset()); } else { ! if (sel0 == sel1 || selected == unselected) { ! // no selection, or it is invisible x = drawUnselectedText(g, x, y, p0, p1); } else if ((p0 >= sel0 && p0 <= sel1) && (p1 >= sel0 && p1 <= sel1)) { x = drawSelectedText(g, x, y, p0, p1); *************** *** 235,247 **** Rectangle alloc = (Rectangle) a; tabBase = alloc.x; JTextComponent host = (JTextComponent) getContainer(); g.setFont(host.getFont()); sel0 = host.getSelectionStart(); sel1 = host.getSelectionEnd(); unselected = (host.isEnabled()) ? host.getForeground() : host.getDisabledTextColor(); Caret c = host.getCaret(); ! selected = c.isSelectionVisible() ? host.getSelectedTextColor() : unselected; updateMetrics(); // If the lines are clipped then we don't expend the effort to --- 235,249 ---- Rectangle alloc = (Rectangle) a; tabBase = alloc.x; JTextComponent host = (JTextComponent) getContainer(); + Highlighter h = host.getHighlighter(); g.setFont(host.getFont()); sel0 = host.getSelectionStart(); sel1 = host.getSelectionEnd(); unselected = (host.isEnabled()) ? host.getForeground() : host.getDisabledTextColor(); Caret c = host.getCaret(); ! selected = c.isSelectionVisible() && h != null ? ! host.getSelectedTextColor() : unselected; updateMetrics(); // If the lines are clipped then we don't expend the effort to *************** *** 267,273 **** int lineCount = map.getElementCount(); int endLine = Math.min(lineCount, linesTotal - linesBelow); lineCount--; - Highlighter h = host.getHighlighter(); LayeredHighlighter dh = (h instanceof LayeredHighlighter) ? (LayeredHighlighter)h : null; for (int line = linesAbove; line < endLine; line++) { --- 269,274 ---- *** /net/crown/export1/zpm/webrev/src/share/classes/javax/swing/text/WrappedPlainView.java- Tue Aug 12 15:59:05 2003 --- WrappedPlainView.java Tue Aug 12 14:57:07 2003 *************** *** 119,126 **** p0-elem.getStartOffset(), p1-elem.getStartOffset()); } else { ! if (sel0 == sel1) { ! // no selection x = drawUnselectedText(g, x, y, p0, p1); } else if ((p0 >= sel0 && p0 <= sel1) && (p1 >= sel0 && p1 <= sel1)) { x = drawSelectedText(g, x, y, p0, p1); --- 119,126 ---- p0-elem.getStartOffset(), p1-elem.getStartOffset()); } else { ! if (sel0 == sel1 || selected == unselected) { ! // no selection, or it is invisible x = drawUnselectedText(g, x, y, p0, p1); } else if ((p0 >= sel0 && p0 <= sel1) && (p1 >= sel0 && p1 <= sel1)) { x = drawSelectedText(g, x, y, p0, p1); *************** *** 344,350 **** unselected = (host.isEnabled()) ? host.getForeground() : host.getDisabledTextColor(); Caret c = host.getCaret(); ! selected = c.isSelectionVisible() ? host.getSelectedTextColor() : unselected; g.setFont(host.getFont()); // superclass paints the children --- 344,351 ---- unselected = (host.isEnabled()) ? host.getForeground() : host.getDisabledTextColor(); Caret c = host.getCaret(); ! selected = c.isSelectionVisible() && host.getHighlighter() != null ? ! host.getSelectedTextColor() : unselected; g.setFont(host.getFont()); // superclass paints the children ###@###.### ======================================================================
24-08-2004