From 4fb895028578e126538ecf3cb1370969860049cd Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Tue, 12 Mar 2024 12:16:59 -0400 Subject: [PATCH] GP-4321 - Fixed 'Copy Columns...' action in tables --- .../docking/widgets/table/GTableTest.java | 3 +- .../java/docking/widgets/table/GTable.java | 64 +++++++++++++++---- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/Ghidra/Features/Base/src/test.slow/java/docking/widgets/table/GTableTest.java b/Ghidra/Features/Base/src/test.slow/java/docking/widgets/table/GTableTest.java index dbbc66b15a..4760500967 100644 --- a/Ghidra/Features/Base/src/test.slow/java/docking/widgets/table/GTableTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/docking/widgets/table/GTableTest.java @@ -35,7 +35,6 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest { private GhidraTable table; private JFrame frame; - private long testKeyTimeout = 100; private boolean timeoutTriggered; @Before @@ -56,7 +55,7 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest { } private void installTestAutoLookupTimeout() { - // note: this call will not work due to the unpredictable timing of event + // note: this call will not work due to the unpredictable timing of event // processing in the various test environments // table.setAutoLookupTimeout(testKeyTimeout); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java index c96359269d..052d782647 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java @@ -18,6 +18,7 @@ package docking.widgets.table; import static docking.DockingUtils.*; import static docking.action.MenuData.*; import static java.awt.event.InputEvent.*; +import static javax.swing.ListSelectionModel.*; import java.awt.*; import java.awt.event.*; @@ -1158,30 +1159,31 @@ public class GTable extends JTable { private void copyColumns(int... copyColumns) { - int[] originalColumns = new int[0]; - boolean wasAllowed = getColumnSelectionAllowed(); - if (wasAllowed) { - originalColumns = getSelectedColumns(); - } - - setColumnSelectionAllowed(true); - setSelectedColumns(copyColumns); + // + // We have to change the column model's selection settings to ensure that the copy works + // correctly. For example, if the model only allows single column selection, then we have + // to change that to allow for multiple column selection. We will put the original state + // back when finished. + // + ColumnSelectionState originalState = ColumnSelectionState.copy(this); + ColumnSelectionState newState = ColumnSelectionState.withColumns(this, copyColumns); + newState.apply(); copying = true; try { - Action builtinCopyAction = TransferHandler.getCopyAction(); builtinCopyAction.actionPerformed(new ActionEvent(GTable.this, 0, "copy")); } finally { copying = false; - - // put back whatever selection existed before this action was executed - setSelectedColumns(originalColumns); - setColumnSelectionAllowed(wasAllowed); + originalState.apply(); // put back column model's original selection state } } + private int getColumnSelectionMode() { + return getColumnModel().getSelectionModel().getSelectionMode(); + } + private void setSelectedColumns(int[] columns) { columnModel.getSelectionModel().clearSelection(); for (int column : columns) { @@ -1442,6 +1444,42 @@ public class GTable extends JTable { // Inner Classes //================================================================================================== + /** + * A class that captures attribute of the table's column model so that we can change and then + * restore those values. + */ + private static class ColumnSelectionState { + private GTable table; + private boolean selectionAllowed; + private int[] selectedColumns; + private int selectionMode; + + ColumnSelectionState(GTable table, boolean selectionAllowed, int selectionMode, + int[] selectedColumns) { + this.table = table; + this.selectionAllowed = selectionAllowed; + this.selectedColumns = selectedColumns; + this.selectionMode = selectionMode; + } + + void apply() { + table.getColumnModel().getSelectionModel().setSelectionMode(selectionMode); + table.setColumnSelectionAllowed(selectionAllowed); + table.setSelectedColumns(selectedColumns); + } + + static ColumnSelectionState withColumns(GTable table, int[] columns) { + return new ColumnSelectionState(table, true, MULTIPLE_INTERVAL_SELECTION, columns); + } + + static ColumnSelectionState copy(GTable table) { + int[] columns = table.getSelectedColumns(); + boolean allowed = table.getColumnSelectionAllowed(); + int mode = table.getColumnSelectionMode(); + return new ColumnSelectionState(table, allowed, mode, columns); + } + } + private class MyTableColumnModelListener implements TableColumnModelListener { @Override public void columnSelectionChanged(ListSelectionEvent e) {