kirill-grouchnikov / substance

A modern and high-performant Swing look-and-feel library
164 stars 109 forks source link

SubstanceTableHeaderUI not being able to find draggedColumn #70

Closed IvanRF closed 6 years ago

IvanRF commented 6 years ago

Version of Substance

Not the latest but the code is still the same on SubstanceTableHeaderUI

Version of Java

8 update 144

Version of OS

Win 10

The issue you're experiencing (expected vs actual, screenshot, stack trace etc)

First time in years I see this issue. If/When I have some time I will write a test code. Steps to reproduce (how I saw it):

In this particular scenario many confirm dialogs were shown and I click multiple times in the buttons area until the process finished. My guess is that some of clicks maybe were catched by the table header and by the time the EDT is ready to process them, the JTable had a different model.

Thus, function viewIndexForColumn() returns -1 for draggedColumnIndex on SubstanceTableHeaderUI.java#L431.

I debugged the error and aColumn in the call to viewIndexForColumn() was present in header.getColumnModel() but with a different object id. That's why I guess is trying to find an old column from the previous DefaultTableColumnModel.

The UI section where the table is located becomes unresponsive and an exception is thrown for every mouse movement on that area.

The question is how to solve this. Maybe the painting should be avoided when draggedColumnIndex is -1.

This is the exception:

Exception in thread "AWT-EventQueue-1" java.lang.ArrayIndexOutOfBoundsException: -1
    at java.util.Vector.elementData(Vector.java:734)
    at java.util.Vector.elementAt(Vector.java:477)
    at javax.swing.table.DefaultTableColumnModel.getColumn(DefaultTableColumnModel.java:294)
    at org.pushingpixels.substance.internal.ui.SubstanceTableHeaderUI.getHeaderRenderer(SubstanceTableHeaderUI.java:457)
    at org.pushingpixels.substance.internal.ui.SubstanceTableHeaderUI.paintCell(SubstanceTableHeaderUI.java:640)
    at org.pushingpixels.substance.internal.ui.SubstanceTableHeaderUI.paint(SubstanceTableHeaderUI.java:441)
    at org.pushingpixels.substance.internal.ui.SubstanceTableHeaderUI.__org__pushingpixels__substance__internal__ui__SubstanceTableHeaderUI__update(SubstanceTableHeaderUI.java:773)
    at org.pushingpixels.substance.internal.ui.SubstanceTableHeaderUI.update(SubstanceTableHeaderUI.java)
    at javax.swing.JComponent.paintComponent(JComponent.java:780)
    at javax.swing.JComponent.paint(JComponent.java:1056)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JViewport.paint(JViewport.java:728)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JComponent.paintToOffscreen(JComponent.java:5210)
    at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
    at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
    at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
    at javax.swing.JComponent._paintImmediately(JComponent.java:5158)
    at javax.swing.JComponent.paintImmediately(JComponent.java:4969)
    at javax.swing.RepaintManager$4.run(RepaintManager.java:831)
    at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
    at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
    at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
    at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
    at java.awt.EventQueue.access$500(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:709)
    at java.awt.EventQueue$3.run(EventQueue.java:703)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
kirill-grouchnikov commented 6 years ago

There's not much to operate on here without a simple standalone sample that reproduces this issue under the latest Substance dev builds.

It might be in Substance. It might be in core Swing classes. Or it might be in application code that is incorrectly changes UI state off the UI thread.

IvanRF commented 6 years ago

I will try to make a sample for the lastest Substance. In the app, all changes to UI components are made in the UI thread.

IvanRF commented 6 years ago

I was able to reproduce the issue on the latest version.

Here is sample app: test.zip

And a console screenshot: 2018-01-22_14-32-59

It cost me a little to reproduce it. You need to start dragging/moving columns while the SwingWorker is processing, in the example simulated with a Thread.sleep().

kirill-grouchnikov commented 6 years ago

Same exact thing happens under Metal.

kirill-grouchnikov commented 6 years ago

And Aqua (default macOS swing LAF)

IvanRF commented 6 years ago

Oh, yes, BasicTableHeaderUI functions code is the same as SubstanceTableHeaderUI

IvanRF commented 6 years ago

It seems it has been there for a while: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6480543

kirill-grouchnikov commented 6 years ago

I see. Looks like this indeed can be worked around in a couple of places in the table UI delegate that draw the dragged column / cells. I'll upload the bits tonight or tomorrow.

IvanRF commented 6 years ago

excellent, thanks!