Hello,

I built the recent OpenJDK8u and OpenJDK9 sources (openjdk_versions.txt) with the patch shown in the output_diff.txt attachment.

I applied your patch for JDK-8133864 : Wrong display, when the document I18n properties is true. And I applied my patch for JDK-7169915 : Swing Table Layout bad repaint of the row.

All works fine in OpenJDK8u and the document is well displayed. The table appears as I expected with all its lines and columns (JDK-8133864 solved), size and borders included even if we write some text inside (JDK-7169915 solved). I can modify it as I want.

But with OpenJDK9, the display of the document is wrong. The table appears as I expected with all its lines and columns (JDK-8133864 solved), size and borders included (JDK-7169915 solved) but the entire document display is modified, the table is displayed on a new line. And the document became unuseable, I can't modify it as I want.

This morning, I ran the same test programme (CodeBug.java in attachment) with the Oracle JDK9 b114 (i.e. OpenJDK9 only with your patch for JDK-8133864) : The table appears as I expected with all its lines and columns (JDK-8133864 solved) but the size and borders are bad repainted when we write some text inside (JDK-7169915 solved). And the document became unuseable too, I can't modify it as I want.

My conclusion :
1- JDK-8133864 is solved with your PATCH.
2- JDK-7169915 could be solved with my PATCH.
3- There is regression between JDK8 and JDK9 may be in the Views arrangement.

Best regards.

----------------------------------------------------------------------------------------------------------------------

Hello,

Could you apply the modification I suggested 4 years ago about the Bug : JDK-7169915 : Swing Table Layout bad repaint of the row.

The test case I had sent in 2012 is the same I used in : JDK-8133864 Wrong display, when the document I18n properties is true.

A version of this test (called I18nLayoutTest.java) is now candidate as part of tests for JDK 9 (/test/javax/swing/text/TableView/)

Yours faithfully.


--
Abossolo Foh Guy
71 rue Guy de Maupassant
69500 Bron
diff --git a/src/share/classes/javax/swing/text/CompositeView.java b/src/share/classes/javax/swing/text/CompositeView.java
--- a/src/share/classes/javax/swing/text/CompositeView.java
+++ b/src/share/classes/javax/swing/text/CompositeView.java
@@ -24,7 +24,7 @@
  */
 package javax.swing.text;
 
-import java.util.Vector;
+import java.util.*;
 import java.awt.*;
 import javax.swing.event.*;
 import javax.swing.SwingConstants;
@@ -182,9 +182,14 @@
             views = ZERO;
         }
 
