2016-03-24 20:03:38 +03:00
/ *
2017-03-06 22:52:45 +03:00
* Copyright ( c ) 2007 , 2017 , Oracle and / or its affiliates . All rights reserved .
2016-03-24 20:03:38 +03:00
* 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
2016-07-07 16:21:45 +02:00
* @key headful
2017-03-06 22:52:45 +03:00
* @bug 8133864 8158209
2016-03-24 20:03:38 +03:00
* @summary Wrong display , when the document I18n properties is true .
* /
import javax.swing.* ;
import javax.swing.text.* ;
import java.awt.* ;
2017-03-06 22:52:45 +03:00
import java.awt.event.KeyEvent ;
2016-03-24 20:03:38 +03:00
import java.util.ArrayList ;
2017-03-06 22:52:45 +03:00
import javax.swing.event.CaretEvent ;
import javax.swing.event.CaretListener ;
public class TableViewLayoutTest extends JFrame {
private static double yCaret ;
private static double xCaret ;
// Number of iteration to verify the stability of the test with different robot delays :
// Work well with robot.delay(50) in hitKey method.
// But if the robot delay is too low, the test is not stable.
// Put this to 100, and reduce robot delay sometimes answers may be different.
private static int tn = 2 ;
// The four caret positions to test.
private static double yCarFLTab ;
private static double yCarLLTab ;
private static double xCarBTab ;
private static double xCarETab ;
// The caret coordonate differences along axis after the insertion and the removing cycle.
// 0 if the table layout is right.
private static double dyCarFLTab ;
private static double dyCarLLTab ;
private static double dxCarBTab ;
private static double dxCarETab ;
private static JEditorPane edit = new JEditorPane ( ) ;
private static TableViewLayoutTest frame ;
2016-03-24 20:03:38 +03:00
2017-03-06 22:52:45 +03:00
private static String Prop = " \ n " ;
private static boolean isTabWrong = Boolean . FALSE ;
2016-03-24 20:03:38 +03:00
2017-03-06 22:52:45 +03:00
private static Boolean isI18n = false ;
public TableViewLayoutTest ( ) {
2016-03-24 20:03:38 +03:00
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 . pack ( ) ;
this . setLocationRelativeTo ( null ) ;
2017-03-06 22:52:45 +03:00
edit . addCaretListener ( new CaretListener ( ) {
public void caretUpdate ( CaretEvent e ) {
JTextComponent textComp = ( JTextComponent ) e . getSource ( ) ;
try {
Rectangle rect = textComp . getUI ( ) . modelToView ( textComp , e . getDot ( ) ) ;
yCaret = rect . getY ( ) ;
xCaret = rect . getX ( ) ;
} catch ( BadLocationException ex ) {
throw new RuntimeException ( " Failed to get pixel position of caret " , ex ) ;
}
}
} ) ;
2016-03-24 20:03:38 +03:00
}
private void initCodeBug ( ) {
CodeBugDocument doc = ( CodeBugDocument ) edit . getDocument ( ) ;
try {
2017-03-06 22:52:45 +03:00
doc . insertString ( 0 , " TextB TextE " , null ) ;
2016-03-24 20:03:38 +03:00
} 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 ) throws Exception {
2017-03-06 22:52:45 +03:00
for ( int i = 0 ; i < tn ; i + + ) {
Robot rob = new Robot ( ) ;
SwingUtilities . invokeAndWait ( new Runnable ( ) {
@Override
public void run ( ) {
frame = new TableViewLayoutTest ( ) ;
frame . setVisible ( true ) ;
}
} ) ;
SwingUtilities . invokeAndWait ( new Runnable ( ) {
@Override
public void run ( ) {
//Enable or disable i18n.
isI18n = ! isI18n ;
edit . getDocument ( ) . putProperty ( " i18n " , isI18n ) ;
//Made a change to update table layout.
//Without any change the table i18n property change is not take in account.
edit . select ( 11 , 12 ) ;
edit . replaceSelection ( " 1 " ) ;
//Catch the four caret positions to test before insertions.
edit . setCaretPosition ( 6 ) ;
xCarBTab = xCaret ;
edit . setCaretPosition ( 91 ) ;
xCarETab = xCaret ;
edit . setCaretPosition ( 74 ) ;
yCarLLTab = yCaret ;
edit . setCaretPosition ( 11 ) ;
yCarFLTab = yCaret ;
}
} ) ;
hitKey ( rob , KeyEvent . VK_T ) ;
hitKey ( rob , KeyEvent . VK_E ) ;
hitKey ( rob , KeyEvent . VK_S ) ;
hitKey ( rob , KeyEvent . VK_T ) ;
hitKey ( rob , KeyEvent . VK_BACK_SPACE ) ;
hitKey ( rob , KeyEvent . VK_BACK_SPACE ) ;
hitKey ( rob , KeyEvent . VK_BACK_SPACE ) ;
hitKey ( rob , KeyEvent . VK_BACK_SPACE ) ;
rob . waitForIdle ( ) ;
SwingUtilities . invokeAndWait ( new Runnable ( ) {
@Override
public void run ( ) {
//Calculate caret coordinate differences and catch caret positions after insertions.
edit . setCaretPosition ( 6 ) ;
dxCarBTab = Math . abs ( xCarBTab - xCaret ) ;
edit . setCaretPosition ( 91 ) ;
dxCarETab = Math . abs ( xCarETab - xCaret ) ;
edit . setCaretPosition ( 74 ) ;
dyCarLLTab = Math . abs ( yCarLLTab - yCaret ) ;
edit . setCaretPosition ( 11 ) ;
dyCarFLTab = Math . abs ( yCarFLTab - yCaret ) ;
edit . setCaretPosition ( 74 ) ;
yCarLLTab = yCaret ;
edit . setCaretPosition ( 11 ) ;
yCarFLTab = yCaret ;
}
} ) ;
Object dp = edit . getDocument ( ) . getProperty ( " i18n " ) ;
Boolean isI18n = dp instanceof Boolean ? ( Boolean ) dp : Boolean . FALSE ;
String i18n = isI18n ? " \ nWhen i18n enable, " : " \ nWhen i18n disable, " ;
if ( Math . abs ( yCarFLTab - yCarLLTab ) < 10 ) {
isTabWrong = Boolean . TRUE ;
Prop = Prop + i18n + " test can't be completed : TableView layout wrong, lines overlap, see JDK-8133864. " ;
} else {
if ( dyCarFLTab ! = 0 | | dyCarLLTab ! = 0 ) {
isTabWrong = Boolean . TRUE ;
Prop = Prop + i18n + " TableView layout wrong : Table high change when inserts and removes caracters, bug never reported yet. First Line dy= " + dyCarFLTab + " Last Line dy= " + dyCarLLTab ;
}
if ( dxCarBTab ! = 0 | | dxCarETab ! = 0 ) {
isTabWrong = Boolean . TRUE ;
Prop = Prop + i18n + " TableView layout wrong : Table width change when inserts and removes caracters, see JDK-8158209 and JDK-7169915. Before Table dx= " + dxCarBTab + " After Table dx= " + dxCarETab ;
}
2016-03-24 20:03:38 +03:00
}
2017-03-06 22:52:45 +03:00
rob . waitForIdle ( ) ;
SwingUtilities . invokeAndWait ( new Runnable ( ) {
@Override
public void run ( ) {
frame . dispose ( ) ;
}
} ) ;
}
if ( isTabWrong ) {
throw new RuntimeException ( Prop ) ;
2016-03-24 20:03:38 +03:00
}
2017-03-06 22:52:45 +03:00
2016-03-24 20:03:38 +03:00
System . out . println ( " ok " ) ;
}
2017-03-06 22:52:45 +03:00
private static void hitKey ( Robot robot , int k ) throws Exception {
robot . delay ( 50 ) ;
robot . keyPress ( k ) ;
robot . keyRelease ( k ) ;
robot . delay ( 50 ) ;
}
2016-03-24 20:03:38 +03:00
}
//------------------------------------------------------------------------------
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 void setParent ( View parent ) {
super . setParent ( parent ) ;
}
@Override
public void setSize ( float width , float height ) {
super . setSize ( width , height ) ;
}
@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 float getPreferredSpan ( int axis ) {
2017-03-06 22:52:45 +03:00
if ( axis = = 0 ) {
return super . getPreferredSpan ( 0 ) ;
}
2016-03-24 20:03:38 +03:00
float preferredSpan = super . getPreferredSpan ( axis ) ;
return preferredSpan ;
}
@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 {
2017-03-06 22:52:45 +03:00
2016-03-24 20:03:38 +03:00
@Override
public void setParent ( View parent ) {
super . setParent ( parent ) ;
}
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 ) ;
}
2017-03-06 22:52:45 +03:00
} ;
2016-03-24 20:03:38 +03:00
}
//------------------------------------------------------------------------------
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 ( ) {
2017-03-06 22:52:45 +03:00
//putProperty("i18n", Boolean.TRUE);
2016-03-24 20:03:38 +03:00
}
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 ) ;
2017-03-06 22:52:45 +03:00
ElementSpec tableStart
= new ElementSpec ( tableAttrs , ElementSpec . StartTagType ) ;
2016-03-24 20:03:38 +03:00
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 + + ) {
2017-03-06 22:52:45 +03:00
ElementSpec rowStart
= new ElementSpec ( rowAttrs , ElementSpec . StartTagType ) ;
2016-03-24 20:03:38 +03:00
Specs . add ( rowStart ) ;
fillCellSpecs ( Specs , colCount ) ;
2017-03-06 22:52:45 +03:00
ElementSpec rowEnd
= new ElementSpec ( rowAttrs , ElementSpec . EndTagType ) ;
2016-03-24 20:03:38 +03:00
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 ) ;
2017-03-06 22:52:45 +03:00
ElementSpec cellStart
= new ElementSpec ( cellAttrs , ElementSpec . StartTagType ) ;
2016-03-24 20:03:38 +03:00
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 ) ;
2017-03-06 22:52:45 +03:00
ElementSpec cellEnd
= new ElementSpec ( cellAttrs , ElementSpec . EndTagType ) ;
2016-03-24 20:03:38 +03:00
Specs . add ( cellEnd ) ;
}
}
2016-07-07 16:21:45 +02:00
}