renatoathaydes / Automaton

Simple framework which allows the testing of Swing and JavaFX2 applications.
Apache License 2.0
100 stars 21 forks source link

JTable cells are selected by their model value rather than the rendered value #32

Closed meyertee closed 9 years ago

meyertee commented 9 years ago

If you use a custom renderer to render a File instance for example, the selectors will only match against the model object's string-value rather than what is actually rendered, e.g.

def tModel = [
        [ firstCol: new File("a.txt"), secCol: new File("b.txt") ],
]
def cellRenderer = new DefaultTableCellRenderer(){
    @Override
    protected void setValue(Object value) {
        setText(((File)value).getAbsolutePath())
    }
}
JTable jTable =  table {
    tableModel( list: tModel ) {
        propertyColumn( header: 'Col 1', propertyName: 'firstCol', type: File.class, cellRenderer: cellRenderer )
        propertyColumn( header: 'Col 2', propertyName: 'secCol', type: File.class, cellRenderer: cellRenderer )
    }
}

This will match only 'text:a.txt rather than the absolute path of the file as rendered by the cell renderer.

I'll create a PR with a suggested fix.

meyertee commented 9 years ago

Here's a workaround in Groovy, which I currently use in my Spock tests. It changes Automaton's utility method to the one suggested in the PR:

static def MetaMethod origNavigateBreadthFirst
def setupSpec() {
    origNavigateBreadthFirst = SwingUtil.metaClass.getStaticMetaMethod("navigateBreadthFirst", JTable, Closure)
    SwingUtil.metaClass.static.navigateBreadthFirst = { JTable table, Closure action ->
        def cols = (0..<table.model.columnCount)
        def rows = (0..<table.model.rowCount)
        for (col in cols) {
            if (action(table.model.getColumnName(col), -1, col)) return true
        }
        for (row in rows) {
            for (col in cols) {
                if (action(getRenderedTableValue(table, row, col), row, col)) return true
            }
        }
        return false
    }
}

def cleanupSpec() {
    SwingUtil.metaClass.static.navigateBreadthFirst = origNavigateBreadthFirst;
}

private Object getRenderedTableValue(JTable table, row, col) {
    def value = table.model.getValueAt(row, col)
    def rendererComp = table.getCellRenderer(row, col)
            .getTableCellRendererComponent(table, value, false, false, row, col)
    if (rendererComp instanceof JLabel) {
        (rendererComp as JLabel).getText()
    } else {
        return value
    }
}
renatoathaydes commented 9 years ago

Hi @meyertee the code you've contributed has been released with verison 1.3.0-beta. could you please try it out and confirm everything works for you?

Thanks.

meyertee commented 8 years ago

Works without workaround in 1.3.0-beta, as does the rest of my tests!

(Just needed to overwrite the swing-selectors version in build.gradle as described in this comment).