Fixed table dispose not accounting for a wrapped model; Fixed missing

dispose calls of GTableFilterPanel
This commit is contained in:
dragonmacher
2020-12-07 17:11:14 -05:00
parent f69546e508
commit 8be90db260
19 changed files with 111 additions and 78 deletions
@@ -343,7 +343,7 @@ public class BundleStatusComponentProvider extends ComponentProviderAdapter {
* cleanup this component
*/
public void dispose() {
bundleStatusTable.dispose();
filterPanel.dispose();
}
void selectModelRow(int modelRowIndex) {
@@ -27,7 +27,6 @@ import docking.help.HelpService;
import docking.widgets.label.GLabel;
import docking.widgets.table.GTableFilterPanel;
import docking.widgets.table.TableFilter;
import ghidra.app.events.ProgramSelectionPluginEvent;
import ghidra.app.plugin.core.scalartable.RangeFilterTextField.FilterType;
import ghidra.app.services.GoToService;
import ghidra.framework.plugintool.ComponentProviderAdapter;
@@ -116,8 +115,12 @@ public class ScalarSearchProvider extends ComponentProviderAdapter {
buffy.append(" [filter: ").append(minValueText).append(']'); // single scalar search
}
else if (!isDefaultFilterRange(minValueText, maxValueText)) {
buffy.append(" [filter: ").append(minValueText).append(" - ").append(
maxValueText).append(']');
buffy.append(" [filter: ")
.append(minValueText)
.append(" - ")
.append(
maxValueText)
.append(']');
}
setTitle(buffy.toString());
@@ -139,12 +142,6 @@ public class ScalarSearchProvider extends ComponentProviderAdapter {
return min.equals(Integer.toString(minValue)) && max.equals(Integer.toString(maxValue));
}
private void selectDataInProgramFromTable(ProgramSelection selection) {
ProgramSelectionPluginEvent pspe =
new ProgramSelectionPluginEvent("Selection", selection, plugin.getCurrentProgram());
plugin.firePluginEvent(pspe);
}
@Override
public void componentShown() {
scalarModel.reload();
@@ -183,7 +180,6 @@ public class ScalarSearchProvider extends ComponentProviderAdapter {
closeComponent();
threadedTablePanel.dispose();
filter.dispose();
scalarTable.dispose();
}
ProgramSelection getSelection() {
@@ -16,8 +16,6 @@
package ghidra.bitpatterns.gui;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.*;
@@ -42,13 +40,14 @@ public class ByteSequencePanelBuilder extends ContextRegisterFilterablePanelBuil
private JButton applyLengthFilterButton;
private JButton clearLengthFilterButton;
private JTextField numSeqsField;
private GFilterTable<ByteSequenceRowObject> filterTable;
private static final String APPLY_LENGTH_FILTER_BUTTON_TEXT = "Apply Length Filter";
private static final String CLEAR_LENGTH_FILTER_BUTTON_TEXT = "Clear Length Filter";
private static final String BYTE_SEQUENCE_LENGTH_FILTER_CREATER_TEXT = "Set Length Filter";
private static final String NUM_SEQS_LABEL_TEXT = " Number of Sequences ";
/**
* Creates a {@link ByteSequencePanelBuilder} in a given {@link FunctionBitPatternPlugin} for sequences of a
* Creates a {@link ByteSequencePanelBuilder} in a given {@link FunctionBitPatternsExplorerPlugin} for sequences of a
* given {@PatternType}
* @param plugin plugin
* @param type {@PatternType} of sequences
@@ -59,7 +58,7 @@ public class ByteSequencePanelBuilder extends ContextRegisterFilterablePanelBuil
}
/**
* Returns the last selected {@link ByteSequenceRowObjects}s of the table associated to
* Returns the last selected {@link ByteSequenceRowObject}s of the table associated to
* this panel
* @return the selected objects
*/
@@ -121,7 +120,7 @@ public class ByteSequencePanelBuilder extends ContextRegisterFilterablePanelBuil
mainPanel.add(getButtonPanel(), BorderLayout.SOUTH);
byteSeqTable = new DisassembledByteSequenceTableModel(plugin, rowObjects);
GFilterTable<ByteSequenceRowObject> filterTable = new GFilterTable<>(byteSeqTable);
filterTable = new GFilterTable<>(byteSeqTable);
mainPanel.add(filterTable, BorderLayout.CENTER, TABLE_INDEX);
addLengthFilterAndAnalysisButtons();
mainPanel.setVisible(true);
@@ -133,10 +132,12 @@ public class ByteSequencePanelBuilder extends ContextRegisterFilterablePanelBuil
*/
public void updateTable() {
mainPanel.remove(TABLE_INDEX);
filterTable.dispose();
rowObjects = ByteSequenceRowObject.getFilteredRowObjects(fsReader.getFInfoList(), type,
getContextRegisterFilter(), lengthFilter);
byteSeqTable = new DisassembledByteSequenceTableModel(plugin, rowObjects);
GFilterTable<ByteSequenceRowObject> filterTable = new GFilterTable<>(byteSeqTable);
filterTable = new GFilterTable<>(byteSeqTable);
int totalNumSeqs = 0;
for (ByteSequenceRowObject row : rowObjects) {
@@ -149,7 +150,7 @@ public class ByteSequencePanelBuilder extends ContextRegisterFilterablePanelBuil
}
/**
* Sets the {@link FileBitsPatternInfoReader} object to use a data source
* Sets the {@link FileBitPatternInfoReader} object to use a data source
* @param fsReader {@link FileBitPatternInfoReader} object containing the sequences to analyze
*/
public void setFsReader(FileBitPatternInfoReader fsReader) {
@@ -163,43 +164,40 @@ public class ByteSequencePanelBuilder extends ContextRegisterFilterablePanelBuil
applyLengthFilterButton = new JButton(APPLY_LENGTH_FILTER_BUTTON_TEXT);
getButtonPanel().add(applyLengthFilterButton);
applyLengthFilterButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ByteSequenceLengthFilterInputDialog filterCreator =
new ByteSequenceLengthFilterInputDialog(
BYTE_SEQUENCE_LENGTH_FILTER_CREATER_TEXT, mainPanel);
if (filterCreator.isCanceled()) {
return;
}
lengthFilter = filterCreator.getValue();
applyFilterAction();
applyLengthFilterButton.addActionListener(e -> {
ByteSequenceLengthFilterInputDialog filterCreator =
new ByteSequenceLengthFilterInputDialog(
BYTE_SEQUENCE_LENGTH_FILTER_CREATER_TEXT, mainPanel);
if (filterCreator.isCanceled()) {
return;
}
lengthFilter = filterCreator.getValue();
applyFilterAction();
});
clearLengthFilterButton = new JButton(CLEAR_LENGTH_FILTER_BUTTON_TEXT);
getButtonPanel().add(clearLengthFilterButton);
clearLengthFilterButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
lengthFilter = null;
updateTable();
}
clearLengthFilterButton.addActionListener(e -> {
lengthFilter = null;
updateTable();
});
}
/**
* Enables the "Apply Length Filter" and "Clear Length Filter" buttons based on a boolean input
* @param buttons will be enabled precisely when this parameter is {@code true}
* @param enabled will be enabled precisely when this parameter is {@code true}
*/
public void enableLengthFilterButtons(boolean x) {
public void enableLengthFilterButtons(boolean enabled) {
if (applyLengthFilterButton != null) {
applyLengthFilterButton.setEnabled(x);
applyLengthFilterButton.setEnabled(enabled);
}
if (clearLengthFilterButton != null) {
clearLengthFilterButton.setEnabled(x);
clearLengthFilterButton.setEnabled(enabled);
}
return;
}
public void dispose() {
filterTable.dispose();
}
}
@@ -88,13 +88,10 @@ public class ClipboardPanel extends JPanel {
buttonPanel = new JPanel(new FlowLayout());
JButton deletedButton = new JButton("Remove Selected Patterns");
deletedButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
List<PatternInfoRowObject> selected = filterTable.getSelectedRowObjects();
plugin.removePatterns(selected);
updateClipboard();
}
deletedButton.addActionListener(e -> {
List<PatternInfoRowObject> selected = filterTable.getSelectedRowObjects();
plugin.removePatterns(selected);
updateClipboard();
});
buttonPanel.add(deletedButton);
@@ -415,6 +412,7 @@ public class ClipboardPanel extends JPanel {
*/
public void updateClipboard() {
remove(filterTable);
filterTable.dispose();
patternInfoTable = new PatternInfoTableModel(plugin);
filterTable = new GFilterTable<>(patternInfoTable);
add(filterTable, 0);
@@ -495,4 +493,7 @@ public class ClipboardPanel extends JPanel {
return patternInfoTable.getLastSelectedObjects();
}
public void dispose() {
filterTable.dispose();
}
}
@@ -41,8 +41,9 @@ public class ClosedPatternTableDialog extends DialogComponentProvider {
private DockingAction sendToClipboardAction;
private static final String TITLE = "Closed Patterns";
private ClosedPatternTableModel closedPatternTableModel;
private FunctionBitPatternsExplorerPlugin plugin;
private GThreadedTablePanel<ClosedPatternRowObject> tablePanel;
private JPanel mainPanel;
private FunctionBitPatternsExplorerPlugin plugin;
private PatternType type;
private ContextRegisterFilter cRegFilter;
@@ -77,9 +78,8 @@ public class ClosedPatternTableDialog extends DialogComponentProvider {
private JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
GThreadedTablePanel<ClosedPatternRowObject> table =
new GThreadedTablePanel<>(closedPatternTableModel);
panel.add(table, BorderLayout.CENTER);
tablePanel = new GThreadedTablePanel<>(closedPatternTableModel);
panel.add(tablePanel, BorderLayout.CENTER);
return panel;
}
@@ -122,4 +122,8 @@ public class ClosedPatternTableDialog extends DialogComponentProvider {
this.addAction(sendToClipboardAction);
}
@Override
public void close() {
tablePanel.dispose();
}
}
@@ -451,6 +451,8 @@ public class FunctionBitPatternsMainProvider extends ComponentProviderAdapter
* Removes the action from the tool.
*/
public void dispose() {
firstBytesPanel.dispose();
clipboard.dispose();
tool.removeAction(gatherDataFromProgramAction);
}
@@ -308,6 +308,7 @@ public class FidSearchResultFrame extends JFrame implements FidQueryCloseListene
@Override
public void dispose() {
table.dispose();
dbService.removeCloseListener(this);
super.dispose();
}
@@ -70,6 +70,11 @@ public class ListSelectionTableDialog<T> extends DialogComponentProvider {
}
}
@Override
public void close() {
filterPanel.dispose();
}
private JComponent build() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
@@ -127,7 +132,7 @@ public class ListSelectionTableDialog<T> extends DialogComponentProvider {
public void setMultiSelectionMode(boolean enable) {
if (enable) {
gTable.getSelectionModel()
.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
}
else {
gTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
@@ -89,4 +89,9 @@ public class ObjectChooserDialog<T> extends DialogComponentProvider {
public void setFilterText(String text) {
table.setFilterText(text);
}
@Override
public void close() {
table.dispose();
}
}
@@ -93,12 +93,14 @@ public class TableChooserDialog<T> extends DialogComponentProvider {
protected void okCallback() {
selectedItems = gFilterTable.getSelectedRowObjects();
close();
gFilterTable.dispose();
}
@Override
protected void cancelCallback() {
selectedItems = null;
close();
gFilterTable.dispose();
}
@Override
@@ -555,4 +555,16 @@ public abstract class GDynamicColumnTableModel<ROW_TYPE, DATA_SOURCE>
DynamicTableColumn<ROW_TYPE, ?, ?> column = tableColumns.get(index);
return column.getMaxLines(columnSettings.get(column));
}
@Override
public void dispose() {
super.dispose();
disposeDynamicColumnData();
}
protected void disposeDynamicColumnData() {
tableColumns.clear();
defaultTableColumns.clear();
columnSettings.clear();
}
}
@@ -42,7 +42,6 @@ public class GFilterTable<ROW_OBJECT> extends JPanel {
public void dispose() {
filterPanel.dispose();
table.dispose();
}
private void buildTable() {
@@ -279,8 +279,9 @@ public class GTable extends JTable {
* Call this when the table will no longer be used
*/
public void dispose() {
if (dataModel instanceof AbstractGTableModel) {
((AbstractGTableModel<?>) dataModel).dispose();
TableModel unwrappedeModel = getUnwrappedTableModel();
if (unwrappedeModel instanceof AbstractGTableModel) {
((AbstractGTableModel<?>) unwrappedeModel).dispose();
}
if (columnModel instanceof GTableColumnModel) {
@@ -223,4 +223,8 @@ public class GTableWidget<T> extends JPanel {
public void setFilterText(String text) {
gFilterTable.setFiterText(text);
}
public void dispose() {
gFilterTable.dispose();
}
}
@@ -23,6 +23,7 @@ import javax.swing.*;
import docking.widgets.EmptyBorderButton;
import docking.widgets.label.GLabel;
import docking.widgets.table.GTable;
import ghidra.util.Swing;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorComponent;
import resources.Icons;
@@ -30,6 +31,8 @@ import resources.Icons;
/**
* A convenience component designed specifically for rendering threaded table models.
* This panel will automatically create a threaded table and a task monitor component.
*
* @param <T> the type
*/
public class GThreadedTablePanel<T> extends JPanel {
@@ -135,7 +138,6 @@ public class GThreadedTablePanel<T> extends JPanel {
public void dispose() {
threadedModel.dispose();
table.dispose();
}
public TaskMonitor getTaskMonitor() {
@@ -162,22 +164,23 @@ public class GThreadedTablePanel<T> extends JPanel {
}
/**
* Returns the underlying table.
* Returns the underlying table
* @return the table
*/
public GTable getTable() {
return table;
}
private void handleUpdatePending() {
SwingUtilities.invokeLater(showPendingRunnable);
Swing.runLater(showPendingRunnable);
}
private void handleUpdating() {
SwingUtilities.invokeLater(showProgressRunnable);
Swing.runLater(showProgressRunnable);
}
private void handleUpdateComplete() {
SwingUtilities.invokeLater(updateCompleteRunnable);
Swing.runLater(updateCompleteRunnable);
}
private void doUpdateComplete() {
@@ -24,6 +24,7 @@ import docking.widgets.table.*;
import docking.widgets.table.sort.DefaultColumnComparator;
import generic.concurrent.ConcurrentListenerSet;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.util.Swing;
import ghidra.util.SystemUtilities;
import ghidra.util.datastruct.*;
import ghidra.util.exception.*;
@@ -123,7 +124,7 @@ public abstract class ThreadedTableModel<ROW_OBJECT, DATA_SOURCE>
TaskMonitor monitor, boolean loadIncrementally) {
super(serviceProvider);
if (!SwingUtilities.isEventDispatchThread()) {
if (!Swing.isSwingThread()) {
throw new AssertException(
"You must create the ThreadedTableModel in the AWT Event Dispatch Thread");
}
@@ -143,7 +144,7 @@ public abstract class ThreadedTableModel<ROW_OBJECT, DATA_SOURCE>
// We are expecting to be in the swing thread. We want the reload to happen after our
// constructor is fully completed since the reload will cause our initialize method to
// be called in another thread, thereby creating a possible race condition.
SwingUtilities.invokeLater(() -> updateManager.reload());
Swing.runLater(() -> updateManager.reload());
}
public boolean isLoadIncrementally() {
@@ -617,12 +618,11 @@ public abstract class ThreadedTableModel<ROW_OBJECT, DATA_SOURCE>
*/
@Override
public void fireTableChanged(TableModelEvent e) {
if (SwingUtilities.isEventDispatchThread()) {
if (Swing.isSwingThread()) {
super.fireTableChanged(e);
return;
}
final TableModelEvent e1 = e;
SwingUtilities.invokeLater(() -> ThreadedTableModel.super.fireTableChanged(e1));
Swing.runLater(() -> ThreadedTableModel.super.fireTableChanged(e));
}
/**
@@ -636,6 +636,7 @@ public abstract class ThreadedTableModel<ROW_OBJECT, DATA_SOURCE>
worker.dispose();
}
doClearData();
disposeDynamicColumnData();
}
/**
@@ -21,14 +21,12 @@ import java.awt.event.MouseEvent;
import java.util.*;
import javax.swing.BorderFactory;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import docking.ActionContext;
import docking.DialogComponentProvider;
import docking.widgets.table.GTableCellRenderer;
import docking.widgets.table.GTableCellRenderingData;
import docking.widgets.table.*;
import docking.widgets.table.threaded.GThreadedTablePanel;
import docking.widgets.table.threaded.ThreadedTableModelListener;
import ghidra.framework.main.datatable.ProjectDataContext;
@@ -46,7 +44,7 @@ public class FindCheckoutsDialog extends DialogComponentProvider {
private FindCheckoutsTableModel model;
private Plugin plugin;
private DomainFolder folder;
private JTable table;
private GTable table;
private boolean showMessage = true;
private GThreadedTablePanel<CheckoutInfo> threadedTablePanel;
@@ -123,7 +121,7 @@ public class FindCheckoutsDialog extends DialogComponentProvider {
@Override
public void close() {
super.close();
model.dispose();
threadedTablePanel.dispose();
}
@Override
@@ -99,8 +99,6 @@ public class KeyBindingsPanel extends JPanel {
public void dispose() {
tableFilterPanel.dispose();
tableModel.dispose();
actionTable.dispose();
propertyChangeListener = null;
}
@@ -71,7 +71,7 @@ public class PluginInstallerDialog extends DialogComponentProvider {
@Override
protected void dialogShown() {
// users often wish to start typing in the filter when the dialog appeears
// users often wish to start typing in the filter when the dialog appears
tableFilterPanel.requestFocus();
}
@@ -84,7 +84,6 @@ public class PluginInstallerDialog extends DialogComponentProvider {
public void close() {
super.close();
tableFilterPanel.dispose();
table.dispose();
}
/**
@@ -173,10 +172,14 @@ public class PluginInstallerDialog extends DialogComponentProvider {
TableSortState.createDefaultSortState(PluginInstallerTableModel.NAME_COL));
tableModel.refresh();
table.getColumnModel().getColumn(PluginInstallerTableModel.NAME_COL).setCellRenderer(
new NameCellRenderer());
table.getColumnModel().getColumn(PluginInstallerTableModel.STATUS_COL).setCellRenderer(
new StatusCellRenderer());
table.getColumnModel()
.getColumn(PluginInstallerTableModel.NAME_COL)
.setCellRenderer(
new NameCellRenderer());
table.getColumnModel()
.getColumn(PluginInstallerTableModel.STATUS_COL)
.setCellRenderer(
new StatusCellRenderer());
HelpService help = Help.getHelpService();
help.registerHelp(table, new HelpLocation(GenericHelpTopics.TOOL, "PluginDialog"));