mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GT-2925 - Key Bindings - Support Window Menu Provider Key Bindings -
test and review fixes
This commit is contained in:
parent
6015650079
commit
a88ecfe6b5
40 changed files with 499 additions and 392 deletions
|
@ -73,14 +73,15 @@ public class SampleProgramTreePlugin extends ProgramPlugin {
|
||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
modularize();
|
modularize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabledForContext(ActionContext context) {
|
||||||
|
return currentProgram != null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
action.setMenuBarData(
|
action.setMenuBarData(
|
||||||
new MenuData(new String[] { "Misc", "Create Sample Tree" }, null, null));
|
new MenuData(new String[] { "Misc", "Create Sample Tree" }, null, null));
|
||||||
|
|
||||||
action.setEnabled(false);
|
|
||||||
|
|
||||||
action.setDescription("Plugin to create a program tree and modularize accordingly");
|
action.setDescription("Plugin to create a program tree and modularize accordingly");
|
||||||
enableOnProgram(action);
|
|
||||||
tool.addAction(action);
|
tool.addAction(action);
|
||||||
|
|
||||||
}// end of createActions()
|
}// end of createActions()
|
||||||
|
|
|
@ -32,7 +32,6 @@ import ghidra.program.util.ProgramChangeRecord;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sample plugin for dealing with Programs. The base class handles
|
* Sample plugin for dealing with Programs. The base class handles
|
||||||
* the event processing and enabling/disabling of actions. This
|
* the event processing and enabling/disabling of actions. This
|
||||||
|
@ -51,107 +50,98 @@ import ghidra.util.Msg;
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
public class TemplateProgramPlugin extends ProgramPlugin implements DomainObjectListener {
|
public class TemplateProgramPlugin extends ProgramPlugin implements DomainObjectListener {
|
||||||
|
|
||||||
private DockingAction action;
|
private DockingAction action;
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
*
|
*
|
||||||
* Standard Plugin Constructor
|
* Standard Plugin Constructor
|
||||||
*
|
*
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
public TemplateProgramPlugin(PluginTool tool) {
|
public TemplateProgramPlugin(PluginTool tool) {
|
||||||
|
|
||||||
super(tool,
|
super(tool, true, // true means this plugin consumes ProgramLocation events
|
||||||
true, // true means this plugin consumes ProgramLocation events
|
false); // false means this plugin does not consume
|
||||||
false); // false means this plugin does not consume
|
// ProgramSelection events
|
||||||
// ProgramSelection events
|
// the base class ProgramPlugin handles all the event registering
|
||||||
// the base class ProgramPlugin handles all the event registering
|
|
||||||
|
|
||||||
// set up list of actions.
|
// set up list of actions.
|
||||||
setupActions();
|
setupActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the callback method for DomainObjectChangedEvents.
|
* This is the callback method for DomainObjectChangedEvents.
|
||||||
*/
|
*/
|
||||||
public void domainObjectChanged(DomainObjectChangedEvent ev) {
|
@Override
|
||||||
for (int i=0; i< ev.numRecords(); i++) {
|
public void domainObjectChanged(DomainObjectChangedEvent ev) {
|
||||||
DomainObjectChangeRecord record = ev.getChangeRecord(i);
|
for (int i = 0; i < ev.numRecords(); i++) {
|
||||||
if (record instanceof ProgramChangeRecord) {
|
DomainObjectChangeRecord record = ev.getChangeRecord(i);
|
||||||
@SuppressWarnings("unused")
|
if (record instanceof ProgramChangeRecord) {
|
||||||
ProgramChangeRecord r = (ProgramChangeRecord)record;
|
@SuppressWarnings("unused")
|
||||||
// code for processing the record...
|
ProgramChangeRecord r = (ProgramChangeRecord) record;
|
||||||
// ...
|
// code for processing the record...
|
||||||
}
|
// ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the program is opened.
|
* Called when the program is opened.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void programActivated(Program program) {
|
protected void programActivated(Program program) {
|
||||||
program.addListener(this);
|
program.addListener(this);
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Called when the program is closed.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void programDeactivated(Program program) {
|
|
||||||
program.removeListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
/**
|
||||||
********************************************************************
|
* Called when the program is closed.
|
||||||
**
|
*/
|
||||||
**
|
@Override
|
||||||
** Function 1
|
protected void programDeactivated(Program program) {
|
||||||
**
|
program.removeListener(this);
|
||||||
**
|
}
|
||||||
********************************************************************
|
|
||||||
*******************************************************************/
|
|
||||||
private void Function_1 () {
|
|
||||||
// do something with a program location
|
|
||||||
Msg.info(this, getPluginDescription().getName()
|
|
||||||
+ ": Program Location==> " + currentLocation.getAddress());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
********************************************************************
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** Function 1
|
||||||
|
**
|
||||||
|
**
|
||||||
|
********************************************************************
|
||||||
|
*******************************************************************/
|
||||||
|
private void Function_1() {
|
||||||
|
// do something with a program location
|
||||||
|
Msg.info(this, getPluginDescription().getName() + ": Program Location==> " +
|
||||||
|
currentLocation.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up Actions
|
* Set up Actions
|
||||||
*/
|
*/
|
||||||
private void setupActions() {
|
private void setupActions() {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Function 1
|
// Function 1
|
||||||
//
|
//
|
||||||
action = new DockingAction("Function 1 Code", getName() ) {
|
action = new DockingAction("Function 1 Code", getName()) {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionContext e) {
|
public void actionPerformed(ActionContext e) {
|
||||||
Function_1();
|
Function_1();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidContext( ActionContext context ) {
|
public boolean isValidContext(ActionContext context) {
|
||||||
return context instanceof ListingActionContext;
|
return context instanceof ListingActionContext;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
action.setEnabled( false );
|
action.setEnabled(false);
|
||||||
|
|
||||||
|
|
||||||
action.setMenuBarData( new MenuData(
|
|
||||||
new String[]{"Misc", "Menu","Menu item 1"}, null, null ) );
|
|
||||||
|
|
||||||
|
|
||||||
// call method in base class to enable this action when a
|
|
||||||
// program location event comes in; disable it when focus is
|
|
||||||
// lost; it will be disable when the program is closed
|
|
||||||
enableOnLocation(action);
|
|
||||||
|
|
||||||
action.setHelpLocation(new HelpLocation("SampleHelpTopic",
|
|
||||||
"TemplateProgramPlugin_Anchor_Name"));
|
|
||||||
tool.addAction(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
action.setMenuBarData(
|
||||||
|
new MenuData(new String[] { "Misc", "Menu", "Menu item 1" }, null, null));
|
||||||
|
|
||||||
|
action.setHelpLocation(
|
||||||
|
new HelpLocation("SampleHelpTopic", "TemplateProgramPlugin_Anchor_Name"));
|
||||||
|
tool.addAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,6 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin;
|
package ghidra.app.plugin;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import docking.ActionContext;
|
||||||
|
import docking.action.DockingAction;
|
||||||
import ghidra.app.events.*;
|
import ghidra.app.events.*;
|
||||||
import ghidra.app.services.GoToService;
|
import ghidra.app.services.GoToService;
|
||||||
import ghidra.framework.plugintool.*;
|
import ghidra.framework.plugintool.*;
|
||||||
|
@ -25,10 +28,6 @@ import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.program.util.ProgramSelection;
|
import ghidra.program.util.ProgramSelection;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import docking.action.DockingAction;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class to handle common program events: Program Open/Close,
|
* Base class to handle common program events: Program Open/Close,
|
||||||
* Program Location, Program Selection, and Program Highlight.
|
* Program Location, Program Selection, and Program Highlight.
|
||||||
|
@ -87,10 +86,10 @@ public abstract class ProgramPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
registerEventConsumed(ProgramOpenedPluginEvent.class);
|
registerEventConsumed(ProgramOpenedPluginEvent.class);
|
||||||
registerEventConsumed(ProgramClosedPluginEvent.class);
|
registerEventConsumed(ProgramClosedPluginEvent.class);
|
||||||
programActionList = new ArrayList<DockingAction>(3);
|
programActionList = new ArrayList<>(3);
|
||||||
locationActionList = new ArrayList<DockingAction>(3);
|
locationActionList = new ArrayList<>(3);
|
||||||
selectionActionList = new ArrayList<DockingAction>(3);
|
selectionActionList = new ArrayList<>(3);
|
||||||
highlightActionList = new ArrayList<DockingAction>(3);
|
highlightActionList = new ArrayList<>(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProgramPlugin(PluginTool tool, boolean consumeLocationChange,
|
public ProgramPlugin(PluginTool tool, boolean consumeLocationChange,
|
||||||
|
@ -201,7 +200,10 @@ public abstract class ProgramPlugin extends Plugin {
|
||||||
* the program is closed.
|
* the program is closed.
|
||||||
* @throws IllegalArgumentException if this action was called for
|
* @throws IllegalArgumentException if this action was called for
|
||||||
* another enableOnXXX(PlugAction) method.
|
* another enableOnXXX(PlugAction) method.
|
||||||
|
* @deprecated {@link ActionContext} is now used for action enablement. Deprecated in 9.1; to
|
||||||
|
* be removed no sooner than two versions after that.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
protected void enableOnProgram(DockingAction action) {
|
protected void enableOnProgram(DockingAction action) {
|
||||||
if (locationActionList.contains(action)) {
|
if (locationActionList.contains(action)) {
|
||||||
throw new IllegalArgumentException("Action already added to location action list");
|
throw new IllegalArgumentException("Action already added to location action list");
|
||||||
|
@ -222,7 +224,10 @@ public abstract class ProgramPlugin extends Plugin {
|
||||||
* is null.
|
* is null.
|
||||||
* @throws IllegalArgumentException if this action was called for
|
* @throws IllegalArgumentException if this action was called for
|
||||||
* another enableOnXXX(PlugAction) method.
|
* another enableOnXXX(PlugAction) method.
|
||||||
|
* @deprecated {@link ActionContext} is now used for action enablement. Deprecated in 9.1; to
|
||||||
|
* be removed no sooner than two versions after that.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
protected void enableOnLocation(DockingAction action) {
|
protected void enableOnLocation(DockingAction action) {
|
||||||
if (programActionList.contains(action)) {
|
if (programActionList.contains(action)) {
|
||||||
throw new IllegalArgumentException("Action already added to program action list");
|
throw new IllegalArgumentException("Action already added to program action list");
|
||||||
|
@ -243,7 +248,10 @@ public abstract class ProgramPlugin extends Plugin {
|
||||||
* the selection is null or empty.
|
* the selection is null or empty.
|
||||||
* @throws IllegalArgumentException if this action was called for
|
* @throws IllegalArgumentException if this action was called for
|
||||||
* another enableOnXXX(PlugAction) method.
|
* another enableOnXXX(PlugAction) method.
|
||||||
|
* @deprecated {@link ActionContext} is now used for action enablement. Deprecated in 9.1; to
|
||||||
|
* be removed no sooner than two versions after that.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
protected void enableOnSelection(DockingAction action) {
|
protected void enableOnSelection(DockingAction action) {
|
||||||
if (programActionList.contains(action)) {
|
if (programActionList.contains(action)) {
|
||||||
throw new IllegalArgumentException("Action already added to program action list");
|
throw new IllegalArgumentException("Action already added to program action list");
|
||||||
|
@ -263,7 +271,10 @@ public abstract class ProgramPlugin extends Plugin {
|
||||||
* the highlight is null or empty.
|
* the highlight is null or empty.
|
||||||
* @throws IllegalArgumentException if this action was called for
|
* @throws IllegalArgumentException if this action was called for
|
||||||
* another enableOnXXX(PlugAction) method.
|
* another enableOnXXX(PlugAction) method.
|
||||||
|
* @deprecated {@link ActionContext} is now used for action enablement. Deprecated in 9.1; to
|
||||||
|
* be removed no sooner than two versions after that.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
protected void enableOnHighlight(DockingAction action) {
|
protected void enableOnHighlight(DockingAction action) {
|
||||||
if (programActionList.contains(action)) {
|
if (programActionList.contains(action)) {
|
||||||
throw new IllegalArgumentException("Action already added to program action list");
|
throw new IllegalArgumentException("Action already added to program action list");
|
||||||
|
@ -378,8 +389,8 @@ public abstract class ProgramPlugin extends Plugin {
|
||||||
if (currentProgram == null) {
|
if (currentProgram == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
firePluginEvent(new ProgramSelectionPluginEvent(getName(), new ProgramSelection(set),
|
firePluginEvent(
|
||||||
currentProgram));
|
new ProgramSelectionPluginEvent(getName(), new ProgramSelection(set), currentProgram));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -58,9 +58,9 @@ public class BookmarkProvider extends ComponentProviderAdapter {
|
||||||
BookmarkProvider(PluginTool tool, BookmarkPlugin plugin) {
|
BookmarkProvider(PluginTool tool, BookmarkPlugin plugin) {
|
||||||
super(tool, "Bookmarks", plugin.getName(), ProgramActionContext.class);
|
super(tool, "Bookmarks", plugin.getName(), ProgramActionContext.class);
|
||||||
|
|
||||||
setIcon(BookmarkNavigator.NOTE_ICON, true);
|
setIcon(BookmarkNavigator.NOTE_ICON);
|
||||||
setDefaultKeyBinding(
|
addToToolbar();
|
||||||
new KeyBindingData(KeyEvent.VK_B, DockingUtils.CONTROL_KEY_MODIFIER_MASK));
|
setKeyBinding(new KeyBindingData(KeyEvent.VK_B, DockingUtils.CONTROL_KEY_MODIFIER_MASK));
|
||||||
|
|
||||||
model = new BookmarkTableModel(tool, null);
|
model = new BookmarkTableModel(tool, null);
|
||||||
threadedTablePanel = new GhidraThreadedTablePanel<>(model);
|
threadedTablePanel = new GhidraThreadedTablePanel<>(model);
|
||||||
|
|
|
@ -107,7 +107,8 @@ public class CallTreeProvider extends ComponentProviderAdapter implements Domain
|
||||||
setWindowMenuGroup(TITLE);
|
setWindowMenuGroup(TITLE);
|
||||||
setDefaultWindowPosition(WindowPosition.BOTTOM);
|
setDefaultWindowPosition(WindowPosition.BOTTOM);
|
||||||
|
|
||||||
setIcon(CallTreePlugin.PROVIDER_ICON, true);
|
setIcon(CallTreePlugin.PROVIDER_ICON);
|
||||||
|
addToToolbar();
|
||||||
setHelpLocation(new HelpLocation(plugin.getName(), "Call_Tree_Plugin"));
|
setHelpLocation(new HelpLocation(plugin.getName(), "Call_Tree_Plugin"));
|
||||||
|
|
||||||
addToTool();
|
addToTool();
|
||||||
|
|
|
@ -117,13 +117,18 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
|
||||||
|
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.formatMgr = formatMgr;
|
this.formatMgr = formatMgr;
|
||||||
|
|
||||||
setConnected(isConnected);
|
setConnected(isConnected);
|
||||||
|
setIcon(ResourceManager.loadImage("images/Browser.gif"));
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
setTransient();
|
setTransient();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
addToToolbar();
|
||||||
|
}
|
||||||
setHelpLocation(new HelpLocation("CodeBrowserPlugin", "Code_Browser"));
|
setHelpLocation(new HelpLocation("CodeBrowserPlugin", "Code_Browser"));
|
||||||
setDefaultWindowPosition(WindowPosition.RIGHT);
|
setDefaultWindowPosition(WindowPosition.RIGHT);
|
||||||
setIcon(ResourceManager.loadImage("images/Browser.gif"), isConnected);
|
|
||||||
listingPanel = new ListingPanel(formatMgr);
|
listingPanel = new ListingPanel(formatMgr);
|
||||||
listingPanel.enablePropertyBasedColorModel(true);
|
listingPanel.enablePropertyBasedColorModel(true);
|
||||||
decorationPanel = new ListingPanelContainer(listingPanel, isConnected);
|
decorationPanel = new ListingPanelContainer(listingPanel, isConnected);
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.commentwindow;
|
package ghidra.app.plugin.core.commentwindow;
|
||||||
|
|
||||||
import docking.ActionContext;
|
|
||||||
import docking.action.DockingAction;
|
import docking.action.DockingAction;
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.events.ProgramSelectionPluginEvent;
|
import ghidra.app.events.ProgramSelectionPluginEvent;
|
||||||
|
@ -186,13 +185,7 @@ public class CommentWindowPlugin extends ProgramPlugin implements DomainObjectLi
|
||||||
|
|
||||||
private void createActions() {
|
private void createActions() {
|
||||||
|
|
||||||
selectAction = new MakeProgramSelectionAction(getName(), provider.getTable()) {
|
selectAction = new MakeProgramSelectionAction(this, provider.getTable());
|
||||||
@Override
|
|
||||||
protected void makeSelection(ActionContext context) {
|
|
||||||
selectComment(provider.selectComment());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
tool.addLocalAction(provider, selectAction);
|
tool.addLocalAction(provider, selectAction);
|
||||||
|
|
||||||
DockingAction selectionAction = new SelectionNavigationAction(this, provider.getTable());
|
DockingAction selectionAction = new SelectionNavigationAction(this, provider.getTable());
|
||||||
|
|
|
@ -100,7 +100,8 @@ public class DataTypesProvider extends ComponentProviderAdapter {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
||||||
setTitle(TITLE);
|
setTitle(TITLE);
|
||||||
setIcon(ResourceManager.loadImage(DATA_TYPES_ICON), true);
|
setIcon(ResourceManager.loadImage(DATA_TYPES_ICON));
|
||||||
|
addToToolbar();
|
||||||
|
|
||||||
navigationHistory.setAllowDuplicates(true);
|
navigationHistory.setAllowDuplicates(true);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ package ghidra.app.plugin.core.datawindow;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import docking.ActionContext;
|
|
||||||
import docking.action.DockingAction;
|
import docking.action.DockingAction;
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.events.ProgramSelectionPluginEvent;
|
import ghidra.app.events.ProgramSelectionPluginEvent;
|
||||||
|
@ -180,13 +179,7 @@ public class DataWindowPlugin extends ProgramPlugin implements DomainObjectListe
|
||||||
*/
|
*/
|
||||||
private void createActions() {
|
private void createActions() {
|
||||||
|
|
||||||
selectAction = new MakeProgramSelectionAction(getName(), provider.getTable()) {
|
selectAction = new MakeProgramSelectionAction(this, provider.getTable());
|
||||||
@Override
|
|
||||||
protected void makeSelection(ActionContext context) {
|
|
||||||
selectData(provider.selectData());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
tool.addLocalAction(provider, selectAction);
|
tool.addLocalAction(provider, selectAction);
|
||||||
|
|
||||||
filterAction = new FilterAction(this);
|
filterAction = new FilterAction(this);
|
||||||
|
|
|
@ -524,10 +524,28 @@ public class AddressTableDialog extends DialogComponentProvider {
|
||||||
|
|
||||||
private void createAction() {
|
private void createAction() {
|
||||||
|
|
||||||
DockingAction selectAction = new MakeProgramSelectionAction(DIALOG_NAME, resultsTable) {
|
DockingAction selectAction = new MakeProgramSelectionAction(plugin, resultsTable) {
|
||||||
@Override
|
@Override
|
||||||
protected void makeSelection(ActionContext context) {
|
protected ProgramSelection makeSelection(ActionContext context) {
|
||||||
doMakeSelection();
|
Program program = plugin.getProgram();
|
||||||
|
AddressSet set = new AddressSet();
|
||||||
|
AutoTableDisassemblerModel model = plugin.getModel();
|
||||||
|
int[] selectedRows = resultsTable.getSelectedRows();
|
||||||
|
for (int selectedRow : selectedRows) {
|
||||||
|
Address selectedAddress = model.getAddress(selectedRow);
|
||||||
|
AddressTable addrTab = model.get(selectedAddress);
|
||||||
|
if (addrTab != null) {
|
||||||
|
set.addRange(selectedAddress,
|
||||||
|
selectedAddress.add(addrTab.getByteLength() - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ProgramSelection selection = new ProgramSelection(set);
|
||||||
|
if (!set.isEmpty()) {
|
||||||
|
plugin.firePluginEvent(
|
||||||
|
new ProgramSelectionPluginEvent(plugin.getName(), selection, program));
|
||||||
|
}
|
||||||
|
|
||||||
|
return selection;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -140,15 +140,19 @@ public class AutoTableDisassemblerPlugin extends ProgramPlugin implements Domain
|
||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
startDialog();
|
startDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabledForContext(ActionContext context) {
|
||||||
|
return currentProgram != null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
findTableAction.setHelpLocation(
|
findTableAction.setHelpLocation(
|
||||||
new HelpLocation(HelpTopics.SEARCH, findTableAction.getName()));
|
new HelpLocation(HelpTopics.SEARCH, findTableAction.getName()));
|
||||||
findTableAction.setMenuBarData(
|
findTableAction.setMenuBarData(
|
||||||
new MenuData(new String[] { ToolConstants.MENU_SEARCH, "For Address Tables..." }, null,
|
new MenuData(new String[] { ToolConstants.MENU_SEARCH, "For Address Tables..." }, null,
|
||||||
"search for"));
|
"search for"));
|
||||||
|
|
||||||
findTableAction.setDescription(getPluginDescription().getDescription());
|
findTableAction.setDescription(getPluginDescription().getDescription());
|
||||||
enableOnLocation(findTableAction);
|
|
||||||
tool.addAction(findTableAction);
|
tool.addAction(findTableAction);
|
||||||
|
|
||||||
} // end of createActions()
|
} // end of createActions()
|
||||||
|
|
|
@ -190,13 +190,7 @@ public class FunctionWindowPlugin extends ProgramPlugin implements DomainObjectL
|
||||||
|
|
||||||
private void addSelectAction() {
|
private void addSelectAction() {
|
||||||
|
|
||||||
selectAction = new MakeProgramSelectionAction(getName(), provider.getTable()) {
|
selectAction = new MakeProgramSelectionAction(this, provider.getTable());
|
||||||
@Override
|
|
||||||
protected void makeSelection(ActionContext context) {
|
|
||||||
selectFunctions(provider.selectFunctions());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
tool.addLocalAction(provider, selectAction);
|
tool.addLocalAction(provider, selectAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,8 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
||||||
|
|
||||||
setHelpLocation(new HelpLocation(plugin.getName(), getName()));
|
setHelpLocation(new HelpLocation(plugin.getName(), getName()));
|
||||||
memManager = plugin.getMemoryMapManager();
|
memManager = plugin.getMemoryMapManager();
|
||||||
setIcon(ResourceManager.loadImage(MEMORY_IMAGE), true);
|
setIcon(ResourceManager.loadImage(MEMORY_IMAGE));
|
||||||
|
addToToolbar();
|
||||||
mainPanel = buildMainPanel();
|
mainPanel = buildMainPanel();
|
||||||
addToTool();
|
addToTool();
|
||||||
addLocalActions();
|
addLocalActions();
|
||||||
|
|
|
@ -249,12 +249,8 @@ public class LocationReferencesProvider extends ComponentProviderAdapter
|
||||||
homeAction.setToolBarData(new ToolBarData(HOME_ICON));
|
homeAction.setToolBarData(new ToolBarData(HOME_ICON));
|
||||||
updateHomeActionState();
|
updateHomeActionState();
|
||||||
|
|
||||||
selectionAction = new MakeProgramSelectionAction(getName(), referencesPanel.getTable()) {
|
selectionAction =
|
||||||
@Override
|
new MakeProgramSelectionAction(locationReferencesPlugin, referencesPanel.getTable());
|
||||||
protected void makeSelection(ActionContext context) {
|
|
||||||
doMakeSelection();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
highlightAction = new ToggleDockingAction("Highlight Matches", getName()) {
|
highlightAction = new ToggleDockingAction("Highlight Matches", getName()) {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -66,7 +66,8 @@ public class RegisterManagerProvider extends ComponentProviderAdapter {
|
||||||
buildComponent();
|
buildComponent();
|
||||||
|
|
||||||
setHelpLocation(new HelpLocation("RegisterPlugin", "Register_Manager"));
|
setHelpLocation(new HelpLocation("RegisterPlugin", "Register_Manager"));
|
||||||
setIcon(REGISTER_ICON, true);
|
setIcon(REGISTER_ICON);
|
||||||
|
addToToolbar();
|
||||||
setDefaultWindowPosition(WindowPosition.WINDOW);
|
setDefaultWindowPosition(WindowPosition.WINDOW);
|
||||||
|
|
||||||
updateMgr = new SwingUpdateManager(500, () -> update());
|
updateMgr = new SwingUpdateManager(500, () -> update());
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.reloc;
|
package ghidra.app.plugin.core.reloc;
|
||||||
|
|
||||||
import docking.ActionContext;
|
|
||||||
import docking.action.DockingAction;
|
import docking.action.DockingAction;
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.events.*;
|
import ghidra.app.events.*;
|
||||||
|
@ -63,13 +62,7 @@ public class RelocationTablePlugin extends Plugin implements DomainObjectListene
|
||||||
|
|
||||||
private void createActions() {
|
private void createActions() {
|
||||||
|
|
||||||
DockingAction selectAction =
|
DockingAction selectAction = new MakeProgramSelectionAction(this, provider.getTable());
|
||||||
new MakeProgramSelectionAction(getName(), provider.getTable()) {
|
|
||||||
@Override
|
|
||||||
protected void makeSelection(ActionContext context) {
|
|
||||||
doMakeSelection();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
tool.addLocalAction(provider, selectAction);
|
tool.addLocalAction(provider, selectAction);
|
||||||
|
|
||||||
DockingAction navigationAction = new SelectionNavigationAction(this, provider.getTable());
|
DockingAction navigationAction = new SelectionNavigationAction(this, provider.getTable());
|
||||||
|
|
|
@ -23,7 +23,6 @@ import javax.swing.*;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
|
|
||||||
import docking.*;
|
import docking.*;
|
||||||
import docking.action.DockingAction;
|
|
||||||
import docking.help.HelpService;
|
import docking.help.HelpService;
|
||||||
import docking.widgets.label.GLabel;
|
import docking.widgets.label.GLabel;
|
||||||
import docking.widgets.table.GTableFilterPanel;
|
import docking.widgets.table.GTableFilterPanel;
|
||||||
|
@ -62,8 +61,6 @@ public class ScalarSearchProvider extends ComponentProviderAdapter {
|
||||||
private GhidraTable scalarTable;
|
private GhidraTable scalarTable;
|
||||||
private ScalarSearchModel scalarModel;
|
private ScalarSearchModel scalarModel;
|
||||||
|
|
||||||
private DockingAction selectAction;
|
|
||||||
|
|
||||||
private ProgramSelection currentSelection;
|
private ProgramSelection currentSelection;
|
||||||
private Program program;
|
private Program program;
|
||||||
private String primarySubTitle;
|
private String primarySubTitle;
|
||||||
|
@ -258,21 +255,11 @@ public class ScalarSearchProvider extends ComponentProviderAdapter {
|
||||||
|
|
||||||
private void createActions() {
|
private void createActions() {
|
||||||
|
|
||||||
selectAction = new MakeProgramSelectionAction(getName(), getTable()) {
|
tool.addLocalAction(this, new MakeProgramSelectionAction(plugin, scalarTable));
|
||||||
@Override
|
tool.addLocalAction(this, new SelectionNavigationAction(plugin, getTable()));
|
||||||
protected void makeSelection(ActionContext context) {
|
|
||||||
selectDataInProgramFromTable(getSelection());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
tool.addLocalAction(this, selectAction);
|
|
||||||
|
|
||||||
DockingAction selectionAction = new SelectionNavigationAction(plugin, getTable());
|
|
||||||
tool.addLocalAction(this, selectionAction);
|
|
||||||
|
|
||||||
GhidraTable table = threadedTablePanel.getTable();
|
GhidraTable table = threadedTablePanel.getTable();
|
||||||
DockingAction removeItemsAction = new DeleteTableRowAction(table, plugin.getName());
|
tool.addLocalAction(this, new DeleteTableRowAction(table, plugin.getName()));
|
||||||
tool.addLocalAction(this, removeItemsAction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
|
@ -102,7 +102,8 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
||||||
setHelpLocation(new HelpLocation(plugin.getName(), plugin.getName()));
|
setHelpLocation(new HelpLocation(plugin.getName(), plugin.getName()));
|
||||||
setIcon(ResourceManager.loadImage("images/play.png"), true);
|
setIcon(ResourceManager.loadImage("images/play.png"));
|
||||||
|
addToToolbar();
|
||||||
setWindowGroup(WINDOW_GROUP);
|
setWindowGroup(WINDOW_GROUP);
|
||||||
|
|
||||||
build();
|
build();
|
||||||
|
|
|
@ -21,7 +21,9 @@ import ghidra.docking.settings.Settings;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.framework.plugintool.ServiceProvider;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressSet;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.util.ProgramSelection;
|
||||||
import ghidra.program.util.string.FoundString;
|
import ghidra.program.util.string.FoundString;
|
||||||
import ghidra.util.datastruct.Accumulator;
|
import ghidra.util.datastruct.Accumulator;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
|
@ -46,6 +48,20 @@ public class StringTableModel extends AddressBasedTableModel<FoundString> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProgramSelection getProgramSelection(int[] rows) {
|
||||||
|
|
||||||
|
AddressSet addressSet = new AddressSet();
|
||||||
|
for (int row : rows) {
|
||||||
|
FoundString foundString = getRowObject(row);
|
||||||
|
Address addr = foundString.getAddress();
|
||||||
|
if (addr != null) {
|
||||||
|
addressSet.addRange(addr, addr.add(foundString.getLength() - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ProgramSelection(addressSet);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Address getAddress(int row) {
|
public Address getAddress(int row) {
|
||||||
FoundString stringData = getRowObject(row);
|
FoundString stringData = getRowObject(row);
|
||||||
|
|
|
@ -28,7 +28,8 @@ import ghidra.app.services.GoToService;
|
||||||
import ghidra.app.util.HelpTopics;
|
import ghidra.app.util.HelpTopics;
|
||||||
import ghidra.framework.plugintool.PluginInfo;
|
import ghidra.framework.plugintool.PluginInfo;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.framework.plugintool.util.*;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
|
import ghidra.framework.plugintool.util.ToolConstants;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.util.ProgramSelection;
|
import ghidra.program.util.ProgramSelection;
|
||||||
|
@ -99,8 +100,7 @@ public class StringTablePlugin extends ProgramPlugin {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
ArrayList<StringTableProvider> list =
|
ArrayList<StringTableProvider> list = new ArrayList<>(transientProviders);
|
||||||
new ArrayList<>(transientProviders);
|
|
||||||
|
|
||||||
for (StringTableProvider stringTableProvider : list) {
|
for (StringTableProvider stringTableProvider : list) {
|
||||||
stringTableProvider.closeComponent();
|
stringTableProvider.closeComponent();
|
||||||
|
@ -114,8 +114,7 @@ public class StringTablePlugin extends ProgramPlugin {
|
||||||
if (transientProviders.isEmpty()) {
|
if (transientProviders.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ArrayList<StringTableProvider> list =
|
ArrayList<StringTableProvider> list = new ArrayList<>(transientProviders);
|
||||||
new ArrayList<>(transientProviders);
|
|
||||||
for (StringTableProvider stringTableProvider : list) {
|
for (StringTableProvider stringTableProvider : list) {
|
||||||
stringTableProvider.programClosed(program);
|
stringTableProvider.programClosed(program);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,15 +30,12 @@ import docking.widgets.label.GLabel;
|
||||||
import docking.widgets.table.*;
|
import docking.widgets.table.*;
|
||||||
import docking.widgets.table.threaded.ThreadedTableModel;
|
import docking.widgets.table.threaded.ThreadedTableModel;
|
||||||
import docking.widgets.textfield.IntegerTextField;
|
import docking.widgets.textfield.IntegerTextField;
|
||||||
import ghidra.app.events.ProgramSelectionPluginEvent;
|
|
||||||
import ghidra.app.services.GoToService;
|
import ghidra.app.services.GoToService;
|
||||||
import ghidra.app.util.HelpTopics;
|
import ghidra.app.util.HelpTopics;
|
||||||
import ghidra.docking.settings.SettingsImpl;
|
import ghidra.docking.settings.SettingsImpl;
|
||||||
import ghidra.framework.model.DomainObjectChangedEvent;
|
import ghidra.framework.model.DomainObjectChangedEvent;
|
||||||
import ghidra.framework.model.DomainObjectListener;
|
import ghidra.framework.model.DomainObjectListener;
|
||||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||||
import ghidra.program.model.address.Address;
|
|
||||||
import ghidra.program.model.address.AddressSet;
|
|
||||||
import ghidra.program.model.data.StringDataInstance;
|
import ghidra.program.model.data.StringDataInstance;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.DumbMemBufferImpl;
|
import ghidra.program.model.mem.DumbMemBufferImpl;
|
||||||
|
@ -305,10 +302,16 @@ public class StringTableProvider extends ComponentProviderAdapter implements Dom
|
||||||
makeCharArrayAction.setHelpLocation(makeStringHelp);
|
makeCharArrayAction.setHelpLocation(makeStringHelp);
|
||||||
addLocalAction(makeCharArrayAction);
|
addLocalAction(makeCharArrayAction);
|
||||||
|
|
||||||
DockingAction selectAction = new MakeProgramSelectionAction(plugin.getName(), table) {
|
DockingAction selectAction = new MakeProgramSelectionAction(plugin, table) {
|
||||||
@Override
|
@Override
|
||||||
protected void makeSelection(ActionContext context) {
|
protected ProgramSelection makeSelection(ActionContext context) {
|
||||||
doMakeSelection();
|
ProgramSelection selection = super.makeSelection(context);
|
||||||
|
|
||||||
|
// Also make sure this plugin keeps track of the new selection, since it will
|
||||||
|
// not receive this new event.
|
||||||
|
// TODO this should not be necessary; old code perhaps?
|
||||||
|
plugin.setSelection(selection);
|
||||||
|
return selection;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -321,37 +324,6 @@ public class StringTableProvider extends ComponentProviderAdapter implements Dom
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doMakeSelection() {
|
|
||||||
AddressSet set = new AddressSet();
|
|
||||||
|
|
||||||
addToAddressSet(set, table.getSelectedRows());
|
|
||||||
|
|
||||||
if (!set.isEmpty()) {
|
|
||||||
|
|
||||||
ProgramSelection ps = new ProgramSelection(set);
|
|
||||||
|
|
||||||
// This event is given this specific source name because AsciiFinderPlugin
|
|
||||||
// is looking for it, so it can circumvent
|
|
||||||
// some unwanted behavior. See AsciiFinderPlugin.firePluginEvent for details.
|
|
||||||
plugin.firePluginEvent(new ProgramSelectionPluginEvent(
|
|
||||||
"AsciiFinderDialogFiredSelection", ps, currentProgram));
|
|
||||||
|
|
||||||
// Also make sure this plugin keeps track of the new selection, since it will
|
|
||||||
// not receive this new event.
|
|
||||||
plugin.setSelection(ps);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void addToAddressSet(AddressSet modifiableSet, int[] rows) {
|
|
||||||
for (int rowValue : rows) {
|
|
||||||
FoundString foundString = stringModel.getRowObject(rowValue);
|
|
||||||
Address addr = foundString.getAddress();
|
|
||||||
if (addr != null) {
|
|
||||||
modifiableSet.addRange(addr, addr.add(foundString.getLength() - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private JPanel createMainPanel() {
|
private JPanel createMainPanel() {
|
||||||
JPanel panel = new JPanel(new BorderLayout());
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
panel.add(buildTablePanel(), BorderLayout.CENTER);
|
panel.add(buildTablePanel(), BorderLayout.CENTER);
|
||||||
|
|
|
@ -100,15 +100,7 @@ public class ViewStringsPlugin extends ProgramPlugin implements DomainObjectList
|
||||||
refreshAction.setHelpLocation(new HelpLocation("ViewStringsPlugin", "Refresh"));
|
refreshAction.setHelpLocation(new HelpLocation("ViewStringsPlugin", "Refresh"));
|
||||||
tool.addLocalAction(provider, refreshAction);
|
tool.addLocalAction(provider, refreshAction);
|
||||||
|
|
||||||
selectAction = new MakeProgramSelectionAction(getName(), provider.getTable()) {
|
tool.addLocalAction(provider, new MakeProgramSelectionAction(this, provider.getTable()));
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void makeSelection(ActionContext context) {
|
|
||||||
selectData(provider.selectData());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
tool.addLocalAction(provider, selectAction);
|
|
||||||
|
|
||||||
linkNavigationAction = new SelectionNavigationAction(this, provider.getTable());
|
linkNavigationAction = new SelectionNavigationAction(this, provider.getTable());
|
||||||
tool.addLocalAction(provider, linkNavigationAction);
|
tool.addLocalAction(provider, linkNavigationAction);
|
||||||
|
|
|
@ -103,7 +103,8 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
|
||||||
super(tool, NAME, plugin.getName());
|
super(tool, NAME, plugin.getName());
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
||||||
setIcon(ICON, true);
|
setIcon(ICON);
|
||||||
|
addToToolbar();
|
||||||
|
|
||||||
domainObjectListener = new SymbolTreeProviderDomainObjectListener();
|
domainObjectListener = new SymbolTreeProviderDomainObjectListener();
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,8 @@ class ReferenceProvider extends ComponentProviderAdapter {
|
||||||
super(plugin.getTool(), "Symbol References", plugin.getName(), ProgramActionContext.class);
|
super(plugin.getTool(), "Symbol References", plugin.getName(), ProgramActionContext.class);
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
||||||
setIcon(ICON, true);
|
setIcon(ICON);
|
||||||
|
addToToolbar();
|
||||||
setHelpLocation(new HelpLocation(plugin.getName(), "Symbol_References"));
|
setHelpLocation(new HelpLocation(plugin.getName(), "Symbol_References"));
|
||||||
setWindowGroup("symbolTable");
|
setWindowGroup("symbolTable");
|
||||||
setIntraGroupPosition(WindowPosition.RIGHT);
|
setIntraGroupPosition(WindowPosition.RIGHT);
|
||||||
|
|
|
@ -27,14 +27,11 @@ import docking.DockingUtils;
|
||||||
import docking.action.KeyBindingData;
|
import docking.action.KeyBindingData;
|
||||||
import ghidra.app.context.ProgramActionContext;
|
import ghidra.app.context.ProgramActionContext;
|
||||||
import ghidra.app.context.ProgramSymbolActionContext;
|
import ghidra.app.context.ProgramSymbolActionContext;
|
||||||
import ghidra.app.events.ProgramSelectionPluginEvent;
|
|
||||||
import ghidra.app.util.SymbolInspector;
|
import ghidra.app.util.SymbolInspector;
|
||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.SaveState;
|
||||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||||
import ghidra.framework.plugintool.PluginEvent;
|
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.program.util.ProgramSelection;
|
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.table.GhidraTable;
|
import ghidra.util.table.GhidraTable;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
|
@ -52,9 +49,10 @@ class SymbolProvider extends ComponentProviderAdapter {
|
||||||
super(plugin.getTool(), "Symbol Table", plugin.getName(), ProgramActionContext.class);
|
super(plugin.getTool(), "Symbol Table", plugin.getName(), ProgramActionContext.class);
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
||||||
setIcon(ICON, true);
|
setIcon(ICON);
|
||||||
setDefaultKeyBinding(
|
addToToolbar();
|
||||||
new KeyBindingData(KeyEvent.VK_T, DockingUtils.CONTROL_KEY_MODIFIER_MASK));
|
setKeyBinding(new KeyBindingData(KeyEvent.VK_T, DockingUtils.CONTROL_KEY_MODIFIER_MASK));
|
||||||
|
|
||||||
setHelpLocation(new HelpLocation(plugin.getName(), "Symbol_Table"));
|
setHelpLocation(new HelpLocation(plugin.getName(), "Symbol_Table"));
|
||||||
setWindowGroup("symbolTable");
|
setWindowGroup("symbolTable");
|
||||||
renderer = new SymbolRenderer();
|
renderer = new SymbolRenderer();
|
||||||
|
@ -90,13 +88,6 @@ class SymbolProvider extends ComponentProviderAdapter {
|
||||||
symbolKeyModel.delete(rowObjects);
|
symbolKeyModel.delete(rowObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
void makeSelection() {
|
|
||||||
ProgramSelection selection = symbolPanel.getProgramSelection();
|
|
||||||
PluginEvent event =
|
|
||||||
new ProgramSelectionPluginEvent(plugin.getName(), selection, plugin.getProgram());
|
|
||||||
plugin.firePluginEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFilter() {
|
void setFilter() {
|
||||||
symbolPanel.setFilter();
|
symbolPanel.setFilter();
|
||||||
}
|
}
|
||||||
|
|
|
@ -393,13 +393,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
||||||
DockingAction editExternalLocationAction = new EditExternalLocationAction(this);
|
DockingAction editExternalLocationAction = new EditExternalLocationAction(this);
|
||||||
tool.addLocalAction(symProvider, editExternalLocationAction);
|
tool.addLocalAction(symProvider, editExternalLocationAction);
|
||||||
|
|
||||||
makeSelectionAction = new MakeProgramSelectionAction(getName(), symProvider.getTable()) {
|
makeSelectionAction = new MakeProgramSelectionAction(this, symProvider.getTable());
|
||||||
@Override
|
|
||||||
protected void makeSelection(ActionContext context) {
|
|
||||||
symProvider.makeSelection();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
makeSelectionAction.getPopupMenuData().setMenuGroup(popupGroup);
|
makeSelectionAction.getPopupMenuData().setMenuGroup(popupGroup);
|
||||||
|
|
||||||
tool.addLocalAction(symProvider, makeSelectionAction);
|
tool.addLocalAction(symProvider, makeSelectionAction);
|
||||||
|
|
|
@ -159,10 +159,15 @@ public class TableComponentProvider<T> extends ComponentProviderAdapter
|
||||||
private void createActions(final Plugin plugin) {
|
private void createActions(final Plugin plugin) {
|
||||||
|
|
||||||
GhidraTable table = threadedPanel.getTable();
|
GhidraTable table = threadedPanel.getTable();
|
||||||
selectAction = new MakeProgramSelectionAction(tableServicePlugin.getName(), table) {
|
selectAction = new MakeProgramSelectionAction(tableServicePlugin, table) {
|
||||||
@Override
|
@Override
|
||||||
protected void makeSelection(ActionContext context) {
|
protected ProgramSelection makeSelection(ActionContext context) {
|
||||||
doMakeSelection(plugin);
|
|
||||||
|
ProgramSelection selection = table.getProgramSelection();
|
||||||
|
navigatable.goTo(program, new ProgramLocation(program, selection.getMinAddress()));
|
||||||
|
navigatable.setSelection(selection);
|
||||||
|
navigatable.requestFocus();
|
||||||
|
return selection;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
selectAction.setHelpLocation(new HelpLocation(HelpTopics.SEARCH, "Make_Selection"));
|
selectAction.setHelpLocation(new HelpLocation(HelpTopics.SEARCH, "Make_Selection"));
|
||||||
|
@ -265,19 +270,6 @@ public class TableComponentProvider<T> extends ComponentProviderAdapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doMakeSelection(Plugin plugin) {
|
|
||||||
ProgramSelection selection = threadedPanel.getTable().getProgramSelection();
|
|
||||||
Program modelProgram = model.getProgram();
|
|
||||||
if (modelProgram == null || selection.getNumAddresses() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
navigatable.goTo(model.getProgram(),
|
|
||||||
new ProgramLocation(modelProgram, selection.getMinAddress()));
|
|
||||||
navigatable.setSelection(selection);
|
|
||||||
navigatable.requestFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeComponent() {
|
public void closeComponent() {
|
||||||
if (navigatable != null) {
|
if (navigatable != null) {
|
||||||
|
|
|
@ -160,8 +160,15 @@ public class TableChooserDialog extends DialogComponentProvider
|
||||||
|
|
||||||
DockingAction selectAction = new MakeProgramSelectionAction(owner, table) {
|
DockingAction selectAction = new MakeProgramSelectionAction(owner, table) {
|
||||||
@Override
|
@Override
|
||||||
protected void makeSelection(ActionContext context) {
|
protected ProgramSelection makeSelection(ActionContext context) {
|
||||||
doMakeSelection();
|
ProgramSelection selection = table.getProgramSelection();
|
||||||
|
if (navigatable != null) {
|
||||||
|
navigatable.goTo(program,
|
||||||
|
new ProgramLocation(program, selection.getMinAddress()));
|
||||||
|
navigatable.setSelection(selection);
|
||||||
|
navigatable.requestFocus();
|
||||||
|
}
|
||||||
|
return selection;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -173,18 +180,6 @@ public class TableChooserDialog extends DialogComponentProvider
|
||||||
addAction(selectionNavigationAction);
|
addAction(selectionNavigationAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doMakeSelection() {
|
|
||||||
ProgramSelection selection = table.getProgramSelection();
|
|
||||||
if (program == null || program.isClosed() || selection.getNumAddresses() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (navigatable != null) {
|
|
||||||
navigatable.goTo(program, new ProgramLocation(program, selection.getMinAddress()));
|
|
||||||
navigatable.setSelection(selection);
|
|
||||||
navigatable.requestFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void show() {
|
public void show() {
|
||||||
DockingWindowManager manager = DockingWindowManager.getActiveInstance();
|
DockingWindowManager manager = DockingWindowManager.getActiveInstance();
|
||||||
tool.showDialog(this, manager.getMainWindow());
|
tool.showDialog(this, manager.getMainWindow());
|
||||||
|
|
|
@ -191,10 +191,10 @@ public class GhidraTable extends GTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the program selection equivalent
|
* Returns the program selection equivalent to the rows currently selected in the table.
|
||||||
* to the rows currently selected in the table. This method
|
* This method is only valid when the underlying table model implements
|
||||||
* is only valid when the underlying table model implements
|
* {@link ProgramTableModel}.
|
||||||
* <code>ProgramTableModel</code>.
|
* <P>
|
||||||
* Returns null if no rows are selected or
|
* Returns null if no rows are selected or
|
||||||
* the underlying model does not implement <code>ProgramTableModel</code>.
|
* the underlying model does not implement <code>ProgramTableModel</code>.
|
||||||
* @return the program selection or null.
|
* @return the program selection or null.
|
||||||
|
@ -207,6 +207,20 @@ public class GhidraTable extends GTable {
|
||||||
return programTableModel.getProgramSelection(getSelectedRows());
|
return programTableModel.getProgramSelection(getSelectedRows());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the program being used by this table; null if the underlying model does not
|
||||||
|
* implement {@link ProgramTableModel}
|
||||||
|
*
|
||||||
|
* @return the table's program
|
||||||
|
*/
|
||||||
|
public Program getProgram() {
|
||||||
|
ProgramTableModel programTableModel = getProgramTableModel(dataModel);
|
||||||
|
if (programTableModel == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return programTableModel.getProgram();
|
||||||
|
}
|
||||||
|
|
||||||
private ProgramTableModel getProgramTableModel(TableModel model) {
|
private ProgramTableModel getProgramTableModel(TableModel model) {
|
||||||
if (model instanceof ProgramTableModel) {
|
if (model instanceof ProgramTableModel) {
|
||||||
return (ProgramTableModel) model;
|
return (ProgramTableModel) model;
|
||||||
|
|
|
@ -15,26 +15,53 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.util.table.actions;
|
package ghidra.util.table.actions;
|
||||||
|
|
||||||
import javax.swing.JTable;
|
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
|
import ghidra.app.events.ProgramSelectionPluginEvent;
|
||||||
|
import ghidra.framework.plugintool.Plugin;
|
||||||
|
import ghidra.framework.plugintool.PluginEvent;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.util.ProgramSelection;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
import ghidra.util.table.GhidraTable;
|
||||||
import resources.Icons;
|
import resources.Icons;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An action to make a program selection based on the given table's selection. The clients
|
* An action to make a program selection based on the given table's selection. For the context to
|
||||||
* must implement the make selection code, as they know their own data. Also, for the context to
|
|
||||||
* work, the provider using this action must create an {@link ActionContext} that returns a
|
* work, the provider using this action must create an {@link ActionContext} that returns a
|
||||||
* context object that is the table passed to this action's constructor.
|
* context object that is the table passed to this action's constructor; otherwise, this action
|
||||||
|
* will not be enabled correctly.
|
||||||
*/
|
*/
|
||||||
public abstract class MakeProgramSelectionAction extends DockingAction {
|
public class MakeProgramSelectionAction extends DockingAction {
|
||||||
|
|
||||||
private JTable table;
|
private GhidraTable table;
|
||||||
|
|
||||||
public MakeProgramSelectionAction(String owner, JTable table) {
|
// we will have one of these fields be non-null after construction
|
||||||
|
private Plugin plugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special constructor for clients that do not have a plugin. Clients using this
|
||||||
|
* constructor must override {@link #makeSelection(ActionContext)}.
|
||||||
|
*
|
||||||
|
* @param owner the action's owner
|
||||||
|
* @param table the table needed for this action
|
||||||
|
*/
|
||||||
|
public MakeProgramSelectionAction(String owner, GhidraTable table) {
|
||||||
super("Make Selection", owner, KeyBindingType.SHARED);
|
super("Make Selection", owner, KeyBindingType.SHARED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This normal constructor for this action. The given plugin will be used along with the
|
||||||
|
* given table to fire program selection events as the action is executed.
|
||||||
|
*
|
||||||
|
* @param plugin the plugin
|
||||||
|
* @param table the table
|
||||||
|
*/
|
||||||
|
public MakeProgramSelectionAction(Plugin plugin, GhidraTable table) {
|
||||||
|
super("Make Selection", plugin.getName(), KeyBindingType.SHARED);
|
||||||
|
this.plugin = plugin;
|
||||||
this.table = table;
|
this.table = table;
|
||||||
|
|
||||||
setPopupMenuData(
|
setPopupMenuData(
|
||||||
|
@ -45,7 +72,7 @@ public abstract class MakeProgramSelectionAction extends DockingAction {
|
||||||
// this help location provides generic help; clients can override to point to their help
|
// this help location provides generic help; clients can override to point to their help
|
||||||
setHelpLocation(new HelpLocation("Search", "Make_Selection"));
|
setHelpLocation(new HelpLocation("Search", "Make_Selection"));
|
||||||
|
|
||||||
// null for now, but we may want a default binding in the future
|
// null for now, but we may want a default binding in the future
|
||||||
initKeyStroke(null);
|
initKeyStroke(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +97,15 @@ public abstract class MakeProgramSelectionAction extends DockingAction {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Program program = table.getProgram();
|
||||||
|
if (program == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (program.isClosed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int n = table.getSelectedRowCount();
|
int n = table.getSelectedRowCount();
|
||||||
return n > 0;
|
return n > 0;
|
||||||
}
|
}
|
||||||
|
@ -79,5 +115,17 @@ public abstract class MakeProgramSelectionAction extends DockingAction {
|
||||||
makeSelection(context);
|
makeSelection(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void makeSelection(ActionContext context);
|
protected ProgramSelection makeSelection(ActionContext context) {
|
||||||
|
ProgramSelection selection = table.getProgramSelection();
|
||||||
|
|
||||||
|
if (plugin == null) {
|
||||||
|
throw new IllegalStateException("The Make Program Selection action cannot be used " +
|
||||||
|
"without a plugin unless the client overrides this method");
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginEvent event =
|
||||||
|
new ProgramSelectionPluginEvent(plugin.getName(), selection, table.getProgram());
|
||||||
|
plugin.firePluginEvent(event);
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,7 @@ import javax.swing.*;
|
||||||
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.*;
|
||||||
import docking.action.KeyBindingData;
|
|
||||||
import docking.actions.KeyEntryDialog;
|
import docking.actions.KeyEntryDialog;
|
||||||
import docking.actions.ToolActions;
|
import docking.actions.ToolActions;
|
||||||
import docking.tool.util.DockingToolConstants;
|
import docking.tool.util.DockingToolConstants;
|
||||||
|
@ -54,7 +53,9 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
env = new TestEnv();
|
env = new TestEnv();
|
||||||
tool = env.launchDefaultTool();
|
tool = env.showTool();
|
||||||
|
|
||||||
|
//tool = env.launchDefaultTool();
|
||||||
provider = new TestActionsComponentProvider(tool);
|
provider = new TestActionsComponentProvider(tool);
|
||||||
|
|
||||||
Msg.setErrorLogger(spyLogger);
|
Msg.setErrorLogger(spyLogger);
|
||||||
|
@ -243,23 +244,72 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetIcon_NullIconWithToolbarAction() {
|
public void testDefaultKeyBindingAppearsInWindowMenu() {
|
||||||
|
|
||||||
|
setDefaultKeyBinding(CONTROL_T);
|
||||||
|
showProvider();
|
||||||
|
assertWindowMenuActionHasKeyBinding(CONTROL_T);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddToToolbar_WithoutIcon() {
|
||||||
|
|
||||||
|
runSwing(() -> provider.addToToolbar());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setToolbarIcon(null);
|
setErrorsExpected(true);
|
||||||
|
runSwingWithExceptions(this::showProvider, true);
|
||||||
|
setErrorsExpected(false);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch (Throwable t) {
|
||||||
|
// good
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetIcon_NullIconWithToolbarAction() {
|
||||||
|
|
||||||
|
setIcon(ICON);
|
||||||
|
runSwing(() -> provider.addToToolbar());
|
||||||
|
showProvider();
|
||||||
|
|
||||||
|
try {
|
||||||
|
setErrorsExpected(true);
|
||||||
|
runSwingWithExceptions(() -> provider.setIcon(null), true);
|
||||||
|
setErrorsExpected(false);
|
||||||
fail("Expected an exception passing a null icon when specifying a toolbar action");
|
fail("Expected an exception passing a null icon when specifying a toolbar action");
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Throwable t) {
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDefaultKeyBindingAppearsInWindowMenu() {
|
public void testSetIcon_WithToolbarAction() {
|
||||||
|
setToolbarIcon(ICON);
|
||||||
provider.setDefaultKeyBinding(new KeyBindingData(CONTROL_T));
|
|
||||||
showProvider();
|
showProvider();
|
||||||
assertWindowMenuActionHasKeyBinding(CONTROL_T);
|
|
||||||
|
assertWindowMenuActionHasIcon(ICON);
|
||||||
|
assertToolbarActionHasIcon(ICON);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetIcon_WithToolbarAction_AfterActionHasBeenAddedToToolbar() {
|
||||||
|
|
||||||
|
//
|
||||||
|
// We currently do not prevent providers from changing their icons. Make sure we respond
|
||||||
|
// to changes correctly.
|
||||||
|
//
|
||||||
|
|
||||||
|
setToolbarIcon(ICON);
|
||||||
|
showProvider();
|
||||||
|
|
||||||
|
Icon newIcon = Icons.COLLAPSE_ALL_ICON;
|
||||||
|
setIcon(newIcon);
|
||||||
|
|
||||||
|
assertWindowMenuActionHasIcon(newIcon);
|
||||||
|
assertToolbarActionHasIcon(newIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
@ -277,7 +327,7 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDefaultKeyBinding(KeyStroke defaultKs) {
|
private void setDefaultKeyBinding(KeyStroke defaultKs) {
|
||||||
runSwing(() -> provider.setDefaultKeyBinding(new KeyBindingData(defaultKs)));
|
runSwing(() -> provider.setKeyBinding(new KeyBindingData(defaultKs)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setIcon(Icon icon) {
|
private void setIcon(Icon icon) {
|
||||||
|
@ -285,7 +335,10 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setToolbarIcon(Icon icon) {
|
private void setToolbarIcon(Icon icon) {
|
||||||
runSwing(() -> provider.setIcon(icon, true));
|
runSwing(() -> {
|
||||||
|
provider.setIcon(icon);
|
||||||
|
provider.addToToolbar();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private DockingActionIf getShowProviderAction() {
|
private DockingActionIf getShowProviderAction() {
|
||||||
|
@ -368,6 +421,13 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
expected, action.getMenuBarData().getMenuIcon());
|
expected, action.getMenuBarData().getMenuIcon());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertToolbarActionHasIcon(Icon expected) {
|
||||||
|
DockingActionIf action = getToolbarShowProviderAction();
|
||||||
|
assertNotNull("No toolbar action found; it should be there", action);
|
||||||
|
ToolBarData tbData = action.getToolBarData();
|
||||||
|
assertEquals(expected, tbData.getIcon());
|
||||||
|
}
|
||||||
|
|
||||||
private void assertWindowMenuActionHasKeyBinding(KeyStroke ks) {
|
private void assertWindowMenuActionHasKeyBinding(KeyStroke ks) {
|
||||||
DockingActionIf action = getWindowMenuShowProviderAction();
|
DockingActionIf action = getWindowMenuShowProviderAction();
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@ -476,7 +536,7 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
|
||||||
super(tool, HasDefaultKeyBindingComponentProvider.class.getSimpleName(),
|
super(tool, HasDefaultKeyBindingComponentProvider.class.getSimpleName(),
|
||||||
"Fooberry Plugin");
|
"Fooberry Plugin");
|
||||||
|
|
||||||
setDefaultKeyBinding(new KeyBindingData(CONTROL_T));
|
setKeyBinding(new KeyBindingData(CONTROL_T));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -256,35 +256,6 @@ public class MultiTabPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertEquals(0, panel.getHiddenCount());
|
assertEquals(0, panel.getHiddenCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printResizeDebug() {
|
|
||||||
//
|
|
||||||
// To show the '>>' label, the number of tabs must exceed the room visible to show them
|
|
||||||
//
|
|
||||||
|
|
||||||
// frame size
|
|
||||||
|
|
||||||
// available width
|
|
||||||
int panelWidth = panel.getWidth();
|
|
||||||
System.out.println("available width: " + panelWidth);
|
|
||||||
|
|
||||||
// size label
|
|
||||||
int totalWidth = 0;
|
|
||||||
JComponent listLabel = (JComponent) getInstanceField("showHiddenListLabel", panel);
|
|
||||||
System.out.println("label width: " + listLabel.getWidth());
|
|
||||||
totalWidth = listLabel.getWidth();
|
|
||||||
|
|
||||||
// size of each tab's panel
|
|
||||||
Map<?, ?> map = (Map<?, ?>) getInstanceField("linkedProgramMap", panel);
|
|
||||||
Collection<?> values = map.values();
|
|
||||||
for (Object object : values) {
|
|
||||||
JComponent c = (JComponent) object;
|
|
||||||
totalWidth += c.getWidth();
|
|
||||||
System.out.println("\t" + c.getWidth());
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("Total width: " + totalWidth + " out of " + panelWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTabUpdatesOnProgramChange() throws Exception {
|
public void testTabUpdatesOnProgramChange() throws Exception {
|
||||||
ProgramBuilder builder = new ProgramBuilder("notepad", ProgramBuilder._TOY);
|
ProgramBuilder builder = new ProgramBuilder("notepad", ProgramBuilder._TOY);
|
||||||
|
@ -315,11 +286,11 @@ public class MultiTabPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
setFrameSize(400, 500);
|
setFrameSize(400, 500);
|
||||||
programNames = new String[] { "notepad", "login", "tms", "taskman", "TestGhidraSearches" };
|
programNames = new String[] { "notepad", "login", "tms", "taskman", "TestGhidraSearches" };
|
||||||
openPrograms(programNames);
|
openPrograms(programNames);
|
||||||
assertTrue(panel.isHidden(programs[1]));
|
assertHidden(programs[1]);
|
||||||
|
|
||||||
runSwing(() -> panel.setSelectedProgram(programs[1]));
|
runSwing(() -> panel.setSelectedProgram(programs[1]));
|
||||||
assertEquals(programs[1], panel.getSelectedProgram());
|
assertEquals(programs[1], panel.getSelectedProgram());
|
||||||
assertTrue(!panel.isHidden(programs[1]));
|
assertShowing(programs[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -384,10 +355,6 @@ public class MultiTabPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertEquals(BigInteger.valueOf(4), fp.getCursorLocation().getIndex());
|
assertEquals(BigInteger.valueOf(4), fp.getCursorLocation().getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Color getFieldPanelBackgroundColor(FieldPanel fp, BigInteger index) {
|
|
||||||
return runSwing(() -> fp.getBackgroundColor(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTabUpdate() throws Exception {
|
public void testTabUpdate() throws Exception {
|
||||||
Program p = openDummyProgram("login", true);
|
Program p = openDummyProgram("login", true);
|
||||||
|
@ -449,8 +416,8 @@ public class MultiTabPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
// by trial-and-error, we know that 'tms' is the last visible program tab
|
// by trial-and-error, we know that 'tms' is the last visible program tab
|
||||||
// after resizing
|
// after resizing
|
||||||
setFrameSize(500, 500);
|
setFrameSize(500, 500);
|
||||||
assertTrue(!panel.isHidden(programs[2]));
|
assertShowing(programs[2]);
|
||||||
assertTrue(panel.isHidden(programs[3]));
|
assertHidden(programs[3]);
|
||||||
|
|
||||||
// select the last visible tab
|
// select the last visible tab
|
||||||
selectTab(programs[2]);
|
selectTab(programs[2]);
|
||||||
|
@ -485,8 +452,8 @@ public class MultiTabPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
// by trial-and-error, we know that 'tms' is the last visible program tab
|
// by trial-and-error, we know that 'tms' is the last visible program tab
|
||||||
// after resizing
|
// after resizing
|
||||||
setFrameSize(500, 500);
|
setFrameSize(500, 500);
|
||||||
assertTrue(!panel.isHidden(programs[2]));
|
assertShowing(programs[2]);
|
||||||
assertTrue(panel.isHidden(programs[3]));
|
assertHidden(programs[3]);
|
||||||
|
|
||||||
// select 'tms', which is the last tab before the list is shown
|
// select 'tms', which is the last tab before the list is shown
|
||||||
selectTab(programs[2]);
|
selectTab(programs[2]);
|
||||||
|
@ -521,6 +488,43 @@ public class MultiTabPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertEquals(selectedProgram, p);
|
assertEquals(selectedProgram, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void printResizeDebug() {
|
||||||
|
//
|
||||||
|
// To show the '>>' label, the number of tabs must exceed the room visible to show them
|
||||||
|
//
|
||||||
|
|
||||||
|
// frame size
|
||||||
|
|
||||||
|
// available width
|
||||||
|
int panelWidth = panel.getWidth();
|
||||||
|
System.out.println("available width: " + panelWidth);
|
||||||
|
|
||||||
|
// size label
|
||||||
|
int totalWidth = 0;
|
||||||
|
JComponent listLabel = (JComponent) getInstanceField("showHiddenListLabel", panel);
|
||||||
|
System.out.println("label width: " + listLabel.getWidth());
|
||||||
|
totalWidth = listLabel.getWidth();
|
||||||
|
|
||||||
|
// size of each tab's panel
|
||||||
|
Map<?, ?> map = (Map<?, ?>) getInstanceField("linkedProgramMap", panel);
|
||||||
|
Collection<?> values = map.values();
|
||||||
|
for (Object object : values) {
|
||||||
|
JComponent c = (JComponent) object;
|
||||||
|
totalWidth += c.getWidth();
|
||||||
|
System.out.println("\t" + c.getWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Total width: " + totalWidth + " out of " + panelWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertShowing(Program p) {
|
||||||
|
assertFalse(runSwing(() -> panel.isHidden(p)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertHidden(Program p) {
|
||||||
|
assertTrue(runSwing(() -> panel.isHidden(p)));
|
||||||
|
}
|
||||||
|
|
||||||
private void assertListWindowHidden() {
|
private void assertListWindowHidden() {
|
||||||
Window listWindow = getListWindow();
|
Window listWindow = getListWindow();
|
||||||
assertFalse(listWindow.isShowing());
|
assertFalse(listWindow.isShowing());
|
||||||
|
@ -544,6 +548,10 @@ public class MultiTabPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
return windowForComponent(listPanel);
|
return windowForComponent(listPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Color getFieldPanelBackgroundColor(FieldPanel fp, BigInteger index) {
|
||||||
|
return runSwing(() -> fp.getBackgroundColor(index));
|
||||||
|
}
|
||||||
|
|
||||||
private void performPreviousAction() throws Exception {
|
private void performPreviousAction() throws Exception {
|
||||||
MultiTabPlugin plugin = env.getPlugin(MultiTabPlugin.class);
|
MultiTabPlugin plugin = env.getPlugin(MultiTabPlugin.class);
|
||||||
DockingAction goToPreviousProgramAction =
|
DockingAction goToPreviousProgramAction =
|
||||||
|
|
|
@ -72,11 +72,13 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
|
||||||
super(tool, plugin, "Bytes", ByteViewerActionContext.class);
|
super(tool, plugin, "Bytes", ByteViewerActionContext.class);
|
||||||
|
|
||||||
this.isConnected = isConnected;
|
this.isConnected = isConnected;
|
||||||
|
setIcon(ResourceManager.loadImage("images/binaryData.gif"));
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
setTransient();
|
setTransient();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
setIcon(ResourceManager.loadImage("images/binaryData.gif"), isConnected);
|
addToToolbar();
|
||||||
|
}
|
||||||
|
|
||||||
decorationComponent = new DecoratorPanel(panel, isConnected);
|
decorationComponent = new DecoratorPanel(panel, isConnected);
|
||||||
clipboardProvider = new ByteViewerClipboardProvider(this, tool);
|
clipboardProvider = new ByteViewerClipboardProvider(this, tool);
|
||||||
|
|
|
@ -142,11 +142,12 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
|
||||||
setTransient();
|
setTransient();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setDefaultKeyBinding(
|
addToToolbar();
|
||||||
|
setKeyBinding(
|
||||||
new KeyBindingData(KeyEvent.VK_E, DockingUtils.CONTROL_KEY_MODIFIER_MASK));
|
new KeyBindingData(KeyEvent.VK_E, DockingUtils.CONTROL_KEY_MODIFIER_MASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
setIcon(C_SOURCE_ICON, isConnected);
|
setIcon(C_SOURCE_ICON);
|
||||||
setTitle("Decompile");
|
setTitle("Decompile");
|
||||||
|
|
||||||
setWindowMenuGroup("Decompile");
|
setWindowMenuGroup("Decompile");
|
||||||
|
|
|
@ -103,16 +103,19 @@ public class FGProvider extends VisualGraphComponentProvider<FGVertex, FGEdge, F
|
||||||
controller = new FGController(this, plugin);
|
controller = new FGController(this, plugin);
|
||||||
|
|
||||||
setConnected(isConnected);
|
setConnected(isConnected);
|
||||||
|
setIcon(FunctionGraphPlugin.ICON);
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
setTransient();
|
setTransient();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
addToToolbar();
|
||||||
|
}
|
||||||
|
|
||||||
decorationPanel = new DecoratorPanel(controller.getViewComponent(), isConnected);
|
decorationPanel = new DecoratorPanel(controller.getViewComponent(), isConnected);
|
||||||
setWindowMenuGroup(FunctionGraphPlugin.FUNCTION_GRAPH_NAME);
|
setWindowMenuGroup(FunctionGraphPlugin.FUNCTION_GRAPH_NAME);
|
||||||
setWindowGroup(FunctionGraphPlugin.FUNCTION_GRAPH_NAME);
|
setWindowGroup(FunctionGraphPlugin.FUNCTION_GRAPH_NAME);
|
||||||
setDefaultWindowPosition(WindowPosition.WINDOW);
|
setDefaultWindowPosition(WindowPosition.WINDOW);
|
||||||
|
|
||||||
setIcon(FunctionGraphPlugin.ICON, isConnected);
|
|
||||||
setHelpLocation(new HelpLocation("FunctionGraphPlugin", "FunctionGraphPlugin"));
|
setHelpLocation(new HelpLocation("FunctionGraphPlugin", "FunctionGraphPlugin"));
|
||||||
|
|
||||||
addToTool();
|
addToTool();
|
||||||
|
|
|
@ -2011,7 +2011,7 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FGData triggerPersistence(String functionAddress) {
|
protected FGData triggerPersistenceAndReload(String functionAddress) {
|
||||||
//
|
//
|
||||||
// Ideally, we would like to save, close and re-open the program so that we can get
|
// Ideally, we would like to save, close and re-open the program so that we can get
|
||||||
// a round-trip saving and reloading. However, in the test environment, we cannot save
|
// a round-trip saving and reloading. However, in the test environment, we cannot save
|
||||||
|
@ -2019,8 +2019,9 @@ public abstract class AbstractFunctionGraphTest extends AbstractGhidraHeadedInte
|
||||||
// the cache (to make sure that we read the settings again), and then verify that the
|
// the cache (to make sure that we read the settings again), and then verify that the
|
||||||
// data saved in the program has been used to re-group.
|
// data saved in the program has been used to re-group.
|
||||||
//
|
//
|
||||||
graphFunction("0100415a");
|
String otherAddress = "0100415a";
|
||||||
clearCache();
|
assertNotEquals(functionAddress, otherAddress);
|
||||||
|
graphFunction(otherAddress);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Graph the original function and make sure that the previously grouped nodes is again
|
// Graph the original function and make sure that the previously grouped nodes is again
|
||||||
|
|
|
@ -90,7 +90,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
||||||
Address minAddress = addresses.getMinAddress();
|
Address minAddress = addresses.getMinAddress();
|
||||||
Address maxAddress = addresses.getMaxAddress();
|
Address maxAddress = addresses.getMaxAddress();
|
||||||
|
|
||||||
// Recored the edges for later validate. Note: we have to keep the string form, as the
|
// Record the edges for later validation. Note: we have to keep the string form, as the
|
||||||
// toString() on the edges will call back to its vertices, which will later have been
|
// toString() on the edges will call back to its vertices, which will later have been
|
||||||
// disposed.
|
// disposed.
|
||||||
Collection<FGEdge> oringalGroupedEdges = new HashSet<>(graph.getEdges());// copy so they don't get cleared
|
Collection<FGEdge> oringalGroupedEdges = new HashSet<>(graph.getEdges());// copy so they don't get cleared
|
||||||
|
@ -99,7 +99,9 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
||||||
originalEdgeStrings.add(edge.toString());
|
originalEdgeStrings.add(edge.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
graphData = triggerPersistence("01002cf5");
|
// debug
|
||||||
|
capture(getPrimaryGraphViewer(), "graph.grouping.before.reload");
|
||||||
|
graphData = triggerPersistenceAndReload("01002cf5");
|
||||||
|
|
||||||
waitForAnimation();// the re-grouping may be using animation, which runs after the graph is loaded
|
waitForAnimation();// the re-grouping may be using animation, which runs after the graph is loaded
|
||||||
functionGraph = graphData.getFunctionGraph();
|
functionGraph = graphData.getFunctionGraph();
|
||||||
|
@ -113,6 +115,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
||||||
// TODO debug - this has failed; suspected timing issue
|
// TODO debug - this has failed; suspected timing issue
|
||||||
waitForCondition(() -> pointsAreSimilar(location, newLocation));
|
waitForCondition(() -> pointsAreSimilar(location, newLocation));
|
||||||
|
|
||||||
|
capture(getPrimaryGraphViewer(), "graph.grouping.after.reload");
|
||||||
assertTrue(
|
assertTrue(
|
||||||
"Vertex location not restored to default after performing a relayout " +
|
"Vertex location not restored to default after performing a relayout " +
|
||||||
"original point: " + location + " - reloaded point: " + newLocation,
|
"original point: " + location + " - reloaded point: " + newLocation,
|
||||||
|
@ -292,7 +295,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
||||||
Address secondMinAddress = outerAddresses.getMinAddress();
|
Address secondMinAddress = outerAddresses.getMinAddress();
|
||||||
Address secondMaxAddress = outerAddresses.getMaxAddress();
|
Address secondMaxAddress = outerAddresses.getMaxAddress();
|
||||||
|
|
||||||
graphData = triggerPersistence("01002cf5");
|
graphData = triggerPersistenceAndReload("01002cf5");
|
||||||
|
|
||||||
waitForAnimation();// the re-grouping may be using animation, which runs after the graph is loaded
|
waitForAnimation();// the re-grouping may be using animation, which runs after the graph is loaded
|
||||||
functionGraph = graphData.getFunctionGraph();
|
functionGraph = graphData.getFunctionGraph();
|
||||||
|
@ -410,7 +413,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
||||||
Address minAddress = addresses.getMinAddress();
|
Address minAddress = addresses.getMinAddress();
|
||||||
Address maxAddress = addresses.getMaxAddress();
|
Address maxAddress = addresses.getMaxAddress();
|
||||||
|
|
||||||
graphData = triggerPersistence("01002cf5");
|
graphData = triggerPersistenceAndReload("01002cf5");
|
||||||
|
|
||||||
waitForAnimation();// the re-grouping may be using animation, which runs after the graph is loaded
|
waitForAnimation();// the re-grouping may be using animation, which runs after the graph is loaded
|
||||||
functionGraph = graphData.getFunctionGraph();
|
functionGraph = graphData.getFunctionGraph();
|
||||||
|
@ -665,7 +668,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
||||||
// Trigger persistence
|
// Trigger persistence
|
||||||
//
|
//
|
||||||
Address groupAddress = group.getVertexAddress();
|
Address groupAddress = group.getVertexAddress();
|
||||||
FGData graphData = triggerPersistence("01002cf5");
|
FGData graphData = triggerPersistenceAndReload("01002cf5");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Retrieve the group and make sure its color is restored
|
// Retrieve the group and make sure its color is restored
|
||||||
|
@ -702,7 +705,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
||||||
// Trigger persistence
|
// Trigger persistence
|
||||||
//
|
//
|
||||||
Address groupAddress = group.getVertexAddress();
|
Address groupAddress = group.getVertexAddress();
|
||||||
FGData graphData = triggerPersistence("01002cf5");
|
FGData graphData = triggerPersistenceAndReload("01002cf5");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Retrieve the group and make sure its color is restored
|
// Retrieve the group and make sure its color is restored
|
||||||
|
@ -745,7 +748,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
||||||
// Trigger persistence
|
// Trigger persistence
|
||||||
//
|
//
|
||||||
Address groupAddress = group.getVertexAddress();
|
Address groupAddress = group.getVertexAddress();
|
||||||
FGData graphData = triggerPersistence("01002cf5");
|
FGData graphData = triggerPersistenceAndReload("01002cf5");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Retrieve the group and make sure its color is restored
|
// Retrieve the group and make sure its color is restored
|
||||||
|
|
|
@ -122,7 +122,7 @@ public class FunctionGraphGroupVertices3Test extends AbstractFunctionGraphTest {
|
||||||
uncollapse(groupA);
|
uncollapse(groupA);
|
||||||
assertUncollapsed(v1, v2);
|
assertUncollapsed(v1, v2);
|
||||||
|
|
||||||
triggerPersistence(functionAddress);
|
triggerPersistenceAndReload(functionAddress);
|
||||||
waitForBusyGraph();// the re-grouping may be using animation, which runs after the graph is loaded
|
waitForBusyGraph();// the re-grouping may be using animation, which runs after the graph is loaded
|
||||||
|
|
||||||
v1 = vertex(a1);
|
v1 = vertex(a1);
|
||||||
|
@ -161,7 +161,7 @@ public class FunctionGraphGroupVertices3Test extends AbstractFunctionGraphTest {
|
||||||
|
|
||||||
assertUncollapsed(v1, v2);// sanity check--still uncollapsed
|
assertUncollapsed(v1, v2);// sanity check--still uncollapsed
|
||||||
|
|
||||||
triggerPersistence(functionAddress);
|
triggerPersistenceAndReload(functionAddress);
|
||||||
waitForBusyGraph();// the re-grouping may be using animation, which runs after the graph is loaded
|
waitForBusyGraph();// the re-grouping may be using animation, which runs after the graph is loaded
|
||||||
|
|
||||||
v1 = vertex(a1);
|
v1 = vertex(a1);
|
||||||
|
@ -195,7 +195,7 @@ public class FunctionGraphGroupVertices3Test extends AbstractFunctionGraphTest {
|
||||||
uncollapse(outerGroup);
|
uncollapse(outerGroup);
|
||||||
assertUncollapsed(innerGroup, v3, v4);
|
assertUncollapsed(innerGroup, v3, v4);
|
||||||
|
|
||||||
triggerPersistence(functionAddress);
|
triggerPersistenceAndReload(functionAddress);
|
||||||
waitForBusyGraph();// the re-grouping may be using animation, which runs after the graph is loaded
|
waitForBusyGraph();// the re-grouping may be using animation, which runs after the graph is loaded
|
||||||
|
|
||||||
v1 = vertex(a1);
|
v1 = vertex(a1);
|
||||||
|
|
|
@ -96,7 +96,7 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
|
||||||
private Set<DockingActionIf> actionSet = new LinkedHashSet<>();
|
private Set<DockingActionIf> actionSet = new LinkedHashSet<>();
|
||||||
|
|
||||||
/** True if this provider's action should appear in the toolbar */
|
/** True if this provider's action should appear in the toolbar */
|
||||||
private boolean isToolbarAction;
|
private boolean addToolbarAction;
|
||||||
private boolean isTransient;
|
private boolean isTransient;
|
||||||
private KeyBindingData defaultKeyBindingData;
|
private KeyBindingData defaultKeyBindingData;
|
||||||
private Icon icon;
|
private Icon icon;
|
||||||
|
@ -159,6 +159,12 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addToolbarAction) {
|
||||||
|
Objects.requireNonNull(icon,
|
||||||
|
"The provider's icon cannot be null when requesting the provider's action " +
|
||||||
|
"appear in the toolbar");
|
||||||
|
}
|
||||||
|
|
||||||
boolean supportsKeyBindings = !isTransient;
|
boolean supportsKeyBindings = !isTransient;
|
||||||
showProviderAction = new ShowProviderAction(supportsKeyBindings);
|
showProviderAction = new ShowProviderAction(supportsKeyBindings);
|
||||||
}
|
}
|
||||||
|
@ -498,10 +504,12 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the default key binding that will show this provider when pressed
|
* Sets the default key binding that will show this provider when pressed. This value can
|
||||||
|
* be changed by the user and saved as part of the Tool options.
|
||||||
|
*
|
||||||
* @param kbData the key binding
|
* @param kbData the key binding
|
||||||
*/
|
*/
|
||||||
public void setDefaultKeyBinding(KeyBindingData kbData) {
|
protected void setKeyBinding(KeyBindingData kbData) {
|
||||||
|
|
||||||
if (isInTool()) {
|
if (isInTool()) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
|
@ -510,7 +518,7 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
|
||||||
|
|
||||||
this.defaultKeyBindingData = kbData;
|
this.defaultKeyBindingData = kbData;
|
||||||
|
|
||||||
if (isTransient) {
|
if (isTransient && kbData != null) {
|
||||||
Msg.error(this, TRANSIENT_PROVIDER_KEY_BINDING_WARNING_MESSAGE,
|
Msg.error(this, TRANSIENT_PROVIDER_KEY_BINDING_WARNING_MESSAGE,
|
||||||
ReflectionUtilities.createJavaFilteredThrowable());
|
ReflectionUtilities.createJavaFilteredThrowable());
|
||||||
this.defaultKeyBindingData = null;
|
this.defaultKeyBindingData = null;
|
||||||
|
@ -518,37 +526,34 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method for setting the provider's icon.
|
* Convenience method for setting the provider's icon
|
||||||
* @param icon the icon to use for this provider.
|
* @param icon the icon to use for this provider
|
||||||
*/
|
*/
|
||||||
public void setIcon(Icon icon) {
|
protected void setIcon(Icon icon) {
|
||||||
setIcon(icon, false);
|
this.icon = icon;
|
||||||
|
if (!isInTool()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addToolbarAction && showProviderAction != null) {
|
||||||
|
Objects.requireNonNull(icon, "Icon cannot be set to null when using a toolbar action");
|
||||||
|
showProviderAction.setToolBarData(new ToolBarData(icon));
|
||||||
|
}
|
||||||
|
|
||||||
|
dockingTool.getWindowManager().setIcon(this, icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method for setting the provider's icon
|
* Signals that this provider's action for showing the provider should appear in the main
|
||||||
*
|
* toolbar
|
||||||
* @param icon the icon to use for this provider
|
|
||||||
* @param isToolbarAction true will cause this action to get added to the toolbar; if this
|
|
||||||
* value is true, then the icon cannot be null
|
|
||||||
*/
|
*/
|
||||||
public void setIcon(Icon icon, boolean isToolbarAction) {
|
protected void addToToolbar() {
|
||||||
this.icon = icon;
|
this.addToolbarAction = true;
|
||||||
this.isToolbarAction = isToolbarAction;
|
|
||||||
|
|
||||||
if (isToolbarAction) {
|
if (isTransient) {
|
||||||
Objects.requireNonNull(icon,
|
Msg.error(this, TRANSIENT_PROVIDER_TOOLBAR_WARNING_MESSAGE,
|
||||||
"Icon cannot be null when requesting the provider's action appear in the toolbar");
|
ReflectionUtilities.createJavaFilteredThrowable());
|
||||||
|
addToolbarAction = false;
|
||||||
if (isTransient) {
|
|
||||||
Msg.error(this, TRANSIENT_PROVIDER_TOOLBAR_WARNING_MESSAGE,
|
|
||||||
ReflectionUtilities.createJavaFilteredThrowable());
|
|
||||||
isToolbarAction = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isInTool()) {
|
|
||||||
dockingTool.getWindowManager().setIcon(this, icon);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,8 +600,8 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
|
||||||
}
|
}
|
||||||
|
|
||||||
// avoid visually disturbing the user by adding/removing toolbar actions for temp providers
|
// avoid visually disturbing the user by adding/removing toolbar actions for temp providers
|
||||||
if (isToolbarAction) {
|
if (addToolbarAction) {
|
||||||
isToolbarAction = false;
|
addToolbarAction = false;
|
||||||
Msg.error(this, TRANSIENT_PROVIDER_TOOLBAR_WARNING_MESSAGE,
|
Msg.error(this, TRANSIENT_PROVIDER_TOOLBAR_WARNING_MESSAGE,
|
||||||
ReflectionUtilities.createJavaFilteredThrowable());
|
ReflectionUtilities.createJavaFilteredThrowable());
|
||||||
}
|
}
|
||||||
|
@ -776,7 +781,7 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
|
||||||
super(name, owner,
|
super(name, owner,
|
||||||
supportsKeyBindings ? KeyBindingType.SHARED : KeyBindingType.UNSUPPORTED);
|
supportsKeyBindings ? KeyBindingType.SHARED : KeyBindingType.UNSUPPORTED);
|
||||||
|
|
||||||
if (isToolbarAction) {
|
if (addToolbarAction) {
|
||||||
setToolBarData(new ToolBarData(icon, TOOLBAR_GROUP));
|
setToolBarData(new ToolBarData(icon, TOOLBAR_GROUP));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1092,6 +1092,26 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
||||||
runSwing(runnable, true);
|
runSwing(runnable, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this version of {@link #runSwing(Runnable)} when you expect your runnable to throw
|
||||||
|
* an exception
|
||||||
|
* @param runnable the runnable
|
||||||
|
* @param wait true signals to wait for the Swing operation to finish
|
||||||
|
* @throws Throwable any excption that is thrown on the Swing thread
|
||||||
|
*/
|
||||||
|
public static void runSwingWithExceptions(Runnable runnable, boolean wait) throws Throwable {
|
||||||
|
|
||||||
|
if (Swing.isSwingThread()) {
|
||||||
|
throw new AssertException("Unexpectedly called from the Swing thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
ExceptionHandlingRunner exceptionHandlingRunner = new ExceptionHandlingRunner(runnable);
|
||||||
|
Throwable throwable = exceptionHandlingRunner.getException();
|
||||||
|
if (throwable != null) {
|
||||||
|
throw throwable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void runSwing(Runnable runnable, boolean wait) {
|
public static void runSwing(Runnable runnable, boolean wait) {
|
||||||
if (SwingUtilities.isEventDispatchThread()) {
|
if (SwingUtilities.isEventDispatchThread()) {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
|
@ -1115,7 +1135,6 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
||||||
};
|
};
|
||||||
|
|
||||||
SwingUtilities.invokeLater(swingExceptionCatcher);
|
SwingUtilities.invokeLater(swingExceptionCatcher);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class ExceptionHandlingRunner {
|
protected static class ExceptionHandlingRunner {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue