mgarin / weblaf

WebLaF is a fully open-source Look & Feel and component library written in pure Java for cross-platform desktop Swing applications.
http://weblookandfeel.com
GNU General Public License v3.0
1.14k stars 235 forks source link

TableRowHeightOptimizer.optimizeRowHeight Issue #662

Closed tullisar closed 3 years ago

tullisar commented 3 years ago

WebLAF Version: 1.2.13 Java: OpenJDK (Zulu Build) 15.27+17 OS: Windows 10

The method TableRowHeightOptimizer.optimizeRowHeight throws an error for a table with no rows visible as a result of a row filter being applied. It seems to be as a result of the code taking the following path (I've omitted chunks for brevity)

if (model.getRowCount() > 0)
    ...
    if ( vr.width > 0 && vr.height > 0 ) { ....... } // evaluated to false, not sure why? is it because there are no rows?
    else 
        for( ... )
            final TableCellRenderer cellRenderer = component.getCellRenderer(0, col);   // succeeds, uses default renderer
            final Component renderer = component.prepareRenderer(cellRenderer, 0, col); // fails, call to getValueAt is first thing

I think using model.getRowCount() might be the source of the issue? I'm working to see there's something else going on in my code elsewhere but when following the stack trace this seemed odd to me. If needed, I can post a full source code example, but it seems like it should be pretty easy to reproduce with a bare bones row sorter/filter that hides all elements.

RowFilter<TableModel, Integer> filter = new RowFilter<TableModel, Integer>() 
{
    public boolean include( final RowFilter.Entry<? extends TableModel, ? extends Integer> entry)
    {
        return false;
    }
}

TableRowSorter<TableModel> sorter = new TableRowSorter<>(model)
sorter.setRowFilter(filter)
table.setRowSorter(sorter)
mgarin commented 3 years ago

Thanks for reporting the issue! I'll look into this.

mgarin commented 3 years ago

I've added a fix for this issue in d452e7fa7fb88e5fe8044547f6d7248e73e9fdf9 commit. It will be included in v1.2.14 update.

mgarin commented 3 years ago

Just in case, for the future reference, here is a code example I used to reproduce the issue:

import com.alee.api.annotations.NotNull;
import com.alee.extended.debug.SwingTest;
import com.alee.extended.debug.TestFrame;
import com.alee.laf.scroll.WebScrollPane;
import com.alee.laf.table.WebTable;
import com.alee.utils.swing.WebTimer;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * @author Mikle Garin
 */
@SuppressWarnings ( "JavaDoc" )
public final class Test
{
    public static void main ( final String[] args )
    {
        SwingTest.run ( new Runnable ()
        {
            @Override
            public void run ()
            {
                final DefaultTableModel model = createModel ();

                final WebTable table = new WebTable ( model );
                table.setOptimizeRowHeight ( true );

                final RowFilter<TableModel, Integer> filter = new RowFilter<TableModel, Integer> ()
                {
                    @Override
                    public boolean include ( final RowFilter.Entry<? extends TableModel, ? extends Integer> entry )
                    {
                        return false;
                    }
                };

                final TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel> ( model );
                sorter.setRowFilter ( filter );
                table.setRowSorter ( sorter );

                TestFrame.show ( new WebScrollPane ( table ) );

                WebTimer.repeat ( 1000, true, new ActionListener ()
                {
                    @Override
                    public void actionPerformed ( final ActionEvent actionEvent )
                    {
                        table.setModel ( createModel () );
                    }
                } );
            }
        } );
    }

    @NotNull
    private static DefaultTableModel createModel ()
    {
        return new DefaultTableModel (
                new String[][]{
                        { "1", "2", "3" },
                        { "1", "2", "3" },
                        { "1", "2", "3" }
                },
                new String[]{ "1", "2", "3" }
        );
    }
}

It only occurred at pretty specific circumstances, but even so - it is fairly possible to encounter it in real application.

tullisar commented 2 years ago

Out of curiosity, is the 1.2.14 update available on a beta channel of any kind?

mgarin commented 2 years ago

If you're getting your dependencies from Maven - you can use version from snapshot repository:

<dependencies>
    <dependency>
        <groupId>com.weblookandfeel</groupId>
        <artifactId>weblaf-ui</artifactId>
        <version>1.2.14-SNAPSHOT</version>
    </dependency>
</dependencies>

<repositories>
    <repository>
        <id>sonatype-snapshot-rep</id>
        <name>Sonatype snapshot repository</name>
        <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    </repository>
</repositories>

Or you can directly download artifacts for each module you need: https://oss.sonatype.org/content/repositories/snapshots/com/weblookandfeel/

tullisar commented 2 years ago

I just noticed that the new function prepareRenderer in the updated TableRowHeightOptimizer has the parameters (model, col, row). In optimizeRowHeight, line 169 it's called with (model, row, col). It's called correctly on line 179 it looks like though.

mgarin commented 2 years ago

@tullisar That's a good catch! I probably confused the parameters because usually in Swing they're addressed in order row->col in most cases, but the method had it backwards.

I pushed a small fix for this, snapshot build containing the fix should soon be available.