GP-4275 Set accessible names of focusable components in component providers

This commit is contained in:
ghidragon 2024-03-12 12:27:12 -04:00
parent 317a881488
commit 5bca2c75c7
62 changed files with 565 additions and 202 deletions

View file

@ -954,6 +954,10 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
breakpointPanel.add(breakpointFilterPanel, BorderLayout.SOUTH);
mainPanel.setLeftComponent(breakpointPanel);
String namePrefix = "Breakpoints";
breakpointTable.setAccessibleNamePrefix(namePrefix);
breakpointFilterPanel.setAccessibleNamePrefix(namePrefix);
JPanel locationPanel = new JPanel(new BorderLayout());
locationTable = new GhidraTable(locationTableModel);
locationTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
@ -962,9 +966,12 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
locationFilterPanel.setSecondaryFilter(filterLocationsBySelectedBreakpoints);
locationPanel.add(locationFilterPanel, BorderLayout.SOUTH);
mainPanel.setRightComponent(locationPanel);
mainPanel.setResizeWeight(0.5);
String locationsNamePrefix = "Breakpoint Locations";
locationTable.setAccessibleNamePrefix(locationsNamePrefix);
locationFilterPanel.setAccessibleNamePrefix(locationsNamePrefix);
breakpointTable.getSelectionModel().addListSelectionListener(evt -> {
List<LogicalBreakpointRow> sel = breakpointFilterPanel.getSelectedItems();
// Do this first to prevent overriding context in event chain
@ -1096,6 +1103,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
locColModel.setVisible(locThreadsCol, false);
locColModel.setVisible(locSleighCol, false);
}
protected void navigateToSelectedBreakpoint() {

View file

@ -400,9 +400,9 @@ public class DebuggerConsoleProvider extends ComponentProviderAdapter
private final AutoService.Wiring autoServiceWiring;
@AutoOptionDefined(
name = DebuggerResources.OPTION_NAME_LOG_BUFFER_LIMIT,
description = "The maximum number of entries in the console log (0 or less for unlimited)",
help = @HelpInfo(anchor = "buffer_limit"))
name = DebuggerResources.OPTION_NAME_LOG_BUFFER_LIMIT,
description = "The maximum number of entries in the console log (0 or less for unlimited)",
help = @HelpInfo(anchor = "buffer_limit"))
private int logBufferLimit = DebuggerResources.DEFAULT_LOG_BUFFER_LIMIT;
@SuppressWarnings("unused")
private final AutoOptions.Wiring autoOptionsWiring;
@ -457,6 +457,10 @@ public class DebuggerConsoleProvider extends ComponentProviderAdapter
logFilterPanel = new GhidraTableFilterPanel<>(logTable, logTableModel);
mainPanel.add(logFilterPanel, BorderLayout.NORTH);
String namePrefix = "Debug Console";
logTable.setAccessibleNamePrefix(namePrefix);
logFilterPanel.setAccessibleNamePrefix(namePrefix);
logTable.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
@ -505,9 +509,8 @@ public class DebuggerConsoleProvider extends ComponentProviderAdapter
}
protected void createActions() {
actionClear = ClearAction.builder(plugin)
.onAction(this::activatedClear)
.buildAndInstallLocal(this);
actionClear =
ClearAction.builder(plugin).onAction(this::activatedClear).buildAndInstallLocal(this);
actionSelectNone = SelectNoneAction.builder(plugin)
.popupWhen(ctx -> ctx.getSourceComponent() == logTable)
.onAction(this::activatedSelectNone)
@ -665,16 +668,14 @@ public class DebuggerConsoleProvider extends ComponentProviderAdapter
}
protected ActionList computeToolbarActions(ActionContext context) {
return streamActions(context)
.filter(a -> a.getToolBarData() != null)
return streamActions(context).filter(a -> a.getToolBarData() != null)
.map(a -> new BoundAction(a, context))
.collect(Collectors.toCollection(ActionList::new));
}
@Override
public List<DockingActionIf> getPopupActions(Tool tool, ActionContext context) {
return streamActions(context)
.filter(a -> a.isAddToPopup(context))
return streamActions(context).filter(a -> a.isAddToPopup(context))
.collect(Collectors.toList());
}

View file

@ -70,6 +70,12 @@ public class MemviewPanel extends JPanel implements MouseListener, MouseMotionLi
addMouseListener(this);
addMouseMotionListener(this);
ToolTipManager.sharedInstance().registerComponent(this);
// This panel takes focus since it is a custom widget. Focusable components need to
// have their accessible name set.
String viewName = "Memory View";
setName(viewName);
getAccessibleContext().setAccessibleName(viewName);
}
@Override

View file

@ -59,6 +59,10 @@ public class MemviewTable {
component.add(filterPanel, BorderLayout.SOUTH);
table.setAutoscrolls(true);
String namePrefix = "Memory View";
table.setAccessibleNamePrefix(namePrefix);
filterPanel.setAccessibleNamePrefix(namePrefix);
table.getSelectionModel().addListSelectionListener(e -> {
if (e.getValueIsAdjusting()) {
return;

View file

@ -215,13 +215,16 @@ public class DebuggerStaticMappingProvider extends ComponentProviderAdapter
mainPanel.add(new JScrollPane(mappingTable));
mappingFilterPanel = new GhidraTableFilterPanel<>(mappingTable, mappingTableModel);
mainPanel.add(mappingFilterPanel, BorderLayout.SOUTH);
mappingTable.getSelectionModel().addListSelectionListener(evt -> {
myActionContext = new DebuggerStaticMappingActionContext(this,
mappingFilterPanel.getSelectedItems(), mappingTable);
contextChanged();
});
String namePrefix = "Static Mappings";
mappingTable.setAccessibleNamePrefix(namePrefix);
mappingFilterPanel.setAccessibleNamePrefix(namePrefix);
TableColumnModel columnModel = mappingTable.getColumnModel();
TableColumn dynAddrCol =
columnModel.getColumn(StaticMappingTableColumns.DYNAMIC_ADDRESS.ordinal());

View file

@ -135,8 +135,8 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
private final AutoService.Wiring autoServiceWiring;
@AutoOptionDefined(
name = "Default Extended Step",
description = "The default string for the extended step command")
name = "Default Extended Step",
description = "The default string for the extended step command")
String extendedStep = "";
@SuppressWarnings("unused")
@ -1333,8 +1333,8 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
*/
protected <T extends TargetObject> void performAction(ActionContext context,
boolean fallbackRoot, Class<T> cls,
Function<T, CompletableFuture<Void>> func, String errorMsg) {
boolean fallbackRoot, Class<T> cls, Function<T, CompletableFuture<Void>> func,
String errorMsg) {
TargetObject obj = getObjectFromContext(context);
if (obj == null && fallbackRoot) {
obj = root.getTargetObject();
@ -1485,8 +1485,8 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter
ProgramLocation currentLocation = listingService.getCurrentLocation();
ProgramSelection currentSelection = listingService.getCurrentSelection();
GhidraState state = new GhidraState(tool, project, currentProgram,
currentLocation, currentSelection, null);
GhidraState state =
new GhidraState(tool, project, currentProgram, currentLocation, currentSelection, null);
PrintWriter writer = consoleService.getStdOut();
TaskMonitor monitor = TaskMonitor.DUMMY;

View file

@ -570,6 +570,10 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter
regsFilterPanel = new GhidraTableFilterPanel<>(regsTable, regsTableModel);
mainPanel.add(regsFilterPanel, BorderLayout.SOUTH);
String namePrefix = "Registers";
regsTable.setAccessibleNamePrefix(namePrefix);
regsFilterPanel.setAccessibleNamePrefix(namePrefix);
regsTable.getSelectionModel().addListSelectionListener(evt -> {
if (evt.getValueIsAdjusting()) {
return;

View file

@ -15,7 +15,7 @@
*/
package ghidra.app.plugin.core.debug.gui.target;
import static ghidra.app.plugin.core.debug.gui.DebuggerResources.showError;
import static ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
import java.awt.BorderLayout;
import java.awt.event.MouseEvent;
@ -250,6 +250,8 @@ public class DebuggerTargetsProvider extends ComponentProviderAdapter {
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
mainPanel.add(tree);
tree.setAccessibleNamePrefix("Debugger Targets");
// NB: for both of these, setContext should precede emitEvents
tree.getGTSelectionModel().addGTreeSelectionListener(evt -> {
setContext();

View file

@ -407,6 +407,10 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter
watchFilterPanel = new GhidraTableFilterPanel<>(watchTable, watchTableModel);
mainPanel.add(watchFilterPanel, BorderLayout.SOUTH);
String namePrefix = "Watches";
watchTable.setAccessibleNamePrefix(namePrefix);
watchFilterPanel.setAccessibleNamePrefix(namePrefix);
watchTable.getSelectionModel().addListSelectionListener(evt -> {
if (evt.getValueIsAdjusting()) {
return;

View file

@ -67,11 +67,12 @@ public class BookmarkProvider extends ComponentProviderAdapter {
bookmarkTable = threadedTablePanel.getTable();
bookmarkTable.setAutoLookupColumn(BookmarkTableModel.CATEGORY_COL);
panel = new JPanel(new BorderLayout());
panel.add(threadedTablePanel, BorderLayout.CENTER);
panel.add(createFilterFieldPanel(), BorderLayout.SOUTH);
bookmarkTable.setAccessibleNamePrefix("Bookmarks");
adjustTableColumns();
listener = e -> {
@ -117,6 +118,8 @@ public class BookmarkProvider extends ComponentProviderAdapter {
tableFilterPanel.setToolTipText(
"Include bookmarks with Categories or Descriptions containing this text.");
tableFilterPanel.setAccessibleNamePrefix("Bookmarks");
return tableFilterPanel;
}

View file

@ -781,9 +781,9 @@ public class CallTreeProvider extends ComponentProviderAdapter {
GTreeSelectionListener contextSelectionListener = e -> notifyContextChanged();
incomingTree.addGTreeSelectionListener(contextSelectionListener);
outgoingTree.addGTreeSelectionListener(contextSelectionListener);
splitPane.setLeftComponent(createTreePanel(true, incomingTree));
splitPane.setRightComponent(createTreePanel(false, outgoingTree));
splitPane.addHierarchyListener(new HierarchyListener() {
@Override
public void hierarchyChanged(HierarchyEvent e) {
@ -802,6 +802,9 @@ public class CallTreeProvider extends ComponentProviderAdapter {
container.add(splitPane, BorderLayout.CENTER);
incomingTree.setAccessibleNamePrefix("Incoming Function Calls");
outgoingTree.setAccessibleNamePrefix("Outgoing Function Calls");
return container;
}

View file

@ -202,6 +202,8 @@ public class ComputeChecksumsProvider extends ComponentProviderAdapter {
model = new ChecksumTableModel(tool, checksums);
table = new GhidraTable(model);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.setAccessibleNamePrefix("Checksum Generator");
}
private void updateFields() {

View file

@ -104,7 +104,7 @@ class CommentWindowProvider extends ComponentProviderAdapter {
threadedTablePanel = new GhidraThreadedTablePanel<>(commentModel, 1000);
commentTable = threadedTablePanel.getTable();
commentTable.setName("CommentTable");
commentTable.getAccessibleContext().setAccessibleName("Comment Table");
commentTable.setAutoLookupColumn(CommentTableModel.TYPE_COL);
commentTable.setPreferredScrollableViewportSize(new Dimension(600, 400));
commentTable.setRowSelectionAllowed(true);
@ -137,6 +137,10 @@ class CommentWindowProvider extends ComponentProviderAdapter {
panel.add(threadedTablePanel, BorderLayout.CENTER);
panel.add(filterPanel, BorderLayout.SOUTH);
String namePrefix = "Comments";
commentTable.setAccessibleNamePrefix(namePrefix);
filterPanel.setAccessibleNamePrefix(namePrefix);
return panel;
}

View file

@ -39,8 +39,7 @@ import ghidra.program.model.symbol.SymbolTable;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
public class ConsoleComponentProvider extends ComponentProviderAdapter
implements ConsoleService {
public class ConsoleComponentProvider extends ComponentProviderAdapter implements ConsoleService {
private static final String OLD_NAME = "ConsolePlugin";
private static final String NAME = "Console";
@ -111,9 +110,13 @@ public class ConsoleComponentProvider extends ComponentProviderAdapter
private void build() {
textPane = new ConsoleTextPane(tool);
textPane.setName("CONSOLE");
Gui.registerFont(textPane, DEFAULT_FONT_ID);
textPane.setEditable(false);
String textPaneName = "Console Text Pane";
textPane.setName(textPaneName);
textPane.getAccessibleContext().setAccessibleName(textPaneName);
textPane.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
@ -277,9 +280,8 @@ public class ConsoleComponentProvider extends ComponentProviderAdapter
}
};
scrollAction.setDescription("Scroll Lock");
scrollAction
.setToolBarData(
new ToolBarData(new GIcon("icon.plugin.console.scroll.lock"), null));
scrollAction.setToolBarData(
new ToolBarData(new GIcon("icon.plugin.console.scroll.lock"), null));
scrollAction.setEnabled(true);
scrollAction.setSelected(scrollLock);

View file

@ -74,6 +74,8 @@ public class DataTypeArchiveGTree extends GTree {
}
addTreeExpansionListener(cleanupListener);
setAccessibleNamePrefix("Data Type Manager");
}
private int getHeight(GTreeNode rootNode, DataTypeTreeRenderer renderer) {

View file

@ -117,8 +117,9 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
provider = new DTPPComponentProvider();
tool.addComponentProvider(provider, false);
createActions();
table.setAccessibleNamePrefix("Data Type Preview");
}
@Override

View file

@ -109,7 +109,6 @@ class DataWindowProvider extends ComponentProviderAdapter {
threadedTablePanel = new GhidraThreadedTablePanel<>(dataModel, 1000);
dataTable = threadedTablePanel.getTable();
dataTable.setName("DataTable");
dataTable.setAutoLookupColumn(DataTableModel.DATA_COL);
dataTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
dataTable.setPreferredScrollableViewportSize(new Dimension(350, 150));
@ -138,12 +137,15 @@ class DataWindowProvider extends ComponentProviderAdapter {
setDataTableRenderer();
filterPanel = new GhidraTableFilterPanel<>(dataTable, dataModel);
dataTable.getModel();
JPanel panel = new JPanel(new BorderLayout());
panel.add(threadedTablePanel, BorderLayout.CENTER);
panel.add(filterPanel, BorderLayout.SOUTH);
String namePrefix = "Defined Data";
dataTable.setAccessibleNamePrefix(namePrefix);
filterPanel.setAccessibleNamePrefix(namePrefix);
return panel;
}
@ -158,12 +160,10 @@ class DataWindowProvider extends ComponentProviderAdapter {
private void setDataTableRenderer() {
dataTable.getColumnModel()
.getColumn(DataTableModel.LOCATION_COL)
.setPreferredWidth(
DataTableModel.ADDRESS_COL_WIDTH);
.setPreferredWidth(DataTableModel.ADDRESS_COL_WIDTH);
dataTable.getColumnModel()
.getColumn(DataTableModel.SIZE_COL)
.setPreferredWidth(
DataTableModel.SIZE_COL_WIDTH);
.setPreferredWidth(DataTableModel.SIZE_COL_WIDTH);
}
void reload() {

View file

@ -385,6 +385,10 @@ public class DisassembledViewPlugin extends ProgramPlugin implements DomainObjec
initializeDisplay();
String viewName = "Disassembled View";
contentList.setName(viewName);
contentList.getAccessibleContext().setAccessibleName(viewName);
// we need to do some custom rendering
contentList.setCellRenderer(new GListCellRenderer<DisassembledAddressInfo>() {

View file

@ -138,7 +138,6 @@ public class EquateTableProvider extends ComponentProviderAdapter {
equatesModel = new EquateTableModel(plugin);
equatesTable = new GhidraTable(equatesModel);
equatesTable.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
@ -171,7 +170,6 @@ public class EquateTableProvider extends ComponentProviderAdapter {
equatesTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
equatesFilterPanel = new GhidraTableFilterPanel<>(equatesTable, equatesModel);
JScrollPane equatesTablePane = new JScrollPane(equatesTable);
JPanel equatesPanel = new JPanel(new BorderLayout());
@ -181,6 +179,10 @@ public class EquateTableProvider extends ComponentProviderAdapter {
referencesModel = new EquateReferenceTableModel(plugin);
String namePrefix = "Equates";
equatesTable.setAccessibleNamePrefix(namePrefix);
equatesFilterPanel.setAccessibleNamePrefix(namePrefix);
referencesTable = new GhidraTable(referencesModel);
referencesTable.installNavigation(tool);
referencesTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
@ -188,6 +190,8 @@ public class EquateTableProvider extends ComponentProviderAdapter {
referencesTable.setRowSelectionAllowed(true);
referencesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
referencesTable.setAccessibleNamePrefix("Equates References");
JScrollPane referencesTablePane = new JScrollPane(referencesTable);
JTableHeader referencesHeader = referencesTable.getTableHeader();

View file

@ -30,7 +30,7 @@ import ghidra.util.table.*;
* {@link SourceTagsPanel}
*/
public class AllFunctionsPanel extends JPanel {
private static final String NAME = "Function Tags Applied Functions";
private FunctionTableModel model;
private GhidraTable table;
private GhidraTableFilterPanel<Function> filterPanel;
@ -41,21 +41,21 @@ public class AllFunctionsPanel extends JPanel {
*
* @param program the current program
* @param provider the component provider
* @param title the title of the panel
*/
public AllFunctionsPanel(Program program, ComponentProviderAdapter provider, String title) {
public AllFunctionsPanel(Program program, ComponentProviderAdapter provider) {
model = new FunctionTableModel(title, provider.getTool(), program, null);
GhidraThreadedTablePanel<Function> tablePanel =
new GhidraThreadedTablePanel<>(model);
model = new FunctionTableModel(NAME, provider.getTool(), program, null);
GhidraThreadedTablePanel<Function> tablePanel = new GhidraThreadedTablePanel<>(model);
table = tablePanel.getTable();
filterPanel = new GhidraTableFilterPanel<>(table, model);
setLayout(new BorderLayout());
titleLabel = new JLabel(title);
titleLabel = new JLabel(NAME);
titleLabel.setBorder(BorderFactory.createEmptyBorder(3, 5, 0, 0));
table.setAccessibleNamePrefix(NAME);
filterPanel.setAccessibleNamePrefix(NAME);
add(titleLabel, BorderLayout.NORTH);
add(tablePanel, BorderLayout.CENTER);
add(filterPanel, BorderLayout.SOUTH);
@ -101,10 +101,8 @@ public class AllFunctionsPanel extends JPanel {
return;
}
String tagNames = tags.stream()
.map(t -> t.getName())
.collect(Collectors.joining(" or "))
.toString();
String tagNames =
tags.stream().map(t -> t.getName()).collect(Collectors.joining(" or ")).toString();
titleLabel.setText("Functions With Tag: " + tagNames);
model.setTags(tags);

View file

@ -226,14 +226,13 @@ public class FunctionTagProvider extends ComponentProviderAdapter implements Dom
mainPanel.setPreferredSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
// CENTER PANEL
sourcePanel = new SourceTagsPanel(this, tool, "All Tags");
targetPanel = new TargetTagsPanel(this, tool, "Assigned To Function");
allFunctionsPanel = new AllFunctionsPanel(program, this, "Functions with Selected Tag");
sourcePanel = new SourceTagsPanel(this, tool);
targetPanel = new TargetTagsPanel(this, tool);
allFunctionsPanel = new AllFunctionsPanel(program, this);
buttonPanel = new FunctionTagButtonPanel(sourcePanel, targetPanel);
sourcePanel.setBorder(BorderFactory.createLineBorder(Colors.BORDER));
targetPanel.setBorder(BorderFactory.createLineBorder(Colors.BORDER));
allFunctionsPanel.setBorder(BorderFactory.createLineBorder(Colors.BORDER));
// If we don't set this, then the splitter won't be able to shrink the
// target panels below the size required by its header, which can be large
// because of the amount of text displayed. Keep the minimum size setting on
@ -480,9 +479,7 @@ public class FunctionTagProvider extends ComponentProviderAdapter implements Dom
private JPanel createInputPanel() {
tagInputField = new HintTextField("tag 1, tag 2, ...");
tagInputField.setName("tagInputTF");
tagInputField.addActionListener(e -> processCreates());
inputPanel = new JPanel();
Border outsideBorder = BorderFactory.createBevelBorder(BevelBorder.LOWERED);
Border insideBorder = BorderFactory.createEmptyBorder(5, 2, 2, 2);
@ -492,6 +489,10 @@ public class FunctionTagProvider extends ComponentProviderAdapter implements Dom
inputPanel.add(Box.createHorizontalStrut(5));
inputPanel.add(tagInputField, BorderLayout.CENTER);
String inputFieldName = "Tag Input Text Field";
tagInputField.setName(inputFieldName);
tagInputField.getAccessibleContext().setAccessibleName(inputFieldName);
return inputPanel;
}
}

View file

@ -34,10 +34,9 @@ public class SourceTagsPanel extends TagListPanel {
*
* @param provider the component provider
* @param tool the plugin tool
* @param title the title of the panel
*/
public SourceTagsPanel(FunctionTagProvider provider, PluginTool tool, String title) {
super(provider, tool, title);
public SourceTagsPanel(FunctionTagProvider provider, PluginTool tool) {
super(provider, tool, "Function Tags");
table.setDisabled(true);
}

View file

@ -60,9 +60,9 @@ public abstract class TagListPanel extends JPanel {
*
* @param provider the display provider
* @param tool the plugin tool
* @param title the title of the panel
* @param name the name of the panel
*/
public TagListPanel(FunctionTagProvider provider, PluginTool tool, String title) {
public TagListPanel(FunctionTagProvider provider, PluginTool tool, String name) {
this.tool = tool;
this.provider = provider;
@ -77,13 +77,15 @@ public abstract class TagListPanel extends JPanel {
};
table = (FunctionTagTable) tablePanel.getTable();
filterPanel = new GhidraTableFilterPanel<>(table, model);
titleLabel = new JLabel(title);
titleLabel = new JLabel(name);
titleLabel.setBorder(BorderFactory.createEmptyBorder(3, 5, 0, 0));
add(titleLabel, BorderLayout.NORTH);
add(tablePanel, BorderLayout.CENTER);
add(filterPanel, BorderLayout.SOUTH);
table.setAccessibleNamePrefix(name);
filterPanel.setAccessibleNamePrefix(name);
table.addMouseListener(new MouseAdapter() {
@Override
@ -128,9 +130,8 @@ public abstract class TagListPanel extends JPanel {
FunctionTagRowObject rowObject = model.getRowObject(row);
if (rowObject.isImmutable()) {
Msg.showWarn(this, table, "Tag Not Editable",
"Tag " + "\"" + rowObject.getName() + "\"" +
" must be added to the program before it can be modified/deleted");
Msg.showWarn(this, table, "Tag Not Editable", "Tag " + "\"" + rowObject.getName() +
"\"" + " must be added to the program before it can be modified/deleted");
return;
}
@ -172,8 +173,8 @@ public abstract class TagListPanel extends JPanel {
// Only process the name edit if the name actually changed.
if (!newName.equals(tagName)) {
Command cmd = new ChangeFunctionTagCmd(tagName, newName,
ChangeFunctionTagCmd.TAG_NAME_CHANGED);
Command cmd =
new ChangeFunctionTagCmd(tagName, newName, ChangeFunctionTagCmd.TAG_NAME_CHANGED);
tool.execute(cmd, program);
}

View file

@ -33,11 +33,9 @@ public class TargetTagsPanel extends TagListPanel {
*
* @param provider the component provider
* @param tool the plugin tool
* @param title the panel title
*/
public TargetTagsPanel(FunctionTagProvider provider,
PluginTool tool, String title) {
super(provider, tool, title);
public TargetTagsPanel(FunctionTagProvider provider, PluginTool tool) {
super(provider, tool, "Function Tags Assigned");
table.setDisabled(false);
}

View file

@ -118,8 +118,6 @@ public class FunctionWindowProvider extends ComponentProviderAdapter {
threadedTablePanel = new GhidraThreadedTablePanel<>(functionModel, 1000);
functionTable = threadedTablePanel.getTable();
functionTable.setName("FunctionTable");
functionTable.installNavigation(tool);
functionTable.setAutoLookupColumn(FunctionTableModel.NAME_COL);
functionTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
@ -148,6 +146,10 @@ public class FunctionWindowProvider extends ComponentProviderAdapter {
tableFilterPanel = new GhidraTableFilterPanel<>(functionTable, functionModel);
String namePrefix = "Functions";
functionTable.setAccessibleNamePrefix(namePrefix);
tableFilterPanel.setAccessibleNamePrefix(namePrefix);
JPanel container = new JPanel(new BorderLayout());
container.add(threadedTablePanel, BorderLayout.CENTER);
container.add(tableFilterPanel, BorderLayout.SOUTH);

View file

@ -135,6 +135,10 @@ class MemoryMapProvider extends ComponentProviderAdapter {
table.installNavigation(tool);
table.setAutoCreateColumnsFromModel(false);
String namePrefix = "Memory Map";
table.setAccessibleNamePrefix(namePrefix);
filterPanel.setAccessibleNamePrefix(namePrefix);
GTableCellRenderer monoRenderer = new GTableCellRenderer() {
@Override
protected Font getDefaultFont() {

View file

@ -103,7 +103,6 @@ public class BundleStatusComponentProvider extends ComponentProviderAdapter {
panel = new JPanel(new BorderLayout(5, 5));
bundleStatusTable = new GTable(bundleStatusTableModel);
bundleStatusTable.setName("BUNDLESTATUS_TABLE");
bundleStatusTable.setSelectionBackground(new GColor("color.bg.table.selection.bundle"));
bundleStatusTable.setSelectionForeground(new GColor("color.fg.table.selection.bundle"));
bundleStatusTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
@ -118,14 +117,17 @@ public class BundleStatusComponentProvider extends ComponentProviderAdapter {
// to allow custom cell renderers
bundleStatusTable.setAutoCreateColumnsFromModel(false);
filterPanel = new GTableFilterPanel<>(bundleStatusTable, bundleStatusTableModel);
JScrollPane scrollPane = new JScrollPane(bundleStatusTable);
panel.add(filterPanel, BorderLayout.SOUTH);
panel.add(scrollPane, BorderLayout.CENTER);
panel.setPreferredSize(new Dimension(800, 400));
String namePrefix = "Bundle Manager";
bundleStatusTable.setAccessibleNamePrefix(namePrefix);
filterPanel.setAccessibleNamePrefix(namePrefix);
}
private void addBundlesAction(String actionName, String description, Icon icon,

View file

@ -74,6 +74,9 @@ public class ProgramDnDTree extends DragNDropTree {
/**
* Construct a ProgramDnDTree with the given model.
* @param treeName The name of the tree to show in the tab
* @param model the tree model
* @param plugin the program tree plugin
*/
public ProgramDnDTree(String treeName, DefaultTreeModel model, ProgramTreePlugin plugin) {
super(model);
@ -86,6 +89,10 @@ public class ProgramDnDTree extends DragNDropTree {
mouseListenerDelegate = new JTreeMouseListenerDelegate(this);
initializeKeyEvents();
treeName += " Program Tree";
setName(treeName);
getAccessibleContext().setAccessibleName(treeName);
}
private void initializeKeyEvents() {
@ -316,8 +323,7 @@ public class ProgramDnDTree extends DragNDropTree {
}
try {
Object data = e.getTransferable()
.getTransferData(
SelectionTransferable.localProgramSelectionFlavor);
.getTransferData(SelectionTransferable.localProgramSelectionFlavor);
SelectionTransferData transferData = (SelectionTransferData) data;
return program.getDomainFile().getPathname().equals(transferData.getProgramPath());
}
@ -1285,6 +1291,10 @@ public class ProgramDnDTree extends DragNDropTree {
void setTreeName(String treeName) {
this.treeName = treeName;
treeName += " Program Tree";
setName(treeName);
getAccessibleContext().setAccessibleName(treeName);
}
/**

View file

@ -84,36 +84,36 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
private void createActions() {
new ActionBuilder("Add External Program Name", getOwner())
.popupMenuPath("Add External Program")
.popupMenuIcon(ADD_ICON)
.toolBarIcon(ADD_ICON)
.enabledWhen(ac -> program != null)
.onAction(ac -> addExternalProgram())
.buildAndInstallLocal(this);
.popupMenuPath("Add External Program")
.popupMenuIcon(ADD_ICON)
.toolBarIcon(ADD_ICON)
.enabledWhen(ac -> program != null)
.onAction(ac -> addExternalProgram())
.buildAndInstallLocal(this);
new ActionBuilder("Delete External Program Name", getOwner())
.popupMenuPath("Delete External Program")
.popupMenuIcon(DELETE_ICON)
.toolBarIcon(DELETE_ICON)
.enabledWhen(ac -> hasSelectedRows())
.onAction(ac -> deleteExternalProgram())
.buildAndInstallLocal(this);
.popupMenuPath("Delete External Program")
.popupMenuIcon(DELETE_ICON)
.toolBarIcon(DELETE_ICON)
.enabledWhen(ac -> hasSelectedRows())
.onAction(ac -> deleteExternalProgram())
.buildAndInstallLocal(this);
new ActionBuilder("Set External Name Association", getOwner())
.popupMenuPath("Set External Name Association")
.popupMenuIcon(EDIT_ICON)
.toolBarIcon(EDIT_ICON)
.enabledWhen(ac -> isSingleRowSelected())
.onAction(ac -> setExternalProgramAssociation())
.buildAndInstallLocal(this);
.popupMenuPath("Set External Name Association")
.popupMenuIcon(EDIT_ICON)
.toolBarIcon(EDIT_ICON)
.enabledWhen(ac -> isSingleRowSelected())
.onAction(ac -> setExternalProgramAssociation())
.buildAndInstallLocal(this);
new ActionBuilder("Clear External Name Association", getOwner())
.popupMenuPath("Clear External Name Association")
.popupMenuIcon(CLEAR_ICON)
.toolBarIcon(CLEAR_ICON)
.enabledWhen(ac -> hasSelectedRows())
.onAction(ac -> clearExternalAssociation())
.buildAndInstallLocal(this);
.popupMenuPath("Clear External Name Association")
.popupMenuIcon(CLEAR_ICON)
.toolBarIcon(CLEAR_ICON)
.enabledWhen(ac -> hasSelectedRows())
.onAction(ac -> clearExternalAssociation())
.buildAndInstallLocal(this);
}
@ -161,9 +161,12 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
ToolTipManager.sharedInstance().registerComponent(table);
panel.add(sp, BorderLayout.CENTER);
String namePrefix = "External Programs";
table.setName(namePrefix);
table.getAccessibleContext().setAccessibleName(namePrefix);
return panel;
}
@ -190,8 +193,7 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
private void addExternalProgram() {
InputDialog dialog = new InputDialog("New External Program", "Enter Name");
dialog.setHelpLocation(
new HelpLocation("ReferencesPlugin", "Add_External_Program_Name"));
dialog.setHelpLocation(new HelpLocation("ReferencesPlugin", "Add_External_Program_Name"));
getTool().showDialog(dialog, ExternalReferencesProvider.this);
if (dialog.isCanceled()) {
return;
@ -202,8 +204,7 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
"External program name cannot be empty");
return;
}
AddExternalNameCmd cmd =
new AddExternalNameCmd(newExternalName, SourceType.USER_DEFINED);
AddExternalNameCmd cmd = new AddExternalNameCmd(newExternalName, SourceType.USER_DEFINED);
getTool().execute(cmd, program);
}
@ -212,8 +213,7 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
StringBuilder buf = new StringBuilder();
CompoundCmd cmd = new CompoundCmd("Delete External Program Name");
for (String externalName : getSelectedExternalNames()) {
boolean hasLocations =
externalManager.getExternalLocations(externalName).hasNext();
boolean hasLocations = externalManager.getExternalLocations(externalName).hasNext();
if (hasLocations) {
buf.append("\n ");
buf.append(externalName);
@ -248,16 +248,13 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
String pathName = domainFile.toString();
dialog.close();
ExternalManager externalManager = program.getExternalManager();
String externalLibraryPath =
externalManager.getExternalLibraryPath(externalName);
String externalLibraryPath = externalManager.getExternalLibraryPath(externalName);
if (!pathName.equals(externalLibraryPath)) {
Command cmd =
new SetExternalNameCmd(externalName, domainFile.getPathname());
Command cmd = new SetExternalNameCmd(externalName, domainFile.getPathname());
getTool().execute(cmd, program);
}
});
dialog.setHelpLocation(
new HelpLocation("ReferencesPlugin", "ChooseExternalProgram"));
dialog.setHelpLocation(new HelpLocation("ReferencesPlugin", "ChooseExternalProgram"));
getTool().showDialog(dialog);
}
@ -344,9 +341,8 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
continue;
}
ExternalNamesRow path =
new ExternalNamesRow(programName,
extMgr.getExternalLibraryPath(programName));
ExternalNamesRow path = new ExternalNamesRow(programName,
extMgr.getExternalLibraryPath(programName));
paths.add(path);
}
}
@ -453,7 +449,7 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
// there are lots of empty path values.
Comparator<ExternalNamesRow> c1 =
(r1, r2) -> Objects.requireNonNullElse(r1.getPath(), "")
.compareTo(Objects.requireNonNullElse(r2.getPath(), ""));
.compareTo(Objects.requireNonNullElse(r2.getPath(), ""));
return c1.thenComparing((r1, r2) -> r1.getName().compareTo(r2.getName()));
}
return super.createSortComparator(columnIndex);

View file

@ -35,6 +35,7 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
import ghidra.util.table.GhidraTable;
import ghidra.util.task.SwingUpdateManager;
import resources.Icons;
@ -84,13 +85,17 @@ public class RegisterManagerProvider extends ComponentProviderAdapter {
splitPane.setDividerLocation(0.3);
tree.addGTreeSelectionListener(e -> showRegister());
values.getTable().getSelectionModel().addListSelectionListener(e -> {
JTable table = values.getTable();
deleteRegisterValuesAction.setEnabled(table.getSelectedRowCount() > 0);
selectRegisterValuesAction.setEnabled(table.getSelectedRowCount() > 0);
});
tree.setAccessibleNamePrefix("Register Manager");
GhidraTable table = values.getTable();
String namePrefix = "Register Manager Values";
table.setAccessibleNamePrefix(namePrefix);
}
void createActions() {

View file

@ -79,7 +79,6 @@ class RelocationProvider extends ComponentProviderAdapter {
table.setPreferredScrollableViewportSize(new Dimension(300, 200));
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
table.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
table.getSelectionModel().addListSelectionListener(e -> contextChanged());
ToolTipManager.sharedInstance().registerComponent(table);
@ -89,6 +88,10 @@ class RelocationProvider extends ComponentProviderAdapter {
tableFilterPanel = new GhidraTableFilterPanel<>(table, tableModel);
panel.add(tableFilterPanel, BorderLayout.SOUTH);
String namePrefix = "Relocations";
table.setAccessibleNamePrefix(namePrefix);
tableFilterPanel.setAccessibleNamePrefix(namePrefix);
return panel;
}

View file

@ -148,7 +148,6 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
scriptRoot = new RootNode();
scriptCategoryTree = new GTree(scriptRoot);
scriptCategoryTree.setName("CATEGORY_TREE");
scriptCategoryTree.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
@ -177,6 +176,8 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
scriptCategoryTree.getSelectionModel()
.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
scriptCategoryTree.setAccessibleNamePrefix("Script Category");
}
private void build() {
@ -185,7 +186,6 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
tableModel = new GhidraScriptTableModel(this, infoManager);
scriptTable = new DraggableScriptTable(this, tableModel);
scriptTable.setName("SCRIPT_TABLE");
scriptTable.setAutoLookupColumn(tableModel.getNameColumnIndex());
scriptTable.setRowSelectionAllowed(true);
scriptTable.setAutoCreateColumnsFromModel(false);
@ -214,6 +214,8 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
}
});
scriptTable.setAccessibleNamePrefix("Script");
TableColumnModel columnModel = scriptTable.getColumnModel();
// Set default column sizes
for (int i = 0; i < columnModel.getColumnCount(); i++) {
@ -1015,12 +1017,16 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
tableFilterPanel.setToolTipText("<html>Include scripts with <b>Names</b> or " +
"<b>Descriptions</b> containing this text.");
tableFilterPanel.setFocusComponent(scriptCategoryTree);
tableFilterPanel.setAccessibleNamePrefix("Script");
}
private JComponent buildDescriptionComponent() {
descriptionTextPane = new JTextPane();
descriptionTextPane.setEditable(false);
descriptionTextPane.setEditorKit(new HTMLEditorKit());
descriptionTextPane.setName("Script Description");
JPanel descriptionPanel = new JPanel(new BorderLayout());
descriptionPanel.add(descriptionTextPane);
JScrollPane scrollPane = new JScrollPane(descriptionPanel);
@ -1038,9 +1044,9 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
private void updateDescriptionPanel() {
ResourceFile script = getSelectedScript();
ScriptInfo info = infoManager.getExistingScriptInfo(script); // null script is ok
String text = script != null
? (info != null ? info.getToolTipText() : "Error! no script info!")
: null; // no selected script
String text =
script != null ? (info != null ? info.getToolTipText() : "Error! no script info!")
: null; // no selected script
// have to do an invokeLater here, since the DefaultCaret class runs in an invokeLater,
// which will overwrite our location setting

View file

@ -112,7 +112,6 @@ public class ViewStringsProvider extends ComponentProviderAdapter {
threadedTablePanel = new GhidraThreadedTablePanel<>(stringModel, 1000);
table = threadedTablePanel.getTable();
table.setName("DataTable");
table.setPreferredScrollableViewportSize(new Dimension(350, 150));
table.getSelectionModel().addListSelectionListener(e -> notifyContextChanged());
@ -150,19 +149,21 @@ public class ViewStringsProvider extends ComponentProviderAdapter {
}
});
TableColumn stringRepCol = table.getColumnModel()
.getColumn(
ViewStringsTableModel.COLUMNS.STRING_REP_COL.ordinal());
.getColumn(ViewStringsTableModel.COLUMNS.STRING_REP_COL.ordinal());
stringRepCol.setCellEditor(new StringRepCellEditor());
table.installNavigation(tool);
filterPanel = new GhidraTableFilterPanel<>(table, stringModel);
JPanel panel = new JPanel(new BorderLayout());
panel.add(threadedTablePanel, BorderLayout.CENTER);
panel.add(filterPanel, BorderLayout.SOUTH);
String namePrefix = "Defined Strings";
table.setAccessibleNamePrefix(namePrefix);
filterPanel.setAccessibleNamePrefix(namePrefix);
return panel;
}
@ -237,7 +238,6 @@ public class ViewStringsProvider extends ComponentProviderAdapter {
}
}
public Program getProgram() {
return currentProgram;
}

View file

@ -42,6 +42,8 @@ public class SymbolGTree extends GTree {
setCellRenderer(new SymbolTreeCellRenderer());
setDragNDropHandler(new SymbolGTreeDragNDropHandler(plugin));
setAccessibleNamePrefix("Symbol");
}
@Override

View file

@ -219,7 +219,8 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
SymbolNode node = (SymbolNode) object;
Symbol symbol = node.getSymbol();
SymbolType type = symbol.getSymbolType();
if (!type.isNamespace() || type == SymbolType.FUNCTION) {
if (!type.isNamespace() ||
type == SymbolType.FUNCTION) {
plugin.goTo(symbol);
}
}
@ -246,7 +247,8 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
deleteAction.setEnabled(false);
DockingAction referencesAction =
new ShowSymbolReferencesAction(plugin.getTool(), plugin.getName());
new ShowSymbolReferencesAction(plugin.getTool(),
plugin.getName());
DockingAction selectionAction = new SelectionAction(plugin);
selectionAction.setEnabled(false);
@ -369,11 +371,14 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
}
catch (DuplicateNameException e) {
sb.append("Parent namespace " + namespace.getName() +
" contains namespace named " + symbol.getName() + "\n");
" contains namespace named " + symbol.getName() +
"\n");
}
catch (InvalidInputException | CircularDependencyException e) {
sb.append("Could not change parent namespace for " + symbol.getName() + ": " +
e.getMessage() + "\n");
sb.append("Could not change parent namespace for " + symbol.getName() +
": " +
e.getMessage() +
"\n");
}
}
}
@ -400,7 +405,8 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
return true;
}
// the symbol to move does not allow dups, so make sure all existing symbols do allow dups.
List<Symbol> symbols = symbolTable.getSymbols(symbol.getName(), destinationNamespace);
List<Symbol> symbols = symbolTable.getSymbols(symbol.getName(),
destinationNamespace);
for (Symbol s : symbols) {
if (!s.getSymbolType().allowsDuplicates()) {
return false;
@ -659,7 +665,8 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
@Override
public String toString() {
return getClass().getSimpleName() + " " + symbol;
return getClass().getSimpleName() +
" " + symbol;
}
}

View file

@ -28,10 +28,6 @@ import ghidra.program.model.symbol.Reference;
import ghidra.util.table.GhidraTable;
import ghidra.util.table.GhidraThreadedTablePanel;
/**
*
*
*/
class ReferencePanel extends JPanel {
private ReferenceProvider referenceProvider;
@ -50,7 +46,6 @@ class ReferencePanel extends JPanel {
refTable = threadedTablePanel.getTable();
refTable.setAutoLookupColumn(SymbolReferenceModel.LABEL_COL);
refTable.setName("ReferenceTable");//used by JUnit...
refTable.setPreferredScrollableViewportSize(new Dimension(250, 200));
refTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
refTable.installNavigation(provider.getTool());
@ -66,6 +61,9 @@ class ReferencePanel extends JPanel {
}
add(threadedTablePanel, BorderLayout.CENTER);
String namePrefix = "Reference";
refTable.setAccessibleNamePrefix(namePrefix);
}
GhidraTable getTable() {

View file

@ -62,7 +62,6 @@ class SymbolPanel extends JPanel {
symTable = threadedTablePanel.getTable();
symTable.setAutoLookupColumn(SymbolTableModel.LABEL_COL);
symTable.setName("SymbolTable");//used by JUnit...
symTable.setRowSelectionAllowed(true);
symTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
symTable.getModel().addTableModelListener(listener);
@ -73,6 +72,8 @@ class SymbolPanel extends JPanel {
}
});
symTable.setAccessibleNamePrefix("Symbol");
symTable.installNavigation(tool);
for (int i = 0; i < symTable.getColumnCount(); i++) {
@ -102,8 +103,8 @@ class SymbolPanel extends JPanel {
"<html><b>Selected</b> causes filter to only consider the symbol's name.");
nameColumnOnlyCheckbox.setFocusable(false);
nameColumnOnlyCheckbox.setSelected(FILTER_NAME_ONLY_DEFAULT);
tableFilterPanel.setFilterRowTransformer(
updateRowDataTransformer(FILTER_NAME_ONLY_DEFAULT));
tableFilterPanel
.setFilterRowTransformer(updateRowDataTransformer(FILTER_NAME_ONLY_DEFAULT));
nameColumnOnlyCheckbox.addItemListener(e -> {
boolean nameOnly = nameColumnOnlyCheckbox.isSelected();
tableFilterPanel.setFilterRowTransformer(updateRowDataTransformer(nameOnly));
@ -111,6 +112,7 @@ class SymbolPanel extends JPanel {
tableFilterPanel.add(nameColumnOnlyCheckbox);
tableFilterPanel.setAccessibleNamePrefix("Symbol");
return tableFilterPanel;
}

View file

@ -183,11 +183,9 @@ public class GoToAddressLabelDialog extends ReusableDialogComponentProvider
gbc.weightx = 1;
gbc.gridwidth = 2;
gbc.insets = new Insets(5, 5, 5, 5);
hyperlink = new HyperlinkComponent("<html>Enter an address, label, <a href=\"" +
EXPRESSION_ANCHOR_NAME + "\">expression</a>, or " + "<a href=\"" +
FILE_OFFSET_ANCHOR_NAME + "\">file offset</a>:");
HyperlinkListener hyperlinkListener = evt -> {
if (evt.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
HelpLocation loc = new HelpLocation(HelpTopics.NAVIGATION, evt.getDescription());
@ -196,12 +194,14 @@ public class GoToAddressLabelDialog extends ReusableDialogComponentProvider
};
hyperlink.addHyperlinkListener(EXPRESSION_ANCHOR_NAME, hyperlinkListener);
hyperlink.addHyperlinkListener(FILE_OFFSET_ANCHOR_NAME, hyperlinkListener);
inner.add(hyperlink, gbc);
comboBox = new GhidraComboBox<>();
comboBox.setEditable(true);
comboBox.addActionListener(evt -> okCallback());
String comboName = "Go To Address or Lable Text Field / Combobox";
comboBox.setName(comboName);
comboBox.getAccessibleContext().setAccessibleName(comboName);
gbc.insets = new Insets(2, 5, 2, 0);
gbc.gridx = 0;
@ -212,12 +212,18 @@ public class GoToAddressLabelDialog extends ReusableDialogComponentProvider
caseSensitiveBox = new GCheckBox("Case sensitive", false);
gbc.gridy = 2;
gbc.gridwidth = 1;
String caseSensitiveCheckBoxName = "Case Sensitive Checkbox";
caseSensitiveBox.setName(caseSensitiveCheckBoxName);
caseSensitiveBox.getAccessibleContext().setAccessibleName(caseSensitiveCheckBoxName);
inner.add(caseSensitiveBox, gbc);
includeDynamicBox = new GCheckBox("Dynamic labels", true);
includeDynamicBox.setToolTipText("Include dynamic lables in the search (slower)");
gbc.gridx = 1;
inner.add(includeDynamicBox, gbc);
String dynamicCheckBoxName = "Dynamic Checkbox";
includeDynamicBox.setName(dynamicCheckBoxName);
includeDynamicBox.getAccessibleContext().setAccessibleName(dynamicCheckBoxName);
mainPanel = new JPanel(new BorderLayout());
Border emptyBorder = BorderFactory.createEmptyBorder(5, 5, 0, 5);

View file

@ -32,6 +32,6 @@ public class ListingFieldDescriptionProvider implements FieldDescriptionProvider
String addressString = address.toString(address.getAddressSpace().showSpaceName(), 1);
return fieldFactory.getFieldName() + " Field at Address " + addressString;
}
return "Unknown Field";
return "No program open";
}
}

View file

@ -122,6 +122,10 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
validate();
}
});
String viewName = "Assembly Listing View";
fieldPanel.setName(viewName);
fieldPanel.getAccessibleContext().setAccessibleName(viewName);
}
/**

View file

@ -40,4 +40,5 @@ public class GhidraTableFilterPanel<ROW_OBJECT> extends GTableFilterPanel<ROW_OB
String filterLabel) {
super(table, tableModel, filterLabel);
}
}

View file

@ -88,7 +88,8 @@ public class ByteViewerComponent extends FieldPanel implements FieldMouseListene
this.fm = fm;
this.layoutModel = layoutModel;
setName(model.getName());
setName("Byte Viewer");
getAccessibleContext().setAccessibleName("ByteViewer");
initialize();
// specialized line coloring

View file

@ -37,8 +37,7 @@ public class InteractivePanelManager {
public InteractivePanelManager() {
JTable table = new JTable();
header = new JTableHeader();
table.setTableHeader(header);
header = table.getTableHeader();
columnModel = header.getColumnModel();
separatorWidth = (new JSeparator(SwingConstants.VERTICAL)).getPreferredSize().width;
mainPanel = new JPanel(new HeaderLayoutManager());
@ -296,6 +295,7 @@ public class InteractivePanelManager {
}
record ComponentData(String name, JComponent component) {
@Override
public String toString() {
return name;
}

View file

@ -126,6 +126,9 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
fieldPanel.addFieldLocationListener(this);
fieldPanel.addLayoutListener(this);
fieldPanel.setName("Decompiler View");
fieldPanel.getAccessibleContext().setAccessibleName("Decompiler View");
fieldPanel.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {

View file

@ -522,16 +522,15 @@ public class FcgProvider
}
};
resetGraphAction.setToolBarData(new ToolBarData(Icons.REFRESH_ICON));
resetGraphAction.setDescription(
"<html>Resets the graph--All positioning will be <b>lost</b>");
resetGraphAction.setHelpLocation(
new HelpLocation("FunctionCallGraphPlugin", "Relayout_Graph"));
resetGraphAction
.setDescription("<html>Resets the graph--All positioning will be <b>lost</b>");
resetGraphAction
.setHelpLocation(new HelpLocation("FunctionCallGraphPlugin", "Relayout_Graph"));
addLocalAction(resetGraphAction);
MultiStateDockingAction<LayoutProvider<FcgVertex, FcgEdge, FunctionCallGraph>> layoutAction =
new MultiStateDockingAction<>(
RELAYOUT_GRAPH_ACTION_NAME, plugin.getName()) {
new MultiStateDockingAction<>(RELAYOUT_GRAPH_ACTION_NAME, plugin.getName()) {
@Override
public void actionPerformed(ActionContext context) {
@ -971,8 +970,11 @@ public class FcgProvider
BowTieExpandVerticesJob job = new BowTieExpandVerticesJob(viewer, collection, true);
VisualGraphViewUpdater<FcgVertex, FcgEdge> updater = view.getViewUpdater();
updater.scheduleViewChangeJob(job);
updateTitle();
String viewName = "Function Call Graph";
viewer.setName(viewName);
viewer.getAccessibleContext().setAccessibleName(viewName);
}
private void highlightExistingEdges(FcgExpandingVertexCollection collection) {

View file

@ -446,7 +446,6 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
new VTFunctionAssociationTableModel(tool, controller, sourceProgram, true);
sourceThreadedTablePanel = new GhidraThreadedTablePanel<>(sourceFunctionsModel, 1000);
sourceFunctionsTable = sourceThreadedTablePanel.getTable();
sourceFunctionsTable.setName("SourceFunctionTable");
sourceFunctionsTable
.setPreferenceKey("VTFunctionAssociationTableModel - Source Function Table");
sourceFunctionsTable.installNavigation(tool);
@ -474,7 +473,6 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
sourceTableFilterPanel =
new GhidraTableFilterPanel<>(sourceFunctionsTable, sourceFunctionsModel);
JPanel sourceFunctionPanel = new JPanel(new BorderLayout());
String sourceString =
(sourceProgram != null) ? sourceProgram.getDomainFile().toString() : NO_SESSION;
@ -484,6 +482,11 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
sourceFunctionPanel.add(sourceSessionLabel, BorderLayout.NORTH);
sourceFunctionPanel.add(sourceThreadedTablePanel, BorderLayout.CENTER);
sourceFunctionPanel.add(sourceTableFilterPanel, BorderLayout.SOUTH);
String namePrefix = "Source Functions";
sourceFunctionsTable.setAccessibleNamePrefix(namePrefix);
sourceTableFilterPanel.setAccessibleNamePrefix(namePrefix);
return sourceFunctionPanel;
}
@ -495,7 +498,6 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
destinationThreadedTablePanel =
new GhidraThreadedTablePanel<>(destinationFunctionsModel, 1000);
destinationFunctionsTable = destinationThreadedTablePanel.getTable();
destinationFunctionsTable.setName("DestinationFunctionTable");
destinationFunctionsTable.setPreferenceKey(
"VTFunctionAssociationTableModel - " + "Destination Function Table");
destinationFunctionsTable.installNavigation(tool);
@ -526,7 +528,6 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
destinationTableFilterPanel =
new GhidraTableFilterPanel<>(destinationFunctionsTable, destinationFunctionsModel);
JPanel destinationFunctionPanel = new JPanel(new BorderLayout());
String destinationString =
(destinationProgram != null) ? destinationProgram.getDomainFile().toString()
@ -537,6 +538,11 @@ public class VTFunctionAssociationProvider extends ComponentProviderAdapter
destinationFunctionPanel.add(destinationSessionLabel, BorderLayout.NORTH);
destinationFunctionPanel.add(destinationThreadedTablePanel, BorderLayout.CENTER);
destinationFunctionPanel.add(destinationTableFilterPanel, BorderLayout.SOUTH);
String namePrefix = "Destination Functions";
destinationFunctionsTable.setAccessibleNamePrefix(namePrefix);
destinationTableFilterPanel.setAccessibleNamePrefix(namePrefix);
return destinationFunctionPanel;
}

View file

@ -90,6 +90,11 @@ public class VTImpliedMatchesTableProvider extends ComponentProviderAdapter
filterPanel = new GhidraTableFilterPanel<>(impliedMatchesTable, impliedMatchTableModel);
panel.add(tablePanel, BorderLayout.CENTER);
panel.add(filterPanel, BorderLayout.SOUTH);
String namePrefix = "Implied Matches";
impliedMatchesTable.setAccessibleNamePrefix(namePrefix);
filterPanel.setAccessibleNamePrefix(namePrefix);
return panel;
}
@ -250,7 +255,6 @@ public class VTImpliedMatchesTableProvider extends ComponentProviderAdapter
new GhidraThreadedTablePanel<>(impliedMatchTableModel);
impliedMatchesTable = impliedMatchTablePanel.getTable();
impliedSelectionListener = e -> {
if (e.getValueIsAdjusting()) {
return;

View file

@ -175,6 +175,9 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
functionComparisonPanel);
splitPane.setResizeWeight(0.4);
markupPanel.add(splitPane, BorderLayout.CENTER);
markupItemsTable.setAccessibleNamePrefix("Markup Items");
return markupPanel;
}
@ -405,6 +408,10 @@ public class VTMarkupItemsTableProvider extends ComponentProviderAdapter
.addActionListener(e -> tool.showDialog(ancillaryFilterDialog, component));
ancillaryFilterButton.setToolTipText("Filters Dialog");
String buttonNamePrefix = "Markup Items Table Filter";
ancillaryFilterButton.setName(buttonNamePrefix + " Button");
ancillaryFilterButton.getAccessibleContext().setAccessibleName(buttonNamePrefix);
parentPanel.add(ancillaryFilterButton, BorderLayout.EAST);
HelpLocation filterHelpLocation =

View file

@ -98,7 +98,6 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
setIcon(VersionTrackingPluginPackage.ICON);
setDefaultWindowPosition(WindowPosition.TOP);
createActions();
component = createComponent();
setVisible(true);
@ -219,14 +218,14 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
matchesTable = createMatchesTable();
JPanel matchesTablePanel = new JPanel(new BorderLayout());
JPanel filterAreaPanel = createFilterArea();
matchesTablePanel.add(tablePanel, BorderLayout.CENTER);
matchesTablePanel.add(filterAreaPanel, BorderLayout.SOUTH);
JPanel parentPanel = new JPanel(new BorderLayout());
parentPanel.add(matchesTablePanel);
matchesTable.setAccessibleNamePrefix("Matches");
return parentPanel;
}

View file

@ -71,6 +71,7 @@ public abstract class AbstractTextFilter<T> extends Filter<T> {
textField.disableFocusEventProcessing();
JLabel label = new GDLabel(filterName + ": ");
label.setLabelFor(textField);
panel.add(label, BorderLayout.WEST);
panel.add(textField, BorderLayout.CENTER);

View file

@ -76,13 +76,11 @@ class ComponentNode extends Node {
String owner = e.getAttributeValue("OWNER");
String title = e.getAttributeValue("TITLE");
String group = e.getAttributeValue("GROUP");
if (group == null || group.trim()
.isEmpty()) {
if (group == null || group.trim().isEmpty()) {
group = ComponentProvider.DEFAULT_WINDOW_GROUP;
}
boolean isActive = Boolean.valueOf(e.getAttributeValue("ACTIVE"))
.booleanValue();
boolean isActive = Boolean.valueOf(e.getAttributeValue("ACTIVE")).booleanValue();
long uniqueID = getUniqueID(e, 0);
@ -131,14 +129,10 @@ class ComponentNode extends Node {
String name = placeholder.getName();
String title = placeholder.getTitle();
for (ComponentPlaceholder existingPlaceholder : windowPlaceholders) {
if (existingPlaceholder.getOwner()
.equals(owner) &&
existingPlaceholder.getName()
.equals(name) &&
existingPlaceholder.getGroup()
.equals(group) &&
existingPlaceholder.getTitle()
.equals(title)) {
if (existingPlaceholder.getOwner().equals(owner) &&
existingPlaceholder.getName().equals(name) &&
existingPlaceholder.getGroup().equals(group) &&
existingPlaceholder.getTitle().equals(title)) {
return true;
}
}

View file

@ -23,7 +23,6 @@ import java.math.BigInteger;
import java.util.*;
import javax.accessibility.*;
import javax.swing.JComponent;
import docking.widgets.EventTrigger;
import docking.widgets.fieldpanel.field.Field;
@ -58,7 +57,7 @@ public class AccessibleFieldPanelDelegate {
private List<AccessibleLayout> accessibleLayouts;
private int totalFieldCount;
private AccessibleField[] fieldsCache;
private JComponent panel;
private FieldPanel panel;
// caret position tracking
private FieldLocation cursorLoc;
@ -71,7 +70,7 @@ public class AccessibleFieldPanelDelegate {
private FieldSelection currentSelection;
public AccessibleFieldPanelDelegate(List<AnchoredLayout> layouts, AccessibleContext context,
JComponent panel) {
FieldPanel panel) {
this.context = context;
this.panel = panel;
setLayouts(layouts);
@ -84,6 +83,7 @@ public class AccessibleFieldPanelDelegate {
*/
public void setLayouts(List<AnchoredLayout> layouts) {
totalFieldCount = 0;
cursorField = null;
accessibleLayouts = new ArrayList<>(layouts.size());
for (AnchoredLayout layout : layouts) {
AccessibleLayout accessibleLayout = new AccessibleLayout(layout, totalFieldCount);
@ -92,6 +92,9 @@ public class AccessibleFieldPanelDelegate {
}
fieldsCache = new AccessibleField[totalFieldCount];
context.firePropertyChange(ACCESSIBLE_INVALIDATE_CHILDREN, null, panel);
if (cursorLoc != null) {
setCaret(cursorLoc, EventTrigger.GUI_ACTION);
}
}
/**
@ -108,6 +111,7 @@ public class AccessibleFieldPanelDelegate {
AccessibleTextSequence newSequence = getAccessibleTextSequence(cursorField);
String oldDescription = description;
description = generateDescription();
if (trigger == EventTrigger.GUI_ACTION) {
context.firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, oldSequence, newSequence);
context.firePropertyChange(ACCESSIBLE_DESCRIPTION_PROPERTY, oldDescription,
@ -212,15 +216,33 @@ public class AccessibleFieldPanelDelegate {
* @return the AccessibleField associated with the given field location
*/
public AccessibleField getAccessibleField(FieldLocation loc) {
int result = Collections.binarySearch(accessibleLayouts, loc.getIndex(),
AccessibleLayout accessibleLayout = getAccessibleLayout(loc.getIndex());
if (accessibleLayout != null) {
return getAccessibleField(accessibleLayout.getStartingFieldNum() + loc.getFieldNum());
}
LayoutModel layoutModel = panel.getLayoutModel();
Layout layout = layoutModel.getLayout(loc.getIndex());
if (layout == null) {
return null;
}
Field field = layout.getField(loc.getFieldNum());
return new AccessibleField(field, panel, loc.getFieldNum(), null);
}
private AccessibleLayout getAccessibleLayout(BigInteger index) {
if (accessibleLayouts == null) {
return null;
}
int result = Collections.binarySearch(accessibleLayouts, index,
Comparator.comparing(
o -> o instanceof AccessibleLayout lh ? lh.getIndex() : (BigInteger) o,
BigInteger::compareTo));
if (result < 0) {
return null;
}
AccessibleLayout layout = accessibleLayouts.get(result);
return getAccessibleField(layout.getStartingFieldNum() + loc.getFieldNum());
return accessibleLayouts.get(result);
}
private AccessibleField createAccessibleField(int fieldNum) {
@ -321,7 +343,7 @@ public class AccessibleFieldPanelDelegate {
*/
public Accessible getAccessibleAt(Point p) {
int result = Collections.binarySearch(accessibleLayouts, p.y, Comparator
.comparingInt(o -> o instanceof AccessibleLayout lh ? lh.getYpos() : (Integer) o));
.comparingInt(o -> o instanceof AccessibleLayout lh ? lh.getYpos() : (Integer) o));
if (result < 0) {
result = -result - 2;

View file

@ -2195,6 +2195,7 @@ public class FieldPanel extends JPanel
// Make sure the position is valid
if ((index.compareTo(BigInteger.ZERO) < 0) ||
(index.compareTo(model.getNumIndexes()) >= 0)) {
notifyCursorChanged(trigger);
return false;
}

View file

@ -464,4 +464,16 @@ public class FilterTextField extends JPanel {
}
}
/**
* Sets the accessible name prefix for for the focusable components in the filter panel.
* @param prefix the base name for these components. A suffix will be added to further
* describe the sub component.
*/
public void setAccessibleNamePrefix(String prefix) {
String name = prefix + " filter text field";
textField.setName(name);
textField.getAccessibleContext().setAccessibleName(name);
}
}

View file

@ -44,6 +44,15 @@ public class GFilterTable<ROW_OBJECT> extends JPanel {
filterPanel.dispose();
}
/**
* Sets the accessible name prefix for both the table and the filter panel
* @param prefix the name prefix
*/
public void setAccessibleNamePrefix(String prefix) {
table.setAccessibleNamePrefix(prefix);
filterPanel.setAccessibleNamePrefix(prefix);
}
private void buildTable() {
if (model instanceof ThreadedTableModel) {
buildThreadedTable();

View file

@ -409,6 +409,24 @@ public class GTable extends JTable {
return enableActionKeyBindings;
}
/**
* Sets an accessible name on the GTable such that screen readers will properly describe them.
* <P>
* This prefix should be the base name that describes the type of items in the table.
* This method will then append the necessary information to property name the table.
*
* @param namePrefix the accessible name prefix to assign to the filter component. For
* example if the table contains fruits, then "Fruits" would be an appropriate prefix name.
*/
public void setAccessibleNamePrefix(String namePrefix) {
// set the component name as general good practice
setName(namePrefix + " Table");
// screen reader reads the accessible name followed by the role ("table" in this case)
// so don't append "Table" to the accessible name
getAccessibleContext().setAccessibleName(namePrefix);
}
/**
* Enables or disables auto-edit. When enabled, the user can start typing to trigger an
* edit of an editable table cell.

View file

@ -201,6 +201,33 @@ public class GTableFilterPanel<ROW_OBJECT> extends JPanel {
this(table, tableModel, " Filter: ");
}
/**
* Sets an accessible name on the filter component. This prefix will be used to assign
* meaningful accessible names to the filter text field and the filter options button such
* that screen readers will properly describe them.
* <P>
* This prefix should be the base name that describes the type of items in the table. For
* example if the table contains fruits, then "Fruits" would be an appropriate prefix name.
* This method will then append the necessary information to name the text field and the button.
*
* @param namePrefix the accessible name prefix to assign to the filter component.
*/
public void setAccessibleNamePrefix(String namePrefix) {
filterField.setAccessibleNamePrefix(namePrefix);
String filterOptionsPrefix = namePrefix + " Filter Options";
filterStateButton.setName(filterOptionsPrefix + " Button");
// screen reader reads the accessible name followed by the role ("button" in this case)
// so don't append "button" to the accessible name
filterStateButton.getAccessibleContext().setAccessibleName(filterOptionsPrefix);
// Setting the accessible description to empty string prevents it from reading any tooltips
// on the button when the button gets focus. These buttons tend to have particularly large
// tooltips which seem excessive to read to the user every time they get focus. We may need
// to revisit this decision.
filterStateButton.getAccessibleContext().setAccessibleDescription("");
}
public GTableFilterPanel(JTable table, RowObjectTableModel<ROW_OBJECT> tableModel,
String filterLabel) {
this.table = table;

View file

@ -17,6 +17,7 @@ package docking.widgets.tree;
import java.awt.BorderLayout;
import javax.accessibility.AccessibleContext;
import javax.swing.*;
import javax.swing.border.BevelBorder;
@ -72,6 +73,26 @@ public class DefaultGTreeFilterProvider implements GTreeFilterProvider {
filterField.setEnabled(enabled);
}
@Override
public void setAccessibleNamePrefix(String namePrefix) {
filterField.setAccessibleNamePrefix(namePrefix);
String buttonNamePrefix = namePrefix + " Filter Options";
filterStateButton.setName(buttonNamePrefix + " Button");
AccessibleContext context = filterStateButton.getAccessibleContext();
// Don't add "Button" to prefix because screen readers reads the name followed by the role,
// which in this case, is "button"
context.setAccessibleName(buttonNamePrefix);
// Setting the accessible description to empty string prevents it from reading any tooltips
// on the button when the button gets focus. These buttons tend to have particularly large
// tooltips which seem excessive to read to the user every time they get focus. We may need
// to revisit this decision.
context.setAccessibleDescription("");
}
private void updateModelFilter() {
gTree.filterChanged();
}

View file

@ -248,6 +248,24 @@ public class GTree extends JPanel implements BusyListener {
add(filterProvider.getFilterComponent(), BorderLayout.SOUTH);
}
/**
* Sets an accessible name on the GTree. This prefix will be used to assign
* meaningful accessible names to the tree, filter text field and the filter options button such
* that screen readers will properly describe them.
* <P>
* This prefix should be the base name that describes the type of items in the tree.
* This method will then append the necessary information to name the text field and the button.
*
* @param namePrefix the accessible name prefix to assign to the filter component. For
* example if the tree contains fruits, then "Fruits" would be an appropriate prefix name.
*/
public void setAccessibleNamePrefix(String namePrefix) {
tree.setName(namePrefix + " Tree");
tree.getAccessibleContext().setAccessibleName(namePrefix);
tree.getAccessibleContext().setAccessibleDescription("");
filterProvider.setAccessibleNamePrefix(namePrefix);
}
public void setCellRenderer(GTreeRenderer renderer) {
this.renderer = renderer;
tree.setCellRenderer(renderer);
@ -1094,17 +1112,17 @@ public class GTree extends JPanel implements BusyListener {
Consumer<GTreeNode> consumer) {
/*
If the GTree were to use Java's CompletableStage API, then the code below
could be written thusly:
tree.getNewNode(modelParent, newName)
.thenCompose(newModelChild -> {
tree.ignoreFilter(newModelChild);
return tree.getNewNode(viewParent, newName);
))
.thenAccept(consumer);
*/
// ensure we operate on the model node which will always have the given child not the view

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,26 +15,71 @@
*/
package docking.widgets.tree;
import ghidra.util.FilterTransformer;
import javax.swing.JComponent;
import docking.DockingWindowManager;
import docking.widgets.tree.support.GTreeFilter;
import ghidra.util.FilterTransformer;
/**
* Interface for providing a filter for GTrees.
*/
public interface GTreeFilterProvider {
/**
* Returns the component to place at the bottom of a GTree to provider filtering capabilites.
* @return the filter component
*/
public JComponent getFilterComponent();
/**
* returns the {@link GTreeFilter} object to apply to the GTree whenever the filter component
* is manipulated
* @return the GTreeFilter to apply to the tree
*/
public GTreeFilter getFilter();
/**
* Sets the active state for the filter component.
* @param enabled true, the filter component is enabled
*/
public void setEnabled(boolean enabled);
/**
* Sets the filter text for the filter.
* @param text the text to filter on
*/
public void setFilterText(String text);
/**
* Returns the current filter text.
* @return the current filter text
*/
public String getFilterText();
/**
* Sets a {@link FilterTransformer} for preparing tree data to be filtered.
* @param transformer the transform for preparing tree data to be filtered
*/
public void setDataTransformer(FilterTransformer<GTreeNode> transformer);
public void loadFilterPreference(DockingWindowManager windowManager, String uniquePreferenceKey);
/**
* Loads any filter preferences that have been saved.
* @param windowManager the {@link DockingWindowManager} to load preferences from
* @param uniquePreferenceKey the preference key
*/
public void loadFilterPreference(DockingWindowManager windowManager,
String uniquePreferenceKey);
/**
* Sets an accessible name on the filter component. This prefix will be used to assign
* meaningful accessible names to the filter text field and the filter options button such
* that screen readers will properly describe them.
* <P>
* This prefix should be the base name that describes the type of items in the tree.
* This method will then append the necessary information to name the text field and the button.
*
* @param namePrefix the accessible name prefix to assign to the filter component. For
* example if the tree contains fruits, then "Fruits" would be an appropriate prefix name.
*/
public void setAccessibleNamePrefix(String namePrefix);
}

View file

@ -21,6 +21,7 @@ import java.beans.PropertyChangeListener;
import java.util.*;
import java.util.List;
import javax.accessibility.AccessibleContext;
import javax.swing.*;
import docking.*;
@ -64,6 +65,8 @@ public class ComponentInfoDialog extends DialogComponentProvider implements Prop
private EventDisplayPanel eventDisplay;
private JSplitPane splitPane;
private ToggleDockingAction eventAction;
private ToggleDockingAction toggleFollowFocusAction;
private boolean updateOnFocusChange = true;
public ComponentInfoDialog() {
super("Component Inspector", false);
@ -71,7 +74,8 @@ public class ComponentInfoDialog extends DialogComponentProvider implements Prop
addWorkPanel(buildMainPanel());
addDismissButton();
addOKButton();
setOkButtonText("Arm");
setOkButtonText("Reset");
setOkToolTip("Clears component table and will re-populate on next focussed component");
setPreferredSize(1200, 600);
eventDisplay = new EventDisplayPanel();
@ -79,7 +83,7 @@ public class ComponentInfoDialog extends DialogComponentProvider implements Prop
KeyboardFocusManager km = KeyboardFocusManager.getCurrentKeyboardFocusManager();
km.addPropertyChangeListener("permanentFocusOwner", this);
arm();
reset();
}
private void createActions() {
@ -106,6 +110,19 @@ public class ComponentInfoDialog extends DialogComponentProvider implements Prop
.onAction(c -> toggleShowEvents())
.build();
addAction(eventAction);
toggleFollowFocusAction = new ToggleActionBuilder("Follow Focus", ACTION_OWNER)
.toolBarIcon(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON)
.description("On causes component table to constant repopulate as focus changes")
.onAction(c -> toggleFollowFocus())
.selected(true)
.build();
addAction(toggleFollowFocusAction);
}
private void toggleFollowFocus() {
updateOnFocusChange = toggleFollowFocusAction.isSelected();
setOkEnabled(!updateOnFocusChange);
}
private void toggleShowEvents() {
@ -125,11 +142,11 @@ public class ComponentInfoDialog extends DialogComponentProvider implements Prop
@Override
protected void okCallback() {
arm();
reset();
}
// clear the current table data. The next component to get focus will repopulate the table data.
private void arm() {
private void reset() {
setRootContainer(null);
}
@ -154,6 +171,7 @@ public class ComponentInfoDialog extends DialogComponentProvider implements Prop
private JComponent buildTablePanel() {
model = new ComponentTableModel();
filterTable = new GFilterTable<ComponentInfo>(model);
filterTable.setAccessibleNamePrefix("Component Info");
return filterTable;
}
@ -244,7 +262,7 @@ public class ComponentInfoDialog extends DialogComponentProvider implements Prop
}
private void selectFocusedComponentInTable(Component newFocusComponent) {
if (infos.isEmpty()) {
if (infos.isEmpty() || updateOnFocusChange) {
if (newFocusComponent == null) {
return;
}
@ -255,6 +273,9 @@ public class ComponentInfoDialog extends DialogComponentProvider implements Prop
}
void setRootContainer(Container container) {
if (rootComponentForTable == container) {
return;
}
rootComponentForTable = container;
buildComponentModel();
}
@ -383,6 +404,8 @@ public class ComponentInfoDialog extends DialogComponentProvider implements Prop
descriptor.addVisibleColumn(new ComponentNameColumn());
descriptor.addVisibleColumn(new ComponentClassColumn());
descriptor.addVisibleColumn(new ToolTipColumn());
descriptor.addVisibleColumn(new AccessibleNameColumn());
descriptor.addVisibleColumn(new AccessibleDescriptionColumn());
descriptor.addHiddenColumn(new FocusableColumn());
descriptor.addHiddenColumn(new IsFocusCycleRootColumn());
descriptor.addHiddenColumn(new focusCycleRootColumn());
@ -435,6 +458,54 @@ public class ComponentInfoDialog extends DialogComponentProvider implements Prop
}
}
private class AccessibleNameColumn
extends AbstractDynamicTableColumn<ComponentInfo, String, Object> {
@Override
public String getColumnName() {
return "Accessible Name";
}
@Override
public String getValue(ComponentInfo info, Settings settings, Object data,
ServiceProvider provider) throws IllegalArgumentException {
AccessibleContext context = info.getComponent().getAccessibleContext();
if (context != null) {
return context.getAccessibleName();
}
return "";
}
@Override
public int getColumnPreferredWidth() {
return 200;
}
}
private class AccessibleDescriptionColumn
extends AbstractDynamicTableColumn<ComponentInfo, String, Object> {
@Override
public String getColumnName() {
return "Accessible Description";
}
@Override
public String getValue(ComponentInfo info, Settings settings, Object data,
ServiceProvider provider) throws IllegalArgumentException {
AccessibleContext context = info.getComponent().getAccessibleContext();
if (context != null) {
return context.getAccessibleDescription();
}
return "";
}
@Override
public int getColumnPreferredWidth() {
return 200;
}
}
private class ComponentClassColumn
extends AbstractDynamicTableColumn<ComponentInfo, String, Object> {
@ -510,7 +581,8 @@ public class ComponentInfoDialog extends DialogComponentProvider implements Prop
public String getValue(ComponentInfo info, Settings settings, Object data,
ServiceProvider provider) throws IllegalArgumentException {
Set<AWTKeyStroke> keys = info.getComponent()
.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
.getFocusTraversalKeys(
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
return keys == null ? "" : keys.toString();
}

View file

@ -25,13 +25,13 @@ import java.util.Locale;
import javax.accessibility.*;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.junit.Before;
import org.junit.Test;
import docking.widgets.EventTrigger;
import docking.widgets.fieldpanel.field.*;
import docking.widgets.fieldpanel.internal.EmptyBigLayoutModel;
import docking.widgets.fieldpanel.support.*;
public class AccessibleFieldPanelDelegateTest {
@ -42,7 +42,7 @@ public class AccessibleFieldPanelDelegateTest {
private static FontMetrics fontMetrics =
new JLabel("Dummy").getFontMetrics(new Font("Monospaced", Font.PLAIN, 12));
private List<AnchoredLayout> layouts;
private JPanel panel = new JPanel();
private FieldPanel panel = new FieldPanel(new EmptyBigLayoutModel());
private TestAccessibleContext testContext = new TestAccessibleContext();
private int fieldLineHeight = fontMetrics.getHeight() + 1;