GP-5097 - Updated the Importer to allow users to double-click a language to pick it

This commit is contained in:
dragonmacher 2024-11-12 16:11:40 -05:00
parent d09c75e4ac
commit b7dec5e363
4 changed files with 133 additions and 90 deletions

View File

@ -19,8 +19,8 @@ import javax.swing.BorderFactory;
import docking.DialogComponentProvider;
import ghidra.framework.plugintool.PluginTool;
import ghidra.plugin.importer.LcsSelectionListener;
import ghidra.plugin.importer.NewLanguagePanel;
import ghidra.plugin.importer.*;
import ghidra.plugin.importer.LcsSelectionEvent.Type;
import ghidra.program.model.lang.*;
import ghidra.program.util.DefaultLanguageService;
import ghidra.util.HelpLocation;
@ -30,33 +30,14 @@ public class SetLanguageDialog extends DialogComponentProvider {
private NewLanguagePanel selectLangPanel;
private PluginTool tool;
private LanguageCompilerSpecPair currentLCSPair;
private LanguageCompilerSpecPair currentLcsPair;
private LanguageID dialogLanguageID;
private CompilerSpecID dialogCompilerSpecID;
LcsSelectionListener listener = e -> {
LanguageID langID = null;
CompilerSpecID compilerSpecID = null;
if (e != null && e.selection != null) {
langID = e.selection.languageID;
compilerSpecID = e.selection.compilerSpecID;
}
if ((currentLCSPair != null) && (langID != null) &&
(langID.equals(currentLCSPair.getLanguageID()))) {
if (compilerSpecID != null &&
compilerSpecID.equals(currentLCSPair.getCompilerSpecID())) {
setStatusText("Please select a different Language or Compiler Spec.");
setOkEnabled(false);
}
else {
setStatusText(null);
setOkEnabled(true);
}
return;
}
setStatusText(null);
setOkEnabled(langID != null);
private LcsSelectionListener listener = e -> {
languageSelected(e.getLcs());
maybePressOk(e);
};
/**
@ -89,7 +70,7 @@ public class SetLanguageDialog extends DialogComponentProvider {
*/
public SetLanguageDialog(PluginTool tool, LanguageCompilerSpecPair lcsPair, String title) {
super(title, true, true, true, false);
currentLCSPair = lcsPair;
currentLcsPair = lcsPair;
this.tool = tool;
selectLangPanel = new NewLanguagePanel();
@ -110,7 +91,40 @@ public class SetLanguageDialog extends DialogComponentProvider {
setHelpLocation(new HelpLocation("LanguageProviderPlugin", "set language"));
selectLangPanel.setShowRecommendedCheckbox(false);
listener.valueChanged(null); // kick to establish initial button enablement
languageSelected(null); // kick to establish initial button enablement
}
private void languageSelected(LanguageCompilerSpecPair lcs) {
LanguageID langId = null;
CompilerSpecID compilerSpecID = null;
if (lcs != null) {
langId = lcs.languageID;
compilerSpecID = lcs.compilerSpecID;
}
if ((currentLcsPair != null) && (langId != null) &&
(langId.equals(currentLcsPair.getLanguageID()))) {
if (compilerSpecID != null &&
compilerSpecID.equals(currentLcsPair.getCompilerSpecID())) {
setStatusText("Please select a different Language or Compiler Spec.");
setOkEnabled(false);
}
else {
setStatusText(null);
setOkEnabled(true);
}
return;
}
setStatusText(null);
setOkEnabled(langId != null);
}
private void maybePressOk(LcsSelectionEvent e) {
if (e.getType() == Type.PICKED && isOKEnabled()) {
// the user picked (i.e., double-clicked) a language and it is valid, so use it
okCallback();
}
}
private static LanguageCompilerSpecPair getLanguageCompilerSpecPair(String languageIdStr,

View File

@ -19,14 +19,14 @@ import java.awt.Component;
import java.util.*;
import javax.swing.BorderFactory;
import javax.swing.SwingUtilities;
import docking.DialogComponentProvider;
import ghidra.app.util.opinion.LoadSpec;
import ghidra.framework.plugintool.PluginTool;
import ghidra.plugin.importer.LcsSelectionEvent.Type;
import ghidra.program.model.lang.LanguageCompilerSpecPair;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
import ghidra.util.Swing;
public class ImporterLanguageDialog extends DialogComponentProvider {
@ -46,25 +46,11 @@ public class ImporterLanguageDialog extends DialogComponentProvider {
}
public void show(Component parent) {
if (SwingUtilities.isEventDispatchThread()) {
Swing.runIfSwingOrRunLater(() -> {
build();
tool.showDialog(this, parent);
}
else {
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
build();
tool.showDialog(ImporterLanguageDialog.this, parent);
}
});
}
catch (Exception e) {
Msg.error(this, e);
}
}
}
private void build() {
languagePanel = new NewLanguagePanel();
@ -72,10 +58,11 @@ public class ImporterLanguageDialog extends DialogComponentProvider {
languagePanel.setShowAllLcsPairs(false);
languagePanel.setBorder(
BorderFactory.createTitledBorder(" Select Language and Compiler Specification "));
languagePanel.addSelectionListener(new LcsSelectionListener() {
@Override
public void valueChanged(LcsSelectionEvent e) {
languagePanel.addSelectionListener(e -> {
validateFormInput();
if (e.getType() == Type.PICKED && isOKEnabled()) {
okCallback();
}
});

View File

@ -18,14 +18,33 @@ package ghidra.plugin.importer;
import ghidra.program.model.lang.LanguageCompilerSpecPair;
public class LcsSelectionEvent {
public final LanguageCompilerSpecPair selection;
public LcsSelectionEvent(LanguageCompilerSpecPair selection) {
this.selection = selection;
public enum Type {
/** A language was selected in the UI */
SELECTED,
/** A language was picked (e.g., double-clicked) in the UI */
PICKED
}
private final LanguageCompilerSpecPair lcs;
private final Type type;
public LcsSelectionEvent(LanguageCompilerSpecPair selection, Type type) {
this.lcs = selection;
this.type = type;
}
public LanguageCompilerSpecPair getLcs() {
return lcs;
}
public Type getType() {
return type;
}
@Override
public String toString() {
return "LSE{" + selection + "}";
return "LSE{" + lcs + "}";
}
}

View File

@ -23,10 +23,12 @@ import java.util.List;
import javax.swing.*;
import javax.swing.border.Border;
import docking.actions.KeyBindingUtils;
import docking.widgets.checkbox.GCheckBox;
import docking.widgets.label.GDLabel;
import generic.theme.GThemeDefaults.Colors.Messages;
import generic.theme.Gui;
import ghidra.plugin.importer.LcsSelectionEvent.Type;
import ghidra.program.model.lang.*;
import ghidra.program.util.DefaultLanguageService;
import ghidra.util.table.*;
@ -41,12 +43,13 @@ public class NewLanguagePanel extends JPanel {
private JCheckBox recommendedCheckbox;
private JLabel formatLabel;
private void setDescriptionLabelText(String text) {
if (text == null || "".equals(text)) {
text = " ";
}
descriptionLabel.setText(text);
}
private boolean isOnShowAll = true;
private List<LanguageCompilerSpecPair> allLcsPairsList;
private List<LanguageCompilerSpecPair> recommendedLcsPairsList;
private LanguageCompilerSpecPair recommendedLcsPair;
private final Set<LcsSelectionListener> listeners = new HashSet<>();
public NewLanguagePanel() {
constructEverything();
@ -94,7 +97,6 @@ public class NewLanguagePanel extends JPanel {
@Override
public Dimension getPreferredSize() {
// this makes us a bit smaller in height, as the preferred height can be excessive
Dimension preferredSize = super.getPreferredSize();
if (preferredSize.width == 0) {
return preferredSize; // no size yet, don't change anything
@ -138,16 +140,37 @@ public class NewLanguagePanel extends JPanel {
if (e.getValueIsAdjusting()) {
return;
}
notifyListeners();
notifyLanguageSelected();
});
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (e.getClickCount() == 2) {
// do the next action thingie
notfiyLanguagePicked();
}
}
});
// Update Enter to allow the user to pick the selected language
KeyStroke enterKs = KeyBindingUtils.parseKeyStroke("Enter");
Action action = new AbstractAction("Pick Language") {
@Override
public void actionPerformed(ActionEvent e) {
notfiyLanguagePicked();
}
};
// remove the table's enter key binding and then add our own
KeyBindingUtils.clearKeyBinding(table, enterKs);
KeyBindingUtils.registerAction(table, enterKs, action, JComponent.WHEN_FOCUSED);
}
private void setDescriptionLabelText(String text) {
if (text == null || "".equals(text)) {
text = " ";
}
descriptionLabel.setText(text);
}
public void setFormatText(String text) {
@ -158,8 +181,6 @@ public class NewLanguagePanel extends JPanel {
recommendedCheckbox.setVisible(show);
}
private boolean isOnShowAll = true;
private boolean isAllLcsPairsTableShowing() {
return isOnShowAll;
}
@ -174,7 +195,7 @@ public class NewLanguagePanel extends JPanel {
private void setLanguages(List<LanguageCompilerSpecPair> lcsPairList) {
tableModel.setLanguages(lcsPairList);
notifyListeners();
notifyLanguageSelected();
}
private void switchToAllList() {
@ -203,13 +224,20 @@ public class NewLanguagePanel extends JPanel {
}
}
private List<LanguageCompilerSpecPair> allLcsPairsList;
private List<LanguageCompilerSpecPair> recommendedLcsPairsList;
private void notifyLanguageSelected() {
LanguageCompilerSpecPair lcs = getSelectedLcsPair();
LcsSelectionEvent e = new LcsSelectionEvent(lcs, Type.SELECTED);
doNotify(e);
}
private LanguageCompilerSpecPair recommendedLcsPair;
private void notfiyLanguagePicked() {
LanguageCompilerSpecPair lcs = getSelectedLcsPair();
LcsSelectionEvent e = new LcsSelectionEvent(lcs, Type.PICKED);
doNotify(e);
}
private void notifyListeners() {
LanguageCompilerSpecPair selectedLcsPair = getSelectedLcsPair();
private void doNotify(LcsSelectionEvent event) {
LanguageCompilerSpecPair selectedLcsPair = event.getLcs();
if (selectedLcsPair == null) {
descriptionLabel.setText(DEFAULT_DESCRIPTION_TEXT);
}
@ -221,12 +249,9 @@ public class NewLanguagePanel extends JPanel {
descriptionLabel.setText("<LanguageNotFound>");
}
}
// notifyListenersOfValidityChanged();
if (!listeners.isEmpty()) {
LcsSelectionEvent e = new LcsSelectionEvent(selectedLcsPair);
for (LcsSelectionListener listener : listeners) {
listener.valueChanged(e);
}
listener.valueChanged(event);
}
}
@ -314,8 +339,6 @@ public class NewLanguagePanel extends JPanel {
return true;
}
private final Set<LcsSelectionListener> listeners = new HashSet<>();
public void addSelectionListener(LcsSelectionListener listener) {
listeners.add(listener);
}