JDK-8133864 : Wrong display, when the document I18n properties is true.
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 8,9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2015-08-08
  • Updated: 2016-09-08
  • Resolved: 2016-03-24
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 9
9 b114Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :


ADDITIONAL OS VERSION INFORMATION :
Linux localhost 3.10.54-server-2.mga3 #1 SMP Sat Sep 13 14:48:19 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux


A DESCRIPTION OF THE PROBLEM :
It seems that parent views loose their children views when the document I18n property is true. Then the display of children views is wrong.

However, children have still their parents.

This bug breaks the compatibility between the 2 options : I18n true and I18N false.

When  I18n true GlyphPainter2 is used.
When  I18n false GlyphPainter1 is used.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
In the example, in the CodeBugDocument()

Put the document I18n property false :
putProperty("i18n", Boolean.FALSE);
the display is right (a text with a  table).

Put the document I18n property true :
putProperty("i18n", Boolean.TRUE);
the display is wrong (a text with a  table that looses its lines).


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package CodeBug;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.text.*;
//-------------------------------------------------------------------------------

//-------------------------------------------------------------------------------
public class CodeBug extends JFrame {

    JEditorPane edit = new JEditorPane();

    public CodeBug() {
        super("Code example for a TableView bug");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        edit.setEditorKit(new CodeBugEditorKit());
        initCodeBug();

        this.getContentPane().add(new JScrollPane(edit));
        this.setSize(300, 200);
        this.setLocationRelativeTo(null);

    }

    private void initCodeBug() {
        CodeBugDocument doc = (CodeBugDocument) edit.getDocument();
        try {
            doc.insertString(0, "TextB  TextE", null);
        } catch (BadLocationException ex) {
        }
        doc.insertTable(6, 4, 3);
        try {
            doc.insertString(7, "Cell11", null);
            doc.insertString(14, "Cell12", null);
            doc.insertString(21, "Cell13", null);
            doc.insertString(28, "Cell21", null);
            doc.insertString(35, "Cell22", null);
            doc.insertString(42, "Cell23", null);
            doc.insertString(49, "Cell31", null);
            doc.insertString(56, "Cell32", null);
            doc.insertString(63, "Cell33", null);
            doc.insertString(70, "Cell41", null);
            doc.insertString(77, "Cell42", null);
            doc.insertString(84, "Cell43", null);
        } catch (BadLocationException ex) {
        }
    }

    public static void main(String[] args) {
        CodeBug m = new CodeBug();
        m.setVisible(true);
    }
}

//-------------------------------------------------------------------------------
class CodeBugEditorKit extends StyledEditorKit {

    ViewFactory defaultFactory = new TableFactory();

    @Override
    public ViewFactory getViewFactory() {
        return defaultFactory;
    }

    @Override
    public Document createDefaultDocument() {
        return new CodeBugDocument();
    }
}
//-------------------------------------------------------------------------------

class TableFactory implements ViewFactory {

    @Override
    public View create(Element elem) {
        String kind = elem.getName();
        if (kind != null) {
            if (kind.equals(AbstractDocument.ContentElementName)) {
                return new LabelView(elem);
            } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
                return new ParagraphView(elem);
            } else if (kind.equals(AbstractDocument.SectionElementName)) {
                return new BoxView(elem, View.Y_AXIS);
            } else if (kind.equals(StyleConstants.ComponentElementName)) {
                return new ComponentView(elem);
            } else if (kind.equals(CodeBugDocument.ELEMENT_TABLE)) {
                return new tableView(elem);
            } else if (kind.equals(StyleConstants.IconElementName)) {
                return new IconView(elem);
            }
        }
        // default to text display
        return new LabelView(elem);

    }
}
//-------------------------------------------------------------------------------

//-------------------------------------------------------------------------------
class tableView extends TableView implements ViewFactory {

    public tableView(Element elem) {
        super(elem);
    }

    @Override
    public ViewFactory getViewFactory() {
        return this;
    }

    @Override
    public float getMinimumSpan(int axis) {
        return getPreferredSpan(axis);
    }

    @Override
    public float getMaximumSpan(int axis) {
        return getPreferredSpan(axis);
    }

    @Override
    public float getAlignment(int axis) {
        return 0.5f;
    }

    @Override
    public void paint(Graphics g, Shape allocation) {
        super.paint(g, allocation);
        Rectangle alloc = allocation.getBounds();
        int lastY = alloc.y + alloc.height - 1;
        g.drawLine(alloc.x, lastY, alloc.x + alloc.width, lastY);
    }

    @Override
    protected void paintChild(Graphics g, Rectangle alloc, int index) {
        super.paintChild(g, alloc, index);
        int lastX = alloc.x + alloc.width;
        g.drawLine(alloc.x, alloc.y, lastX, alloc.y);
    }

