From 36ba098bb6ac185ced14a9082cf477cdd119a8d3 Mon Sep 17 00:00:00 2001 From: Cole Leavitt Date: Fri, 22 Aug 2025 14:18:02 -0700 Subject: [PATCH 1/2] Fix PSI access threading issues in CsvTableModelSwing --- .../table/swing/CsvTableModelSwing.java | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/main/java/net/seesharpsoft/intellij/plugins/csv/editor/table/swing/CsvTableModelSwing.java b/src/main/java/net/seesharpsoft/intellij/plugins/csv/editor/table/swing/CsvTableModelSwing.java index a3423b62..72020353 100644 --- a/src/main/java/net/seesharpsoft/intellij/plugins/csv/editor/table/swing/CsvTableModelSwing.java +++ b/src/main/java/net/seesharpsoft/intellij/plugins/csv/editor/table/swing/CsvTableModelSwing.java @@ -1,6 +1,7 @@ package net.seesharpsoft.intellij.plugins.csv.editor.table.swing; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiElement; import net.seesharpsoft.intellij.plugins.csv.CsvHelper; import net.seesharpsoft.intellij.plugins.csv.editor.table.CsvTableEditor; @@ -25,12 +26,9 @@ public class CsvTableModelSwing extends CsvTableModelBase implements TableModel { - /** - * List of listeners - */ protected EventListenerList listenerList = new EventListenerList(); - protected ScheduledFuture delayedUpdate; + protected ScheduledFuture delayedUpdate; protected ScheduledExecutorService executorService; @@ -64,10 +62,7 @@ private void doNotifyUpdate() { } protected void fireTableChanged(TableModelEvent e) { - // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); - // Process the listeners last to first, notifying - // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == TableModelListener.class) { ((TableModelListener) listeners[i + 1]).tableChanged(e); @@ -97,17 +92,17 @@ public void removeTableModelListener(TableModelListener l) { @Override public String getColumnName(int column) { - PsiElement headerField = PsiHelper.findFirst(getPsiFile(), CsvTypes.FIELD); - if (headerField != null) { - headerField = PsiHelper.getNextNthSiblingOfType(headerField, column, CsvField.class); - } - String headerText = headerField == null ? "" : CsvHelper.unquoteCsvValue(headerField.getText(), getEscapeCharacter()).trim(); - - Map params = new HashMap<>(); - params.put("header", headerText); - params.put("index", CsvEditorSettings.getInstance().isZeroBasedColumnNumbering() ? column : column + 1); - - return CsvHelper.formatString("${header} (${index})", params); + return ApplicationManager.getApplication().runReadAction((Computable) () -> { + PsiElement headerField = PsiHelper.findFirst(getPsiFile(), CsvTypes.FIELD); + if (headerField != null) { + headerField = PsiHelper.getNextNthSiblingOfType(headerField, column, CsvField.class); + } + String headerText = headerField == null ? "" : CsvHelper.unquoteCsvValue(headerField.getText(), getEscapeCharacter()).trim(); + Map params = new HashMap<>(); + params.put("header", headerText); + params.put("index", CsvEditorSettings.getInstance().isZeroBasedColumnNumbering() ? column : column + 1); + return CsvHelper.formatString("${header} (${index})", params); + }); } @Override From 5f59e72d27ab739a2f68087b75d94ac33f19bef1 Mon Sep 17 00:00:00 2001 From: Cole Leavitt Date: Fri, 22 Aug 2025 14:38:29 -0700 Subject: [PATCH 2/2] CsvTableModelSwing: add docstring for getColumnName and add back in original comments --- .../csv/editor/table/swing/CsvTableModelSwing.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/seesharpsoft/intellij/plugins/csv/editor/table/swing/CsvTableModelSwing.java b/src/main/java/net/seesharpsoft/intellij/plugins/csv/editor/table/swing/CsvTableModelSwing.java index 72020353..df367b84 100644 --- a/src/main/java/net/seesharpsoft/intellij/plugins/csv/editor/table/swing/CsvTableModelSwing.java +++ b/src/main/java/net/seesharpsoft/intellij/plugins/csv/editor/table/swing/CsvTableModelSwing.java @@ -26,6 +26,9 @@ public class CsvTableModelSwing extends CsvTableModelBase implements TableModel { + /** + * List of listeners + */ protected EventListenerList listenerList = new EventListenerList(); protected ScheduledFuture delayedUpdate; @@ -62,7 +65,10 @@ private void doNotifyUpdate() { } protected void fireTableChanged(TableModelEvent e) { + // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); + // Process the listeners last to first, notifying + // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == TableModelListener.class) { ((TableModelListener) listeners[i + 1]).tableChanged(e); @@ -90,6 +96,10 @@ public void removeTableModelListener(TableModelListener l) { listenerList.remove(TableModelListener.class, l); } + /** + * Gets header name for a given column, with index formatting. + * PSI access is wrapped in a read action for thread safety. + */ @Override public String getColumnName(int column) { return ApplicationManager.getApplication().runReadAction((Computable) () -> { @@ -114,4 +124,4 @@ public Class getColumnClass(int columnIndex) { public boolean isCellEditable(int rowIndex, int columnIndex) { return getPsiFileHolder().isEditable(); } -} +} \ No newline at end of file