diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java index e7e4a2bbbd..35a77da536 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java @@ -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 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() { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/console/DebuggerConsoleProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/console/DebuggerConsoleProvider.java index 1408905fdb..ee68fd9c60 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/console/DebuggerConsoleProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/console/DebuggerConsoleProvider.java @@ -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 getPopupActions(Tool tool, ActionContext context) { - return streamActions(context) - .filter(a -> a.isAddToPopup(context)) + return streamActions(context).filter(a -> a.isAddToPopup(context)) .collect(Collectors.toList()); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewPanel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewPanel.java index 341289f903..a7a53490a4 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewPanel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewPanel.java @@ -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 diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewTable.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewTable.java index 040f71f3f3..49ab9795b4 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewTable.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/MemviewTable.java @@ -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; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProvider.java index 0e63f86462..cf6b8a52bb 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProvider.java @@ -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()); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java index 440dcbf5da..843428f55c 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java @@ -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 void performAction(ActionContext context, - boolean fallbackRoot, Class cls, - Function> func, String errorMsg) { + boolean fallbackRoot, Class cls, Function> 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; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java index bf7ba68498..31ae245057 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java @@ -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; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/target/DebuggerTargetsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/target/DebuggerTargetsProvider.java index 7360b1e16a..1f306272ad 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/target/DebuggerTargetsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/target/DebuggerTargetsProvider.java @@ -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(); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProvider.java index d3ee011e75..4867aa9f8e 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProvider.java @@ -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; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkProvider.java index ab09f93377..5c5d813b83 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/bookmark/BookmarkProvider.java @@ -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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreeProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreeProvider.java index ef2a3f01a8..d9d4345089 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreeProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreeProvider.java @@ -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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/checksums/ComputeChecksumsProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/checksums/ComputeChecksumsProvider.java index 6de494c327..cdfb0a3b45 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/checksums/ComputeChecksumsProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/checksums/ComputeChecksumsProvider.java @@ -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() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/commentwindow/CommentWindowProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/commentwindow/CommentWindowProvider.java index 29acd93afe..5a65cf2f04 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/commentwindow/CommentWindowProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/commentwindow/CommentWindowProvider.java @@ -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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/console/ConsoleComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/console/ConsoleComponentProvider.java index 3be30d4367..2d1dc2786e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/console/ConsoleComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/console/ConsoleComponentProvider.java @@ -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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeArchiveGTree.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeArchiveGTree.java index 8be854175b..72e3f3b517 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeArchiveGTree.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/tree/DataTypeArchiveGTree.java @@ -74,6 +74,8 @@ public class DataTypeArchiveGTree extends GTree { } addTreeExpansionListener(cleanupListener); + + setAccessibleNamePrefix("Data Type Manager"); } private int getHeight(GTreeNode rootNode, DataTypeTreeRenderer renderer) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datapreview/DataTypePreviewPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datapreview/DataTypePreviewPlugin.java index df59a8d79e..050887110a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datapreview/DataTypePreviewPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datapreview/DataTypePreviewPlugin.java @@ -117,8 +117,9 @@ public class DataTypePreviewPlugin extends ProgramPlugin { provider = new DTPPComponentProvider(); tool.addComponentProvider(provider, false); - createActions(); + + table.setAccessibleNamePrefix("Data Type Preview"); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowProvider.java index 924fa9ee7c..da47837934 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datawindow/DataWindowProvider.java @@ -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() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/DisassembledViewPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/DisassembledViewPlugin.java index 9b5f74faec..7a00b9dcdb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/DisassembledViewPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/DisassembledViewPlugin.java @@ -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() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquateTableProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquateTableProvider.java index c8cd96177a..f896f5a31a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquateTableProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/EquateTableProvider.java @@ -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(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/AllFunctionsPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/AllFunctionsPanel.java index 8160acd0fe..c2a62e2c6f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/AllFunctionsPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/AllFunctionsPanel.java @@ -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 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 tablePanel = - new GhidraThreadedTablePanel<>(model); + model = new FunctionTableModel(NAME, provider.getTool(), program, null); + GhidraThreadedTablePanel 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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/FunctionTagProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/FunctionTagProvider.java index f7b3cc4b59..67fedd18f9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/FunctionTagProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/FunctionTagProvider.java @@ -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; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/SourceTagsPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/SourceTagsPanel.java index 5835def9df..00c9a7f44b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/SourceTagsPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/SourceTagsPanel.java @@ -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); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/TagListPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/TagListPanel.java index 0a08a6bb8c..7a133ff33c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/TagListPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/TagListPanel.java @@ -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); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/TargetTagsPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/TargetTagsPanel.java index 462375658e..b3e76648fd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/TargetTagsPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/tags/TargetTagsPanel.java @@ -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); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functionwindow/FunctionWindowProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functionwindow/FunctionWindowProvider.java index 66e64d35e9..3eb04d225e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functionwindow/FunctionWindowProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/functionwindow/FunctionWindowProvider.java @@ -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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java index 1326421311..4c66eeace5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/memory/MemoryMapProvider.java @@ -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() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/BundleStatusComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/BundleStatusComponentProvider.java index 540710298a..2e66e0a9ab 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/BundleStatusComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/osgi/BundleStatusComponentProvider.java @@ -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, diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramDnDTree.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramDnDTree.java index 81878f9acf..b092f3727a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramDnDTree.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/programtree/ProgramDnDTree.java @@ -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); } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ExternalReferencesProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ExternalReferencesProvider.java index df49874200..d73cd3fec2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ExternalReferencesProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ExternalReferencesProvider.java @@ -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 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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterManagerProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterManagerProvider.java index 824c5a2b16..3ed5921821 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterManagerProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/register/RegisterManagerProvider.java @@ -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() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationProvider.java index 0eb8923ff3..94ad924424 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reloc/RelocationProvider.java @@ -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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptComponentProvider.java index a6d6a06c63..32daa0e9fa 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptComponentProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptComponentProvider.java @@ -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("Include scripts with Names or " + "Descriptions 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 diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/strings/ViewStringsProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/strings/ViewStringsProvider.java index 11f10dcfd4..bc9f80b782 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/strings/ViewStringsProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/strings/ViewStringsProvider.java @@ -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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolGTree.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolGTree.java index fa4aad8e29..b23a94bcb1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolGTree.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolGTree.java @@ -42,6 +42,8 @@ public class SymbolGTree extends GTree { setCellRenderer(new SymbolTreeCellRenderer()); setDragNDropHandler(new SymbolGTreeDragNDropHandler(plugin)); + + setAccessibleNamePrefix("Symbol"); } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java index 05702ebfbd..a4a9b530f5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java @@ -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 symbols = symbolTable.getSymbols(symbol.getName(), destinationNamespace); + List 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; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/ReferencePanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/ReferencePanel.java index 72bfc9906e..0b7263dba9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/ReferencePanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/ReferencePanel.java @@ -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() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolPanel.java index 3c2868506d..ef24da439b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolPanel.java @@ -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 { "Selected 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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/navigation/GoToAddressLabelDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/navigation/GoToAddressLabelDialog.java index 95543fa7bb..038b977620 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/navigation/GoToAddressLabelDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/navigation/GoToAddressLabelDialog.java @@ -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("Enter an address, label, expression, or " + "file offset:"); - 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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ListingFieldDescriptionProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ListingFieldDescriptionProvider.java index 48cd8e4264..837f630d40 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ListingFieldDescriptionProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ListingFieldDescriptionProvider.java @@ -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"; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java index 06c170e1d8..e698c5f728 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/listingpanel/ListingPanel.java @@ -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); } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraTableFilterPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraTableFilterPanel.java index de5596d170..7b89ff553b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraTableFilterPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraTableFilterPanel.java @@ -40,4 +40,5 @@ public class GhidraTableFilterPanel extends GTableFilterPanelResets the graph--All positioning will be lost"); - resetGraphAction.setHelpLocation( - new HelpLocation("FunctionCallGraphPlugin", "Relayout_Graph")); + resetGraphAction + .setDescription("Resets the graph--All positioning will be lost"); + resetGraphAction + .setHelpLocation(new HelpLocation("FunctionCallGraphPlugin", "Relayout_Graph")); addLocalAction(resetGraphAction); MultiStateDockingAction> 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 updater = view.getViewUpdater(); updater.scheduleViewChangeJob(job); - updateTitle(); + + String viewName = "Function Call Graph"; + viewer.setName(viewName); + viewer.getAccessibleContext().setAccessibleName(viewName); } private void highlightExistingEdges(FcgExpandingVertexCollection collection) { diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/functionassociation/VTFunctionAssociationProvider.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/functionassociation/VTFunctionAssociationProvider.java index 7800c94bf3..e9eb6c9a2f 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/functionassociation/VTFunctionAssociationProvider.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/functionassociation/VTFunctionAssociationProvider.java @@ -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; } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/impliedmatches/VTImpliedMatchesTableProvider.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/impliedmatches/VTImpliedMatchesTableProvider.java index 1d5945cb11..e91f72db02 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/impliedmatches/VTImpliedMatchesTableProvider.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/impliedmatches/VTImpliedMatchesTableProvider.java @@ -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; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/markuptable/VTMarkupItemsTableProvider.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/markuptable/VTMarkupItemsTableProvider.java index c4b51a0c1b..9a4c63b09a 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/markuptable/VTMarkupItemsTableProvider.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/markuptable/VTMarkupItemsTableProvider.java @@ -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 = diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/VTMatchTableProvider.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/VTMatchTableProvider.java index 135ca3d4fe..d608cf7ed2 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/VTMatchTableProvider.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/matchtable/VTMatchTableProvider.java @@ -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; } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/AbstractTextFilter.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/AbstractTextFilter.java index 8fcf731c80..78fbaf8ca2 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/AbstractTextFilter.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/AbstractTextFilter.java @@ -71,6 +71,7 @@ public abstract class AbstractTextFilter extends Filter { textField.disableFocusEventProcessing(); JLabel label = new GDLabel(filterName + ": "); + label.setLabelFor(textField); panel.add(label, BorderLayout.WEST); panel.add(textField, BorderLayout.CENTER); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/ComponentNode.java b/Ghidra/Framework/Docking/src/main/java/docking/ComponentNode.java index 1772086301..720e04c394 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/ComponentNode.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/ComponentNode.java @@ -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; } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/AccessibleFieldPanelDelegate.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/AccessibleFieldPanelDelegate.java index 5724595c66..1a68d7387e 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/AccessibleFieldPanelDelegate.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/AccessibleFieldPanelDelegate.java @@ -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 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 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 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; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/FieldPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/FieldPanel.java index 7eaf9bf905..9eb9fc01aa 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/FieldPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/FieldPanel.java @@ -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; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filter/FilterTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filter/FilterTextField.java index 909063cee5..73bc18f722 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filter/FilterTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filter/FilterTextField.java @@ -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); + + } + } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GFilterTable.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GFilterTable.java index 1869960cc0..d804c0a48b 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GFilterTable.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GFilterTable.java @@ -44,6 +44,15 @@ public class GFilterTable 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(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java index c96359269d..6ed0c7ff6a 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTable.java @@ -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. + *

+ * 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. diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java index 685c95a49a..3435e1a42b 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableFilterPanel.java @@ -201,6 +201,33 @@ public class GTableFilterPanel 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. + *

+ * 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 tableModel, String filterLabel) { this.table = table; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/DefaultGTreeFilterProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/DefaultGTreeFilterProvider.java index fb2e2fc23f..b1ac603fb2 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/DefaultGTreeFilterProvider.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/DefaultGTreeFilterProvider.java @@ -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(); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java index eb225a19f1..4bd3cc9972 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java @@ -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. + *

+ * 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 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 diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTreeFilterProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTreeFilterProvider.java index 23db5aa979..8eb01aea1b 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTreeFilterProvider.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTreeFilterProvider.java @@ -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 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. + *

+ * 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); } diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/ComponentInfoDialog.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/ComponentInfoDialog.java index 6b3aa273db..56382611b2 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/ComponentInfoDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/util/ComponentInfoDialog.java @@ -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(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 { + + @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 { + + @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 { @@ -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 keys = info.getComponent() - .getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + .getFocusTraversalKeys( + KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); return keys == null ? "" : keys.toString(); } diff --git a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/AccessibleFieldPanelDelegateTest.java b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/AccessibleFieldPanelDelegateTest.java index d610c298fc..3619b3eef3 100644 --- a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/AccessibleFieldPanelDelegateTest.java +++ b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/AccessibleFieldPanelDelegateTest.java @@ -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 layouts; - private JPanel panel = new JPanel(); + private FieldPanel panel = new FieldPanel(new EmptyBigLayoutModel()); private TestAccessibleContext testContext = new TestAccessibleContext(); private int fieldLineHeight = fontMetrics.getHeight() + 1;