    @Override
    public View create(Element elem) {
        String kind = elem.getName();
        if (kind != null) {
            if (kind.equals(CodeBugDocument.ELEMENT_TR)) {
                return new trView(elem);
            } else if (kind.equals(CodeBugDocument.ELEMENT_TD)) {
                return new BoxView(elem, View.Y_AXIS);
            }
        }

        // default is to delegate to the normal factory
        View p = getParent();
        if (p != null) {
            ViewFactory f = p.getViewFactory();
            if (f != null) {
                return f.create(elem);
            }
        }

        return null;
    }

    public class trView extends TableRow {

        public trView(Element elem) {
            super(elem);
        }

        public float getMinimumSpan(int axis) {
            return getPreferredSpan(axis);
        }

        public float getMaximumSpan(int axis) {
            return getPreferredSpan(axis);
        }

        public float getAlignment(int axis) {
            return 0f;
        }

        @Override
        protected void paintChild(Graphics g, Rectangle alloc, int index) {
            super.paintChild(g, alloc, index);
            int lastY = alloc.y + alloc.height - 1;
            g.drawLine(alloc.x, alloc.y, alloc.x, lastY);
            int lastX = alloc.x + alloc.width;
            g.drawLine(lastX, alloc.y, lastX, lastY);
        }
    };
}

//-------------------------------------------------------------------------------
class CodeBugDocument extends DefaultStyledDocument {

    public static final String ELEMENT_TABLE = "table";
    public static final String ELEMENT_TR = "table cells row";
    public static final String ELEMENT_TD = "table data cell";

    public CodeBugDocument() {
        putProperty("i18n", Boolean.FALSE);
    }

    protected void insertTable(int offset, int rowCount, int colCount) {
        try {
            ArrayList Specs = new ArrayList();
            ElementSpec gapTag = new ElementSpec(new SimpleAttributeSet(), ElementSpec.ContentType, "\n".toCharArray(), 0, 1);
            Specs.add(gapTag);

            SimpleAttributeSet tableAttrs = new SimpleAttributeSet();
            tableAttrs.addAttribute(ElementNameAttribute, ELEMENT_TABLE);
            ElementSpec tableStart = new ElementSpec(tableAttrs, ElementSpec.StartTagType);
            Specs.add(tableStart); //start table tag


            fillRowSpecs(Specs, rowCount, colCount);

            ElementSpec[] spec = new ElementSpec[Specs.size()];
            Specs.toArray(spec);

            this.insert(offset, spec);
        } catch (BadLocationException ex) {
        }
    }

    protected void fillRowSpecs(ArrayList Specs, int rowCount, int colCount) {
        SimpleAttributeSet rowAttrs = new SimpleAttributeSet();
        rowAttrs.addAttribute(ElementNameAttribute, ELEMENT_TR);
        for (int i = 0; i < rowCount; i++) {
            ElementSpec rowStart = new ElementSpec(rowAttrs, ElementSpec.StartTagType);
            Specs.add(rowStart);

            fillCellSpecs(Specs, colCount);

            ElementSpec rowEnd = new ElementSpec(rowAttrs, ElementSpec.EndTagType);
            Specs.add(rowEnd);
        }

    }

    protected void fillCellSpecs(ArrayList Specs, int colCount) {
        for (int i = 0; i < colCount; i++) {
            SimpleAttributeSet cellAttrs = new SimpleAttributeSet();
            cellAttrs.addAttribute(ElementNameAttribute, ELEMENT_TD);

            ElementSpec cellStart = new ElementSpec(cellAttrs, ElementSpec.StartTagType);
            Specs.add(cellStart);

            ElementSpec parStart = new ElementSpec(new SimpleAttributeSet(), ElementSpec.StartTagType);
            Specs.add(parStart);
            ElementSpec parContent = new ElementSpec(new SimpleAttributeSet(), ElementSpec.ContentType, "\n".toCharArray(), 0, 1);
            Specs.add(parContent);
            ElementSpec parEnd = new ElementSpec(new SimpleAttributeSet(), ElementSpec.EndTagType);
            Specs.add(parEnd);
            ElementSpec cellEnd = new ElementSpec(cellAttrs, ElementSpec.EndTagType);
            Specs.add(cellEnd);
        }

    }
}
---------- END SOURCE ----------


Comments
- Checked this for JDK 7u85, 8u45, 8u51, 8u60 ea b26, 9 ea b76 and could reproduce the issue as reported by the submitter. putProperty("i18n", Boolean.TRUE); fails to render table correctly when compared to putProperty("i18n", Boolean.FALSE); - To verify, run the attached test case (CodeBug.java) in Windows 7 or Linux (64-bit). Note: Occasionally, when running with JDK 8u45 and below with putProperty("i18n", Boolean.TRUE);, it throws an exception, "java.lang.IllegalArgumentException: TextHitInfo is out of range". Moving this up for further evaluation.
18-08-2015