+        Set<View> set = new HashSet<>(Arrays.asList(views));
         // update parent reference on removed views
         for (int i = offset; i < offset + length; i++) {
-            if (children[i].getParent() == this) {
+            View child = children[i];
+            if (child.getParent() == this && !set.contains(child)) {
+        // update parent reference on removed views
+        //for (int i = offset; i < offset + length; i++) {
+        //    if (children[i].getParent() == this) {
                 // in FlowView.java view might be referenced
                 // from two super-views as a child. see logicalView
                 children[i].setParent(null);
diff --git a/src/share/classes/javax/swing/text/TableView.java b/src/share/classes/javax/swing/text/TableView.java
--- a/src/share/classes/javax/swing/text/TableView.java
+++ b/src/share/classes/javax/swing/text/TableView.java
@@ -78,6 +78,8 @@
         super(elem, View.Y_AXIS);
         rows = new Vector<TableRow>();
         gridValid = false;
+        // Bug 1  (JDK-7072926 : Swing Table Layout Update) & (JDK-7169915 : Swing Table Layout bad repaint of the row)
+        totalColumnRequirements = new SizeRequirements();
     }
 
     /**
@@ -345,6 +347,14 @@
         // continue normal layout
         super.layoutMinorAxis(targetSpan, axis, offsets, spans);
     }
+    
+    // Bug   (JDK-7072926 : Swing Table Layout Update) & (JDK-7169915 : Swing Table Layout bad repaint of the row)
+    @Override
+    public void preferenceChanged(View child, boolean width, boolean height) {
+        // Instead of clean columnRequirements in calculateColumnRequirements we could use invalidateGrid()
+        //invalidateGrid();
+        super.preferenceChanged(child, width, height);
+    }    
 
     /**
      * Calculate the requirements for the minor axis.  This is called by
@@ -377,6 +387,11 @@
         r.preferred = (int) pref;
         r.maximum = (int) max;
         r.alignment = 0;
+        
+        // Bug   (JDK-7072926 : Swing Table Layout Update) & (JDK-7169915 : Swing Table Layout bad repaint of the row)
+        totalColumnRequirements.minimum = r.minimum;
+        totalColumnRequirements.preferred = r.preferred;
+        totalColumnRequirements.maximum = r.maximum;
         return r;
     }
 
@@ -406,6 +421,15 @@
      * into consideration any constraining maximums.
      */
     void calculateColumnRequirements(int axis) {
+        // Bug   (JDK-7072926 : Swing Table Layout Update) & (JDK-7169915 : Swing Table Layout bad repaint of the row)
+        // (see preferenceChanged for another solution) 
+        // clean columnRequirements
+        for (SizeRequirements req : columnRequirements) {
+            req.minimum = 0;
+            req.preferred = 0;
+            req.maximum = Integer.MAX_VALUE;
+        }
+    
         // pass 1 - single column cells
         boolean hasMultiColumn = false;
         int nrows = getRowCount();
@@ -576,10 +600,13 @@
 
     int[] columnSpans;
     int[] columnOffsets;
+    // Bug   (JDK-7072926 : Swing Table Layout Update) & (JDK-7169915 : Swing Table Layout bad repaint of the row)
+    SizeRequirements totalColumnRequirements;
+    
     SizeRequirements[] columnRequirements;
     Vector<TableRow> rows;
     boolean gridValid;
-    static final private BitSet EMPTY = new BitSet();
+    private static final BitSet EMPTY = new BitSet();
 
     /**
      * View of a row in a row-centric table.
@@ -645,6 +672,56 @@
             super.replace(offset, length, views);
             invalidateGrid();
         }
+        
+        // Bug   (JDK-7072926 : Swing Table Layout Update) & (JDK-7169915 : Swing Table Layout bad repaint of the row)
+        // The major axis requirements for a row are dictated by the column
+        // requirements. These methods use the value calculated by
+        // TableView.
+        protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) {
+            SizeRequirements req = new SizeRequirements();
+            req.minimum = totalColumnRequirements.minimum;
+            req.maximum = totalColumnRequirements.maximum;
+            req.preferred = totalColumnRequirements.preferred;
+            req.alignment = 0f;
+            return req;
+        }
+        
+        // Bug   (JDK-7072926 : Swing Table Layout Update) & (JDK-7169915 : Swing Table Layout bad repaint of the row)
+        public float getMinimumSpan(int axis) {
+            float value;
+
+            if (axis == View.X_AXIS) {
+                value = totalColumnRequirements.minimum + getLeftInset() + getRightInset();
+            } else {
+                value = super.getMinimumSpan(axis);
+            }
+            return value;
+        }
+        
+        // Bug   (JDK-7072926 : Swing Table Layout Update) & (JDK-7169915 : Swing Table Layout bad repaint of the row)
+        public float getMaximumSpan(int axis) {
+            float value;
+
+            if (axis == View.X_AXIS) {
+                // We're flexible.
+                value = (float) Integer.MAX_VALUE;
+            } else {
+                value = super.getMaximumSpan(axis);
+            }
+            return value;
+        }
+        
+        // Bug   (JDK-7072926 : Swing Table Layout Update) & (JDK-7169915 : Swing Table Layout bad repaint of the row)
+        public float getPreferredSpan(int axis) {
+            float value;
+
+            if (axis == View.X_AXIS) {
+                value = totalColumnRequirements.preferred + getLeftInset() + getRightInset();
+            } else {
+                value = super.getPreferredSpan(axis);
+            }
+            return value;
+        }
 
         /**
          * Perform layout for the major axis of the box (i.e. the
openjdk version "1.8.0-internal"
OpenJDK Runtime Environment (build 
1.8.0-internal-scientificare2015_2016_04_18_16_37-b00)
OpenJDK 64-Bit Server VM (build 25.71-b00, mixed mode)


openjdk version "9-internal"
OpenJDK Runtime Environment (build 
9-internal+0-2016-04-18-052846.scientificware2015.9dev)
OpenJDK 64-Bit Server VM (build 
9-internal+0-2016-04-18-052846.scientificware2015.9dev, mixed mode)
 
//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");
        setUndecorated(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        edit.setEditorKit(new CodeBugEditorKit());
        initCodeBug();

        this.getContentPane().add(new JScrollPane(edit));
        this.setSize(300, 200);
        this.setLocationRelativeTo(null);
        
        edit.getDocument().putProperty("i18n", Boolean.TRUE);

    }

    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.TRUE);
    }

    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);
            gapTag.setDirection(ElementSpec.JoinPreviousDirection);
            
            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);
        }

    }
}

Reply via email to