improve model/view split in bundle status, more nomenclature fixes

This commit is contained in:
Jason P. Leasure 2020-03-27 16:27:22 -04:00
parent ad897f263c
commit d8610b00be
11 changed files with 211 additions and 302 deletions

View file

@ -52,7 +52,7 @@ class GhidraScriptActionManager {
private GhidraScriptComponentProvider provider; private GhidraScriptComponentProvider provider;
private GhidraScriptMgrPlugin plugin; private GhidraScriptMgrPlugin plugin;
private DockingAction refreshAction; private DockingAction refreshAction;
private DockingAction scriptDirsAction; private DockingAction bundlePathsAction;
private DockingAction newAction; private DockingAction newAction;
private DockingAction runAction; private DockingAction runAction;
private DockingAction runLastAction; private DockingAction runLastAction;
@ -349,10 +349,10 @@ class GhidraScriptActionManager {
refreshAction.setEnabled(true); refreshAction.setEnabled(true);
plugin.getTool().addLocalAction(provider, refreshAction); plugin.getTool().addLocalAction(provider, refreshAction);
scriptDirsAction = new DockingAction("Bundle Status", plugin.getName()) { bundlePathsAction = new DockingAction("Bundle Status", plugin.getName()) {
@Override @Override
public void actionPerformed(ActionContext context) { public void actionPerformed(ActionContext context) {
provider.showBundleStatusDialog(); provider.showBundleStatusComponent();
} }
@Override @Override
@ -361,14 +361,14 @@ class GhidraScriptActionManager {
return (contextObject instanceof GTable) || (contextObject instanceof ResourceFile); return (contextObject instanceof GTable) || (contextObject instanceof ResourceFile);
} }
}; };
scriptDirsAction.setPopupMenuData(new MenuData(new String[] { "Bundle Status" }, bundlePathsAction.setPopupMenuData(new MenuData(new String[] { "Bundle Status" },
ResourceManager.loadImage("images/text_list_bullets.png"), null)); ResourceManager.loadImage("images/text_list_bullets.png"), null));
scriptDirsAction.setToolBarData( bundlePathsAction.setToolBarData(
new ToolBarData(ResourceManager.loadImage("images/text_list_bullets.png"), null)); new ToolBarData(ResourceManager.loadImage("images/text_list_bullets.png"), null));
scriptDirsAction.setDescription("Bundle Status"); bundlePathsAction.setDescription("Bundle Status");
scriptDirsAction.setEnabled(true); bundlePathsAction.setEnabled(true);
plugin.getTool().addLocalAction(provider, scriptDirsAction); plugin.getTool().addLocalAction(provider, bundlePathsAction);
helpAction = new DockingAction("Ghidra API Help", plugin.getName()) { helpAction = new DockingAction("Ghidra API Help", plugin.getName()) {
@Override @Override
@ -437,7 +437,7 @@ class GhidraScriptActionManager {
} }
HelpLocation getPathHelpLocation() { HelpLocation getPathHelpLocation() {
return new HelpLocation(plugin.getName(), scriptDirsAction.getName()); return new HelpLocation(plugin.getName(), bundlePathsAction.getName());
} }
HelpLocation getKeyBindingHelpLocation() { HelpLocation getKeyBindingHelpLocation() {

View file

@ -42,7 +42,6 @@ import generic.jar.ResourceFile;
import generic.util.Path; import generic.util.Path;
import ghidra.app.plugin.core.script.osgi.*; import ghidra.app.plugin.core.script.osgi.*;
import ghidra.app.script.*; import ghidra.app.script.*;
import ghidra.app.script.osgi.BundleHost;
import ghidra.app.services.ConsoleService; import ghidra.app.services.ConsoleService;
import ghidra.framework.options.SaveState; import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.ComponentProviderAdapter;
@ -131,12 +130,12 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
return editorMap; return editorMap;
} }
void showBundleStatusDialog() { void showBundleStatusComponent() {
bundleStatusProvider.setVisible(true); bundleStatusProvider.setVisible(true);
} }
private void performRefresh() { private void performRefresh() {
GhidraScriptUtil.setScriptDirectories(bundleStatusProvider.getPaths()); GhidraScriptUtil.setScriptBundlePaths(bundleStatusProvider.getModel().getPaths());
GhidraScriptUtil.clearMetadata(); GhidraScriptUtil.clearMetadata();
refresh(); refresh();
} }
@ -341,12 +340,12 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
} }
public List<BundlePath> getScriptDirectories() { public List<BundlePath> getScriptDirectories() {
return bundleStatusProvider.getPaths().stream().filter(BundlePath::isDirectory).collect( return bundleStatusProvider.getModel().getPaths().stream().filter(
Collectors.toList()); BundlePath::isDirectory).collect(Collectors.toList());
} }
public void enableScriptDirectory(ResourceFile scriptDir) { public void enableScriptDirectory(ResourceFile scriptDir) {
if (bundleStatusProvider.enablePath(scriptDir)) { if (bundleStatusProvider.getModel().enablePath(scriptDir)) {
Msg.showInfo(this, getComponent(), "Script Path Added/Enabled", Msg.showInfo(this, getComponent(), "Script Path Added/Enabled",
"The directory has been automatically enabled for use:\n" + "The directory has been automatically enabled for use:\n" +
scriptDir.getAbsolutePath()); scriptDir.getAbsolutePath());
@ -397,7 +396,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
} }
void runScript(String scriptName, TaskListener listener) { void runScript(String scriptName, TaskListener listener) {
List<BundlePath> dirPaths = bundleStatusProvider.getPaths(); List<BundlePath> dirPaths = bundleStatusProvider.getModel().getPaths();
for (Path dir : dirPaths) { for (Path dir : dirPaths) {
ResourceFile scriptSource = new ResourceFile(dir.getPath(), scriptName); ResourceFile scriptSource = new ResourceFile(dir.getPath(), scriptName);
if (scriptSource.exists()) { if (scriptSource.exists()) {
@ -537,7 +536,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
private void updateAvailableScriptFilesForAllPaths() { private void updateAvailableScriptFilesForAllPaths() {
List<ResourceFile> scriptsToRemove = tableModel.getScripts(); List<ResourceFile> scriptsToRemove = tableModel.getScripts();
List<ResourceFile> scriptAccumulator = new ArrayList<>(); List<ResourceFile> scriptAccumulator = new ArrayList<>();
List<BundlePath> bundlePaths = bundleStatusProvider.getPaths(); List<BundlePath> bundlePaths = bundleStatusProvider.getModel().getPaths();
for (BundlePath bundlePath : bundlePaths) { for (BundlePath bundlePath : bundlePaths) {
if (bundlePath.isDirectory()) { if (bundlePath.isDirectory()) {
updateAvailableScriptFilesForDirectory(scriptsToRemove, scriptAccumulator, updateAvailableScriptFilesForDirectory(scriptsToRemove, scriptAccumulator,
@ -734,10 +733,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
private void build() { private void build() {
bundleStatusProvider = bundleStatusProvider = new BundleStatusProvider(plugin.getTool(), plugin.getName());
new BundleStatusProvider(plugin.getTool(), plugin.getName(), BundleHost.getInstance());
bundleStatusProvider.setFileChooserProperties("Select Script Bundle",
"LastGhidraScriptBundle");
bundleStatusProvider.addListener(new BundlePathManagerListener() { bundleStatusProvider.addListener(new BundlePathManagerListener() {
@Override @Override
@ -745,6 +741,21 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
plugin.getTool().setConfigChanged(true); plugin.getTool().setConfigChanged(true);
performRefresh(); performRefresh();
} }
@Override
public void bundleEnablementChanged(BundlePath path, boolean enabled) {
System.err.printf("XXXX %s is now %s\n", path.toString(),
enabled ? "enabled" : "disabled");
if (path.isDirectory()) {
performRefresh();
}
}
@Override
public void bundleActivationChanged(BundlePath path, boolean newValue) {
System.err.printf("XXXX %s is now %s\n", path.toString(),
newValue ? "active" : "inactive");
}
}); });
scriptRoot = new RootNode(); scriptRoot = new RootNode();
@ -1015,8 +1026,8 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
bundleStatusProvider.restoreState(saveState); bundleStatusProvider.restoreState(saveState);
// pull in the just-loaded paths // pull in the just-loaded paths
List<BundlePath> paths = bundleStatusProvider.getPaths(); List<BundlePath> paths = bundleStatusProvider.getModel().getPaths();
GhidraScriptUtil.setScriptDirectories(paths); GhidraScriptUtil.setScriptBundlePaths(paths);
actionManager.restoreUserDefinedKeybindings(saveState); actionManager.restoreUserDefinedKeybindings(saveState);
actionManager.restoreScriptsThatAreInTool(saveState); actionManager.restoreScriptsThatAreInTool(saveState);

View file

@ -18,22 +18,12 @@ package ghidra.app.plugin.core.script.osgi;
public interface BundlePathManagerListener { public interface BundlePathManagerListener {
default public void pathMessage(String message) {
//
}
/** /**
* Called when the list of bundle paths changes * Called when the list of bundle paths changes
*/ */
default public void bundlesChanged() { public void bundlesChanged();
//
} public void bundleEnablementChanged(BundlePath path, boolean newValue);
public void bundleActivationChanged(BundlePath path, boolean newValue);
/**
* called when a bundle path changes
* @param path that whose attributes changed
*/
default public void bundlePathChanged(BundlePath path) {
//
}
} }

View file

@ -16,38 +16,69 @@
*/ */
package ghidra.app.plugin.core.script.osgi; package ghidra.app.plugin.core.script.osgi;
import java.util.*; import java.util.ArrayList;
import java.util.List;
import docking.widgets.table.AbstractSortedTableModel; import docking.widgets.table.AbstractSortedTableModel;
import generic.jar.ResourceFile;
import ghidra.app.script.GhidraScriptUtil; import ghidra.app.script.GhidraScriptUtil;
import ghidra.framework.preferences.Preferences;
import ghidra.util.Msg;
class BundleStatusModel extends AbstractSortedTableModel<BundlePath> { public class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
private static int column_counter = 0; List<Column> columns = new ArrayList<>();
static enum COLUMN { class Column {
Enabled(Boolean.class) { final Class<?> clazz;
final int index;
final String name;
Column(String name, Class<?> clazz) {
this.name = name;
this.index = columns.size();
columns.add(this);
this.clazz = clazz;
}
boolean editable(BundlePath path) {
return true;
}
Object getValue(BundlePath path) {
return path;
}
void setValue(BundlePath path, Object aValue) {
// do nothing
}
}
Column enabledColumn = new Column("Enabled", Boolean.class) {
@Override @Override
Object getValue(BundlePath path) { Object getValue(BundlePath path) {
return path.isEnabled(); return path.isEnabled();
} }
@Override @Override
void setValue(BundlePath path, Object aValue) { void setValue(BundlePath path, Object newValue) {
path.setEnabled((Boolean) aValue); path.setEnabled((Boolean) newValue);
provider.fireBundleEnablementChanged(path, (Boolean) newValue);
} }
}, };
Active(Boolean.class) { Column activeColumn = new Column("Active", Boolean.class) {
@Override @Override
Object getValue(BundlePath path) { Object getValue(BundlePath path) {
return path.isActive(); return path.isActive();
} }
@Override @Override
void setValue(BundlePath path, Object aValue) { void setValue(BundlePath path, Object newValue) {
path.setActive((Boolean) aValue); path.setActive((Boolean) newValue);
provider.fireBundleActivationChanged(path, (Boolean) newValue);
} }
}, };
Type(String.class) { Column typeColumn = new Column("Type", String.class) {
@Override @Override
boolean editable(BundlePath path) { boolean editable(BundlePath path) {
return false; return false;
@ -57,9 +88,9 @@ class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
Object getValue(BundlePath path) { Object getValue(BundlePath path) {
return path.getType().toString(); return path.getType().toString();
} }
};
}, Column pathColumn = new Column("Path", BundlePath.class) {
Path(BundlePath.class) {
@Override @Override
boolean editable(BundlePath path) { boolean editable(BundlePath path) {
return true; return true;
@ -72,40 +103,18 @@ class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
path.setPath(newpath.getPath()); path.setPath(newpath.getPath());
} }
} }
}, };
__badcolumnindex__(Object.class); Column badColumn = new Column("INVALID", Object.class);
{
columns.remove(columns.size() - 1); // pop badColumn
final Class<?> clazz;
final int index;
boolean editable(BundlePath path) {
return true;
} }
Object getValue(BundlePath path) { Column getColumn(int i) {
return path; if (i >= 0 && i < columns.size()) {
} return columns.get(i);
COLUMN(Class<?> clazz) {
this.index = column_counter++;
this.clazz = clazz;
}
static COLUMN[] vals = values();
static {
vals = Arrays.copyOf(vals, vals.length - 1);
}
static COLUMN val(int i) {
if (i >= 0 && i < vals.length) {
return vals[i];
}
return __badcolumnindex__;
}
void setValue(BundlePath path, Object aValue) {
// do nothing
} }
return badColumn;
} }
private BundleStatusProvider provider; private BundleStatusProvider provider;
@ -115,6 +124,7 @@ class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
super(); super();
this.provider = provider; this.provider = provider;
this.paths.addAll(dedupPaths(GhidraScriptUtil.getDefaultScriptBundles())); this.paths.addAll(dedupPaths(GhidraScriptUtil.getDefaultScriptBundles()));
fireTableDataChanged(); fireTableDataChanged();
} }
@ -136,7 +146,7 @@ class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
return new ArrayList<BundlePath>(paths); return new ArrayList<BundlePath>(paths);
} }
List<BundlePath> getPaths() { public List<BundlePath> getPaths() {
List<BundlePath> list = new ArrayList<>(); List<BundlePath> list = new ArrayList<>();
for (BundlePath path : paths) { for (BundlePath path : paths) {
if (path.isEnabled()) { if (path.isEnabled()) {
@ -146,20 +156,11 @@ class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
return list; return list;
} }
void setPaths(List<BundlePath> paths) { public void setPaths(List<BundlePath> paths) {
this.paths = new ArrayList<>(paths); this.paths = new ArrayList<>(paths);
fireTableDataChanged(); fireTableDataChanged();
} }
void setPaths(BundlePath[] pathsArr) {
paths.clear();
paths = new ArrayList<>();
for (BundlePath element : pathsArr) {
paths.add(element);
}
fireTableDataChanged();
}
void addPath(BundlePath path) { void addPath(BundlePath path) {
if (paths.contains(path)) { if (paths.contains(path)) {
return; return;
@ -169,20 +170,6 @@ class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
fireTableRowsInserted(index, index); fireTableRowsInserted(index, index);
} }
void removePath(BundlePath path) {
int index = paths.indexOf(path);
if (path.isEditable()) {
paths.remove(path);
}
else {
List<BundlePathManagerListener> listeners = provider.getListeners();
for (BundlePathManagerListener listener : listeners) {
listener.pathMessage("Unable to remove path.");
}
}
fireTableRowsDeleted(index, index);
}
void remove(int[] selectedRows) { void remove(int[] selectedRows) {
List<BundlePath> list = new ArrayList<>(); List<BundlePath> list = new ArrayList<>();
for (int selectedRow : selectedRows) { for (int selectedRow : selectedRows) {
@ -193,56 +180,18 @@ class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
paths.remove(path); paths.remove(path);
} }
else { else {
List<BundlePathManagerListener> listeners = provider.getListeners(); Msg.showInfo(this, this.provider.getComponent(), "Unabled to remove path",
for (BundlePathManagerListener listener : listeners) { "System path cannot be removed: " + path.toString());
listener.pathMessage("Unable to remove path.");
}
} }
} }
fireTableDataChanged(); fireTableDataChanged();
} }
int moveUp(int index) {
if (index < 0 || index >= paths.size()) {
return -1;
}
BundlePath path = paths.remove(index);
if (index == 0) {
paths.add(path);//place it last in the list
}
else {
paths.add(index - 1, path);
}
fireTableDataChanged();
return paths.indexOf(path);
}
int moveDown(int index) {
if (index < 0 || index >= paths.size()) {
return -1;
}
int size = paths.size();
BundlePath path = paths.remove(index);
if (index == size - 1) {
paths.add(0, path);//move to the top of the list
}
else {
paths.add(index + 1, path);
}
fireTableDataChanged();
return paths.indexOf(path);
}
/***************************************************/ /***************************************************/
@Override
public java.lang.Class<?> getColumnClass(int columnIndex) {
return COLUMN.val(columnIndex).clazz;
}
@Override @Override
public int getColumnCount() { public int getColumnCount() {
return COLUMN.vals.length; return columns.size();
} }
@Override @Override
@ -250,23 +199,31 @@ class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
return paths.size(); return paths.size();
} }
@Override
public java.lang.Class<?> getColumnClass(int columnIndex) {
return getColumn(columnIndex).clazz;
}
@Override @Override
public boolean isCellEditable(int rowIndex, int columnIndex) { public boolean isCellEditable(int rowIndex, int columnIndex) {
BundlePath path = paths.get(rowIndex); BundlePath path = paths.get(rowIndex);
return COLUMN.val(columnIndex).editable(path); return getColumn(columnIndex).editable(path);
} }
@Override @Override
public String getColumnName(int columnIndex) { public String getColumnName(int columnIndex) {
return COLUMN.val(columnIndex).toString(); return getColumn(columnIndex).name;
} }
@Override @Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) { public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
BundlePath path = paths.get(rowIndex); BundlePath path = paths.get(rowIndex);
COLUMN.val(columnIndex).setValue(path, aValue); getColumn(columnIndex).setValue(path, aValue);
fireTableDataChanged(); }
provider.fireBundlePathChanged(path);
@Override
public Object getColumnValueForRow(BundlePath path, int columnIndex) {
return getColumn(columnIndex).getValue(path);
} }
@Override @Override
@ -284,8 +241,29 @@ class BundleStatusModel extends AbstractSortedTableModel<BundlePath> {
return paths; return paths;
} }
@Override /**
public Object getColumnValueForRow(BundlePath path, int columnIndex) { * (add and) enable a path
return COLUMN.val(columnIndex).getValue(path); * @param file path to enable
* @return true if the path is new
*/
public boolean enablePath(ResourceFile file) {
ResourceFile dir = file.isDirectory() ? file : file.getParentFile();
for (BundlePath path : getAllPaths()) {
if (path.getPath().equals(dir)) {
if (!path.isEnabled()) {
path.setEnabled(true);
fireTableDataChanged();
provider.fireBundlesChanged();
return true;
}
return false;
}
}
BundlePath p = new BundlePath(dir);
p.setEnabled(true);
addPath(p);
Preferences.setProperty(BundleStatusProvider.preferenceForLastSelectedBundle, dir.getAbsolutePath());
provider.fireBundlesChanged();
return true;
} }
} }

View file

@ -22,14 +22,11 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableColumn; import javax.swing.table.TableColumn;
import docking.widgets.filechooser.GhidraFileChooser; import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.filechooser.GhidraFileChooserMode; import docking.widgets.filechooser.GhidraFileChooserMode;
import docking.widgets.table.*; import docking.widgets.table.*;
import generic.jar.ResourceFile;
import ghidra.app.script.osgi.BundleHost;
import ghidra.framework.options.SaveState; import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.ComponentProviderAdapter;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
@ -42,38 +39,40 @@ import resources.ResourceManager;
* component for managing OSGi bundle status * component for managing OSGi bundle status
*/ */
public class BundleStatusProvider extends ComponentProviderAdapter { public class BundleStatusProvider extends ComponentProviderAdapter {
static String preferenceForLastSelectedBundle = "LastGhidraScriptBundle";
private JPanel panel; private JPanel panel;
private GTable bundlePathTable; private GTable bundlePathTable;
private BundleStatusModel bundleStatusModel; private final BundleStatusModel bundleStatusModel;
private TableModelListener bundlePathModelListener;
private JButton addButton; private JButton addButton;
private JButton removeButton; private JButton removeButton;
private Color selectionColor; private Color selectionColor;
private GhidraFileChooser fileChooser; private GhidraFileChooser fileChooser;
private String preferenceForLastSelectedBundle = Preferences.LAST_IMPORT_DIRECTORY;
private String title = "Select File";
private GhidraFileFilter filter; private GhidraFileFilter filter;
private ArrayList<BundlePathManagerListener> listeners = new ArrayList<>(); private ArrayList<BundlePathManagerListener> listeners = new ArrayList<>();
private BundleHost bundleHost; void fireBundlesChanged() {
for (BundlePathManagerListener listener : listeners) {
public BundleStatusProvider(PluginTool tool, String owner, BundleHost bundleHost) { listener.bundlesChanged();
super(tool, "Bundle Status Manager", "my owner"); }
this.bundleHost = bundleHost;
build();
addToTool();
} }
/** void fireBundleEnablementChanged(BundlePath path, boolean newValue) {
* Set properties on the file chooser that is displayed when the "Add" button is pressed. for (BundlePathManagerListener listener : listeners) {
* @param title title of the file chooser listener.bundleEnablementChanged(path, newValue);
* @param preferenceForLastSelectedBundle Preference to use as the starting selection in the }
* file chooser }
*/
void fireBundleActivationChanged(BundlePath path, boolean newValue) {
for (BundlePathManagerListener listener : listeners) {
listener.bundleActivationChanged(path, newValue);
}
}
public BundleStatusProvider(PluginTool tool, String owner) {
super(tool, "Bundle Status Manager", owner);
this.bundleStatusModel = new BundleStatusModel(this);
public void setFileChooserProperties(String title, String preferenceForLastSelectedBundle) {
this.title = title;
this.preferenceForLastSelectedBundle = preferenceForLastSelectedBundle;
this.filter = new GhidraFileFilter() { this.filter = new GhidraFileFilter() {
@Override @Override
public String getDescription() { public String getDescription() {
@ -86,51 +85,13 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
} }
}; };
this.fileChooser = null; this.fileChooser = null;
build();
addToTool();
} }
/** public BundleStatusModel getModel() {
* Return enabled paths in the table. return bundleStatusModel;
* @return enabled paths
*/
public List<BundlePath> getPaths() {
return bundleStatusModel.getPaths();
}
/**
* (add and) enable a path
* @param file path to enable
* @return true if the path is new
*/
public boolean enablePath(ResourceFile file) {
ResourceFile dir = file.isDirectory() ? file : file.getParentFile();
for (BundlePath path : bundleStatusModel.getAllPaths()) {
if (path.getPath().equals(dir)) {
if (!path.isEnabled()) {
path.setEnabled(true);
bundleStatusModel.fireTableDataChanged();
fireBundlesChanged();
return true;
}
return false;
}
}
BundlePath p = new BundlePath(dir);
p.setEnabled(true);
bundleStatusModel.addPath(p);
Preferences.setProperty(preferenceForLastSelectedBundle, dir.getAbsolutePath());
fireBundlesChanged();
return true;
}
public void setPaths(List<BundlePath> paths) {
bundleStatusModel.setPaths(paths);
}
/**
* Clear the paths in the table.
*/
public void clear() {
bundleStatusModel.clear();
} }
public void addListener(BundlePathManagerListener listener) { public void addListener(BundlePathManagerListener listener) {
@ -143,22 +104,6 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
listeners.remove(listener); listeners.remove(listener);
} }
public List<BundlePathManagerListener> getListeners() {
return new ArrayList<>(listeners);
}
void fireBundlesChanged() {
for (BundlePathManagerListener listener : listeners) {
listener.bundlesChanged();
}
}
void fireBundlePathChanged(BundlePath path) {
for (BundlePathManagerListener listener : listeners) {
listener.bundlePathChanged(path);
}
}
private void build() { private void build() {
panel = new JPanel(new BorderLayout(5, 5)); panel = new JPanel(new BorderLayout(5, 5));
@ -187,13 +132,6 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
++gbc.gridy; ++gbc.gridy;
buttonPanel.add(removeButton, gbc); buttonPanel.add(removeButton, gbc);
bundlePathModelListener = e -> {
fireBundlesChanged();
};
bundleStatusModel = new BundleStatusModel(this);
bundleStatusModel.addTableModelListener(bundlePathModelListener);
bundlePathTable = new GTable(bundleStatusModel); bundlePathTable = new GTable(bundleStatusModel);
bundlePathTable.setName("BUNDLEPATH_TABLE"); bundlePathTable.setName("BUNDLEPATH_TABLE");
bundlePathTable.setSelectionBackground(selectionColor); bundlePathTable.setSelectionBackground(selectionColor);
@ -203,25 +141,25 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
int skinnyWidth = 50; int skinnyWidth = 50;
TableColumn column = TableColumn column =
bundlePathTable.getColumnModel().getColumn(BundleStatusModel.COLUMN.Enabled.index); bundlePathTable.getColumnModel().getColumn(bundleStatusModel.enabledColumn.index);
column.setPreferredWidth(skinnyWidth); column.setPreferredWidth(skinnyWidth);
column.setMinWidth(skinnyWidth); column.setMinWidth(skinnyWidth);
column.setMaxWidth(skinnyWidth); column.setMaxWidth(skinnyWidth);
column.setWidth(skinnyWidth); column.setWidth(skinnyWidth);
column = bundlePathTable.getColumnModel().getColumn(BundleStatusModel.COLUMN.Active.index); column = bundlePathTable.getColumnModel().getColumn(bundleStatusModel.activeColumn.index);
column.setPreferredWidth(skinnyWidth); column.setPreferredWidth(skinnyWidth);
column.setMinWidth(skinnyWidth); column.setMinWidth(skinnyWidth);
column.setMaxWidth(skinnyWidth); column.setMaxWidth(skinnyWidth);
column.setWidth(skinnyWidth); column.setWidth(skinnyWidth);
column = bundlePathTable.getColumnModel().getColumn(BundleStatusModel.COLUMN.Type.index); column = bundlePathTable.getColumnModel().getColumn(bundleStatusModel.typeColumn.index);
FontMetrics fontmetrics = panel.getFontMetrics(panel.getFont()); FontMetrics fontmetrics = panel.getFontMetrics(panel.getFont());
column.setMaxWidth(10 + column.setMaxWidth(10 +
SwingUtilities.computeStringWidth(fontmetrics, BundlePath.Type.SourceDir.toString())); SwingUtilities.computeStringWidth(fontmetrics, BundlePath.Type.SourceDir.toString()));
column = bundlePathTable.getColumnModel().getColumn(BundleStatusModel.COLUMN.Path.index); column = bundlePathTable.getColumnModel().getColumn(bundleStatusModel.pathColumn.index);
column.setCellRenderer(new GTableCellRenderer() { column.setCellRenderer(new GTableCellRenderer() {
@Override @Override
public Component getTableCellRendererComponent(GTableCellRenderingData data) { public Component getTableCellRendererComponent(GTableCellRenderingData data) {
@ -265,7 +203,7 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
private void remove() { private void remove() {
int[] selectedRows = bundlePathTable.getSelectedRows(); int[] selectedRows = bundlePathTable.getSelectedRows();
if (selectedRows == null) { if (selectedRows == null || selectedRows.length == 0) {
return; return;
} }
bundleStatusModel.remove(selectedRows); bundleStatusModel.remove(selectedRows);
@ -281,6 +219,7 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
bundlePathTable.setRowSelectionInterval(row, row); bundlePathTable.setRowSelectionInterval(row, row);
} }
updateButtonsEnabled(); updateButtonsEnabled();
fireBundlesChanged();
} }
private void add() { private void add() {
@ -288,7 +227,7 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
fileChooser = new GhidraFileChooser(panel); fileChooser = new GhidraFileChooser(panel);
fileChooser.setMultiSelectionEnabled(true); fileChooser.setMultiSelectionEnabled(true);
fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_AND_DIRECTORIES); fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_AND_DIRECTORIES);
fileChooser.setTitle(title); fileChooser.setTitle("Select Script Bundle(s)");
// fileChooser.setApproveButtonToolTipText(title); // fileChooser.setApproveButtonToolTipText(title);
if (filter != null) { if (filter != null) {
fileChooser.addFileFilter(new GhidraFileFilter() { fileChooser.addFileFilter(new GhidraFileFilter() {
@ -326,13 +265,10 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
BundlePath p = new BundlePath(element); BundlePath p = new BundlePath(element);
bundleStatusModel.addPath(p); bundleStatusModel.addPath(p);
} }
fireBundlesChanged();
} }
} }
/**
* Returns the GUI component for the path manager.
* @return the GUI component for the path manager
*/
@Override @Override
public JComponent getComponent() { public JComponent getComponent() {
return panel; return panel;
@ -376,12 +312,6 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
return; return;
} }
/*
* Temporarily remove the listener to prevent too many
* notifications from being sent.
*/
bundleStatusModel.removeTableModelListener(bundlePathModelListener);
boolean[] enableArr = boolean[] enableArr =
ss.getBooleans("BundleManagerPanel_ENABLE", new boolean[pathArr.length]); ss.getBooleans("BundleManagerPanel_ENABLE", new boolean[pathArr.length]);
boolean[] editArr = ss.getBooleans("BundleManagerPanel_EDIT", new boolean[pathArr.length]); boolean[] editArr = ss.getBooleans("BundleManagerPanel_EDIT", new boolean[pathArr.length]);
@ -415,10 +345,6 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
} }
} }
/*
* Reinstall the listener then fire the update.
*/
bundleStatusModel.addTableModelListener(bundlePathModelListener);
fireBundlesChanged(); fireBundlesChanged();
} }
@ -434,4 +360,8 @@ public class BundleStatusProvider extends ComponentProviderAdapter {
public void dispose() { public void dispose() {
bundlePathTable.dispose(); bundlePathTable.dispose();
} }
void selectRow(int rowIndex) {
bundlePathTable.selectRow(rowIndex);
}
} }

View file

@ -154,10 +154,10 @@ public class GhidraScriptUtil {
} }
/** /**
* Sets the script directories to the new paths. * Sets the script bundle paths
* @param newPaths the new script directories * @param newPaths the new script bundle paths
*/ */
public static void setScriptDirectories(List<BundlePath> newPaths) { public static void setScriptBundlePaths(List<BundlePath> newPaths) {
scriptBundlePaths = new ArrayList<>(newPaths); scriptBundlePaths = new ArrayList<>(newPaths);
} }

View file

@ -207,7 +207,7 @@ public class GhidraScriptRunner implements GhidraLaunchable {
} }
} }
} }
GhidraScriptUtil.setScriptDirectories(paths); GhidraScriptUtil.setScriptBundlePaths(paths);
StringBuffer buf = new StringBuffer("HEADLESS Script Paths:"); StringBuffer buf = new StringBuffer("HEADLESS Script Paths:");
for (ResourceFile dir : GhidraScriptUtil.getScriptSourceDirectories()) { for (ResourceFile dir : GhidraScriptUtil.getScriptSourceDirectories()) {

View file

@ -676,7 +676,7 @@ public class HeadlessAnalyzer {
} }
} }
} }
GhidraScriptUtil.setScriptDirectories(paths); GhidraScriptUtil.setScriptBundlePaths(paths);
StringBuffer buf = new StringBuffer("HEADLESS Script Paths:"); StringBuffer buf = new StringBuffer("HEADLESS Script Paths:");
for (ResourceFile dir : GhidraScriptUtil.getScriptSourceDirectories()) { for (ResourceFile dir : GhidraScriptUtil.getScriptSourceDirectories()) {

View file

@ -980,7 +980,7 @@ public abstract class AbstractGhidraScriptMgrPluginTest
// destroy any NewScriptxxx files...and Temp ones too // destroy any NewScriptxxx files...and Temp ones too
BundleStatusProvider bundleStatusProvider = BundleStatusProvider bundleStatusProvider =
(BundleStatusProvider) TestUtils.getInstanceField("bundlePathManager", provider); (BundleStatusProvider) TestUtils.getInstanceField("bundlePathManager", provider);
List<BundlePath> paths = bundleStatusProvider.getPaths(); List<BundlePath> paths = bundleStatusProvider.getModel().getPaths();
for (BundlePath path : paths) { for (BundlePath path : paths) {
File file = path.getPath().getFile(false); File file = path.getPath().getFile(false);
File[] listFiles = file.listFiles(); File[] listFiles = file.listFiles();

View file

@ -290,9 +290,9 @@ public class GhidraScriptMgrPlugin3Test extends AbstractGhidraScriptMgrPluginTes
dir.mkdirs(); dir.mkdirs();
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
List<BundlePath> paths = bundleStatusProvider.getPaths(); List<BundlePath> paths = bundleStatusProvider.getModel().getPaths();
paths.add(0, new BundlePath(dir)); paths.add(0, new BundlePath(dir));
bundleStatusProvider.setPaths(paths); bundleStatusProvider.getModel().setPaths(paths);
}); });
waitForSwing(); waitForSwing();

View file

@ -117,7 +117,7 @@ public class GhidraScriptMgrPluginScreenShots extends GhidraScreenShotGenerator
paths.add(new BundlePath("/User/defined/invalid/directory")); paths.add(new BundlePath("/User/defined/invalid/directory"));
BundleStatusProvider bundleStatusProvider = showProvider(BundleStatusProvider.class); BundleStatusProvider bundleStatusProvider = showProvider(BundleStatusProvider.class);
bundleStatusProvider.setPaths(paths); bundleStatusProvider.getModel().setPaths(paths);
waitForComponentProvider(BundleStatusProvider.class); waitForComponentProvider(BundleStatusProvider.class);
captureComponent(bundleStatusProvider.getComponent()); captureComponent(bundleStatusProvider.getComponent());