mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-15 00:22:16 +00:00
GP-4519 fixed comment and comment history dialogs for accessibility
This commit is contained in:
parent
6c60bd0313
commit
5e91d02748
@ -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,119 +15,63 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.comments;
|
||||
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.DialogComponentProvider;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
/**
|
||||
* Dialog to show comment history; has a tab for each comment type to show
|
||||
* history of changes to the comment.
|
||||
*/
|
||||
public class CommentHistoryDialog extends DialogComponentProvider implements ChangeListener {
|
||||
|
||||
private Program program;
|
||||
private CodeUnit codeUnit;
|
||||
|
||||
public class CommentHistoryDialog extends DialogComponentProvider {
|
||||
|
||||
private JTabbedPane tabbedPane;
|
||||
private CommentHistoryPanel eolPanel;
|
||||
private CommentHistoryPanel prePanel;
|
||||
private CommentHistoryPanel postPanel;
|
||||
private CommentHistoryPanel platePanel;
|
||||
private CommentHistoryPanel repeatablePanel;
|
||||
|
||||
private final static int[] COMMENT_INDEXES =
|
||||
{CodeUnit.EOL_COMMENT,
|
||||
CodeUnit.PRE_COMMENT,
|
||||
CodeUnit.POST_COMMENT,
|
||||
CodeUnit.PLATE_COMMENT,
|
||||
CodeUnit.REPEATABLE_COMMENT};
|
||||
|
||||
/**
|
||||
* Construct a new CommentHistoryDialog
|
||||
* @param parent parent of this dialog
|
||||
*/
|
||||
CommentHistoryDialog() {
|
||||
|
||||
CommentHistoryDialog(CodeUnit cu, int initialCommentType) {
|
||||
super("Show Comment History");
|
||||
setHelpLocation(new HelpLocation(HelpTopics.COMMENTS, "Show_Comment_History"));
|
||||
addWorkPanel(buildMainPanel());
|
||||
setHelpLocation(new HelpLocation(HelpTopics.COMMENTS, "Show_Comment_History"));
|
||||
addWorkPanel(buildMainPanel(cu, initialCommentType));
|
||||
addDismissButton();
|
||||
setPreferredSize(500, 300);
|
||||
}
|
||||
|
||||
/* (non Javadoc)
|
||||
* @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
|
||||
*/
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
int index = tabbedPane.getSelectedIndex();
|
||||
CommentHistoryPanel panel = getHistoryPanel(COMMENT_INDEXES[index]);
|
||||
panel.showCommentHistory(program, codeUnit.getMinAddress());
|
||||
}
|
||||
void showDialog(CodeUnit cu, int commentType, PluginTool tool, ActionContext context) {
|
||||
codeUnit = cu;
|
||||
program = cu.getProgram();
|
||||
CommentHistoryPanel panel = getHistoryPanel(commentType);
|
||||
panel.showCommentHistory(program, cu.getMinAddress());
|
||||
tabbedPane.removeChangeListener(this);
|
||||
|
||||
for (int i=0;i<COMMENT_INDEXES.length; i++) {
|
||||
if (COMMENT_INDEXES[i] == commentType) {
|
||||
tabbedPane.setSelectedIndex(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
tabbedPane.addChangeListener(this);
|
||||
tool.showDialog( this, context.getComponentProvider() );
|
||||
}
|
||||
|
||||
private JPanel buildMainPanel() {
|
||||
private JPanel buildMainPanel(CodeUnit cu, int initialCommentType) {
|
||||
JPanel mainPanel = new JPanel(new BorderLayout());
|
||||
tabbedPane = new JTabbedPane();
|
||||
mainPanel.add(tabbedPane);
|
||||
|
||||
eolPanel = new CommentHistoryPanel(CodeUnit.EOL_COMMENT);
|
||||
prePanel = new CommentHistoryPanel(CodeUnit.PRE_COMMENT);
|
||||
postPanel = new CommentHistoryPanel(CodeUnit.POST_COMMENT);
|
||||
platePanel = new CommentHistoryPanel(CodeUnit.PLATE_COMMENT);
|
||||
repeatablePanel = new CommentHistoryPanel(CodeUnit.REPEATABLE_COMMENT);
|
||||
// Note that we don't add a keylistener here as in some other tab panes. This is because
|
||||
// the tab components are not focusable so there is no need to try and process a "space"
|
||||
// key. Instead, the history for each comment type is also added as a tooltip on its
|
||||
// corresponding tab. This will cause a screen reader to read the history for a tab
|
||||
// when it is selected.
|
||||
|
||||
eolPanel = new CommentHistoryPanel(CodeUnit.EOL_COMMENT, cu);
|
||||
prePanel = new CommentHistoryPanel(CodeUnit.PRE_COMMENT, cu);
|
||||
postPanel = new CommentHistoryPanel(CodeUnit.POST_COMMENT, cu);
|
||||
platePanel = new CommentHistoryPanel(CodeUnit.PLATE_COMMENT, cu);
|
||||
repeatablePanel = new CommentHistoryPanel(CodeUnit.REPEATABLE_COMMENT, cu);
|
||||
|
||||
addTab(" EOL Comment ", eolPanel);
|
||||
addTab(" Pre Comment ", prePanel);
|
||||
addTab(" Post Comment ", postPanel);
|
||||
addTab(" Plate Comment ", platePanel);
|
||||
addTab(" Repeatable Comment ", repeatablePanel);
|
||||
|
||||
JScrollPane sp = new JScrollPane(eolPanel);
|
||||
JViewport vp = sp.getViewport();
|
||||
Dimension d = vp.getPreferredSize();
|
||||
sp.getViewport().setPreferredSize(new Dimension(500, d.height*7));
|
||||
tabbedPane.addTab(" EOL Comment ",sp);
|
||||
tabbedPane.addTab(" Pre Comment ",new JScrollPane(prePanel));
|
||||
tabbedPane.addTab(" Post Comment ",new JScrollPane(postPanel));
|
||||
tabbedPane.addTab(" Plate Comment ",new JScrollPane(platePanel));
|
||||
tabbedPane.addTab(" Repeatable Comment ", new JScrollPane(repeatablePanel));
|
||||
|
||||
tabbedPane.addChangeListener(this);
|
||||
return mainPanel;
|
||||
}
|
||||
|
||||
private CommentHistoryPanel getHistoryPanel(int commentType) {
|
||||
switch(commentType) {
|
||||
case CodeUnit.EOL_COMMENT:
|
||||
return eolPanel;
|
||||
case CodeUnit.PRE_COMMENT:
|
||||
return prePanel;
|
||||
case CodeUnit.POST_COMMENT:
|
||||
return postPanel;
|
||||
case CodeUnit.PLATE_COMMENT:
|
||||
return platePanel;
|
||||
case CodeUnit.REPEATABLE_COMMENT:
|
||||
return repeatablePanel;
|
||||
}
|
||||
return null;
|
||||
|
||||
private void addTab(String title, CommentHistoryPanel panel) {
|
||||
JScrollPane sp = new JScrollPane(panel);
|
||||
tabbedPane.addTab(title, null, sp, panel.getHistory());
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,7 @@ import javax.swing.text.*;
|
||||
|
||||
import generic.theme.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.CommentHistory;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.util.DateUtils;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
@ -47,16 +46,13 @@ class CommentHistoryPanel extends JPanel {
|
||||
|
||||
private int commentType;
|
||||
|
||||
/**
|
||||
* Construct a new CommentHistoryPanel
|
||||
* @param commentType comment type
|
||||
*/
|
||||
CommentHistoryPanel(int commentType) {
|
||||
CommentHistoryPanel(int commentType, CodeUnit cu) {
|
||||
|
||||
super(new BorderLayout());
|
||||
setUpAttributes();
|
||||
this.commentType = commentType;
|
||||
create();
|
||||
showCommentHistory(cu.getProgram(), cu.getMinAddress());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,7 +60,7 @@ class CommentHistoryPanel extends JPanel {
|
||||
* @param program program
|
||||
* @param addr address of comment history
|
||||
*/
|
||||
void showCommentHistory(Program program, Address addr) {
|
||||
private void showCommentHistory(Program program, Address addr) {
|
||||
|
||||
textPane.setText("");
|
||||
|
||||
@ -89,6 +85,10 @@ class CommentHistoryPanel extends JPanel {
|
||||
private void create() {
|
||||
textPane = new JTextPane();
|
||||
textPane.setEditable(false);
|
||||
// Note that this panel in not focusable which means keyboard users can't navigate to
|
||||
// this text pane and therefore screen readers won't read it. To compensate for this
|
||||
// the history has been added as a tooltip on each tab.
|
||||
textPane.setFocusable(false);
|
||||
add(textPane, BorderLayout.CENTER);
|
||||
doc = textPane.getStyledDocument();
|
||||
}
|
||||
@ -126,4 +126,14 @@ class CommentHistoryPanel extends JPanel {
|
||||
StyleConstants.setTabSet(tabAttrSet, new TabSet(new TabStop[] { tabs }));
|
||||
}
|
||||
|
||||
public String getHistory() {
|
||||
try {
|
||||
return doc.getText(0, doc.getLength());
|
||||
}
|
||||
catch (BadLocationException e) {
|
||||
Msg.error(this, "This should never happen as the indexes came from the document!");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -278,6 +278,12 @@ public class CommentsDialog extends ReusableDialogComponentProvider implements K
|
||||
eolField = new JTextArea(5, 80);
|
||||
repeatableField = new JTextArea(5, 80);
|
||||
|
||||
preField.getAccessibleContext().setAccessibleName("Pre Comment");
|
||||
postField.getAccessibleContext().setAccessibleName("Post Comment");
|
||||
plateField.getAccessibleContext().setAccessibleName("Plate Comment");
|
||||
eolField.getAccessibleContext().setAccessibleName("EOL Comment");
|
||||
repeatableField.getAccessibleContext().setAccessibleName("Repeatable Comment");
|
||||
|
||||
DocumentListener dl = new DocumentListener() {
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
@ -339,8 +345,24 @@ public class CommentsDialog extends ReusableDialogComponentProvider implements K
|
||||
tab.addTab(" Plate Comment ", new JScrollPane(plateField));
|
||||
tab.addTab(" Repeatable Comment ", new JScrollPane(repeatableField));
|
||||
|
||||
tab.addChangeListener(ev -> chooseFocus());
|
||||
|
||||
tab.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
int keyCode = e.getKeyCode();
|
||||
if (keyCode == KeyEvent.VK_SPACE || keyCode == KeyEvent.VK_ENTER) {
|
||||
focusSelectedTab();
|
||||
e.consume();
|
||||
}
|
||||
}
|
||||
});
|
||||
tab.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getButton() == MouseEvent.BUTTON1) {
|
||||
focusSelectedTab();
|
||||
}
|
||||
}
|
||||
});
|
||||
ActionListener addAnnotationAction = e -> {
|
||||
JTextArea currentTextArea = getSelectedTextArea();
|
||||
for (AnnotationAdapterWrapper annotation : annotations) {
|
||||
@ -428,7 +450,7 @@ public class CommentsDialog extends ReusableDialogComponentProvider implements K
|
||||
}
|
||||
}
|
||||
|
||||
private void chooseFocus() {
|
||||
private void focusSelectedTab() {
|
||||
getSelectedTextArea().requestFocus();
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@ import ghidra.app.cmd.comments.SetCommentsCmd;
|
||||
import ghidra.app.context.ListingActionContext;
|
||||
import ghidra.app.context.ListingContextAction;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.framework.options.*;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
@ -118,8 +117,8 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener {
|
||||
plateComment = (plateComment.length() == 0) ? null : plateComment;
|
||||
repeatableComment = (repeatableComment.length() == 0) ? null : repeatableComment;
|
||||
|
||||
Command cmd = new SetCommentsCmd(cu.getMinAddress(), preComment, postComment, eolComment,
|
||||
plateComment, repeatableComment);
|
||||
SetCommentsCmd cmd = new SetCommentsCmd(cu.getMinAddress(), preComment, postComment,
|
||||
eolComment, plateComment, repeatableComment);
|
||||
|
||||
tool.execute(cmd, cu.getProgram());
|
||||
}
|
||||
@ -131,7 +130,7 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener {
|
||||
*/
|
||||
void deleteComments(Program program, ProgramLocation loc) {
|
||||
int commentType = CommentType.getCommentType(null, loc, CodeUnit.EOL_COMMENT);
|
||||
Command cmd = new SetCommentCmd(loc.getByteAddress(), commentType, null);
|
||||
SetCommentCmd cmd = new SetCommentCmd(loc.getByteAddress(), commentType, null);
|
||||
tool.execute(cmd, program);
|
||||
}
|
||||
|
||||
@ -228,9 +227,9 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener {
|
||||
private void showCommentHistory(ListingActionContext context) {
|
||||
CodeUnit cu = context.getCodeUnit();
|
||||
ProgramLocation loc = context.getLocation();
|
||||
CommentHistoryDialog historyDialog = new CommentHistoryDialog();
|
||||
historyDialog.showDialog(cu, CommentType.getCommentType(null, loc, CodeUnit.EOL_COMMENT),
|
||||
tool, context);
|
||||
int commentType = CommentType.getCommentType(null, loc, CodeUnit.EOL_COMMENT);
|
||||
CommentHistoryDialog historyDialog = new CommentHistoryDialog(cu, commentType);
|
||||
tool.showDialog(historyDialog, context.getComponentProvider());
|
||||
}
|
||||
|
||||
private void updatePopupPath(DockingAction action, String actionString, ProgramLocation loc) {
|
||||
@ -242,9 +241,8 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener {
|
||||
|
||||
if (loc instanceof FunctionRepeatableCommentFieldLocation) {
|
||||
action.getPopupMenuData()
|
||||
.setMenuPath(
|
||||
new String[] { "Comments",
|
||||
actionString + " Repeatable Comment" + endString });
|
||||
.setMenuPath(new String[] { "Comments",
|
||||
actionString + " Repeatable Comment" + endString });
|
||||
return;
|
||||
}
|
||||
|
||||
@ -266,9 +264,8 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener {
|
||||
|
||||
case CodeUnit.POST_COMMENT:
|
||||
action.getPopupMenuData()
|
||||
.setMenuPath(
|
||||
new String[] { "Comments",
|
||||
actionString + " Post-Comment" + endString });
|
||||
.setMenuPath(new String[] { "Comments",
|
||||
actionString + " Post-Comment" + endString });
|
||||
break;
|
||||
|
||||
case CodeUnit.EOL_COMMENT:
|
||||
@ -279,9 +276,8 @@ public class CommentsPlugin extends Plugin implements OptionsChangeListener {
|
||||
|
||||
case CodeUnit.REPEATABLE_COMMENT:
|
||||
action.getPopupMenuData()
|
||||
.setMenuPath(
|
||||
new String[] { "Comments",
|
||||
actionString + " Repeatable Comment" + endString });
|
||||
.setMenuPath(new String[] { "Comments",
|
||||
actionString + " Repeatable Comment" + endString });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user