GP-4545 fixing focus issues for data tree dialog in windows OS.

This commit is contained in:
ghidragon 2024-04-24 15:17:32 -04:00
parent 9abfa3da86
commit 330f7fe87c
5 changed files with 84 additions and 147 deletions

View file

@ -1184,12 +1184,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
DomainFileFilter filter = df -> Program.class.isAssignableFrom(df.getDomainObjectClass()); DomainFileFilter filter = df -> Program.class.isAssignableFrom(df.getDomainObjectClass());
// TODO regarding the hack note below, I believe it's fixed, but not sure how to test return new DataTreeDialog(null, "Map Module to Program", DataTreeDialog.OPEN, filter);
return new DataTreeDialog(null, "Map Module to Program", DataTreeDialog.OPEN, filter) {
{ // TODO/HACK: I get an NPE setting the default selection if I don't fake this.
dialogShown();
}
};
} }
public DomainFile askProgram(Program program) { public DomainFile askProgram(Program program) {

View file

@ -430,12 +430,7 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
} }
}; };
// TODO regarding the hack note below, I believe this issue ahs been fixed, but not sure how to test return new DataTreeDialog(null, OpenTraceAction.NAME, DataTreeDialog.OPEN, filter);
return new DataTreeDialog(null, OpenTraceAction.NAME, DataTreeDialog.OPEN, filter) {
{ // TODO/HACK: Why the NPE if I don't do this?
dialogShown();
}
};
} }
public DomainFile askTrace(Trace trace) { public DomainFile askTrace(Trace trace) {

View file

@ -81,10 +81,7 @@ public class DataTreeDialog extends DialogComponentProvider
private Component parent; private Component parent;
private String searchString; private String searchString;
private boolean comboModelInitialized;
private boolean cancelled = false; private boolean cancelled = false;
private String pendingNameText;
private DomainFolder pendingDomainFolder;
private ProjectDataExpandAction<DialogProjectTreeContext> expandAction; private ProjectDataExpandAction<DialogProjectTreeContext> expandAction;
private ProjectDataCollapseAction<DialogProjectTreeContext> collapseAction; private ProjectDataCollapseAction<DialogProjectTreeContext> collapseAction;
@ -134,23 +131,31 @@ public class DataTreeDialog extends DialogComponentProvider
public DataTreeDialog(Component parent, String title, int type, DomainFileFilter filter, public DataTreeDialog(Component parent, String title, int type, DomainFileFilter filter,
Project project) { Project project) {
super(title, true, true, true, false); super(title, true, true, true, false);
if (type < 0 || type > CREATE) {
throw new IllegalArgumentException("Invalid type specified: " + type);
}
this.project = project; this.project = project;
this.parent = parent; this.parent = parent;
initDataTreeDialog(type, filter); this.type = type;
this.filter = filter;
addWorkPanel(buildMainPanel());
initializeButtons();
rootPanel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
initializeFocusedComponent();
createActions();
} }
private static DomainFileFilter getDefaultFilter(int type) { private void initializeFocusedComponent() {
if (type == CHOOSE_FOLDER || type == OPEN) { Component focusComponent = nameField;
// return filter which forces folder selection and allow navigation into linked-folders if (!nameField.isEditable()) {
return new DomainFileFilter() { focusComponent = treePanel.getFilterField();
@Override
public boolean accept(DomainFile df) {
return true; // show all files (legacy behavior)
}
};
} }
return null; setFocusComponent(focusComponent);
} }
public void setTreeSelectionMode(int mode) { public void setTreeSelectionMode(int mode) {
@ -160,34 +165,20 @@ public class DataTreeDialog extends DialogComponentProvider
treeSelectionMode = mode; treeSelectionMode = mode;
} }
private void initDataTreeDialog(int newType, DomainFileFilter newFilter) { private void initializeButtons() {
addOKButton();
if (newType < 0 || newType > CREATE) {
throw new IllegalArgumentException("Invalid type specified: " + newType);
}
this.type = newType;
this.filter = newFilter;
okButton = new JButton("OK");
okButton.setMnemonic('K');
okButton.addActionListener(ev -> okCallback());
addButton(okButton);
addCancelButton(); addCancelButton();
if (newType == SAVE) { if (type == SAVE) {
okButton.setText("Save"); okButton.setText("Save");
okButton.setMnemonic('S'); okButton.setMnemonic('S');
} }
else if (newType == CREATE) { else if (type == CREATE) {
okButton.setText("Create"); okButton.setText("Create");
okButton.setMnemonic('C'); okButton.setMnemonic('C');
} }
setOkEnabled(false);
rootPanel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
setFocusComponent(nameField);
createActions();
} }
private void createActions() { private void createActions() {
@ -223,7 +214,6 @@ public class DataTreeDialog extends DialogComponentProvider
} }
public void show() { public void show() {
doSetup();
DockingWindowManager.showDialog(parent, this); DockingWindowManager.showDialog(parent, this);
} }
@ -235,79 +225,13 @@ public class DataTreeDialog extends DialogComponentProvider
show(); show();
} }
@Override
protected void dialogShown() {
if (!comboModelInitialized) {
doSetup();
}
}
private void doSetup() {
addWorkPanel(buildMainPanel());
comboModelInitialized = true;
// repopulate the tree
ProjectData pd = project.getProjectData();
treePanel.setProjectData(project.getName(), pd);
String nameFieldText = pendingNameText == null ? "" : pendingNameText;
pendingNameText = null;
initializeSelectedFolder();
setFocusComponent(nameField);
if (type == OPEN) {
domainFolder = null;
nameField.setText(nameFieldText);
nameField.selectAll();
populateProjectModel();
// the name field is disabled; use the filter field
setFocusComponent(treePanel.getFilterField());
}
else if (type == SAVE) {
nameField.setText(nameFieldText);
nameField.selectAll();
initializeSelectedFolder();
}
else if (type == CREATE) {
nameField.setText(nameFieldText);
nameField.selectAll();
initializeSelectedFolder();
}
else { // CHOOSE_FOLDER
setFocusComponent(treePanel.getFilterField());
}
setOkEnabled(!nameFieldText.isEmpty());
if (searchString != null) {
findAndSelect(searchString);
}
clearStatusText();
}
private void initializeSelectedFolder() {
if (pendingDomainFolder != null) {
// set the explicitly requested folder to be selected
treePanel.selectDomainFolder(pendingDomainFolder);
pendingDomainFolder = null;
}
else {
// default case--make sure we have a folder selected
domainFolder = treePanel.getSelectedDomainFolder();
if (domainFolder == null) {
treePanel.selectRootDataFolder();
}
}
}
public String getNameText() { public String getNameText() {
return nameField.getText(); return nameField.getText();
} }
public void setNameText(String name) { public void setNameText(String name) {
pendingNameText = name; nameField.setText(name.trim());
nameField.selectAll();
} }
/** /**
@ -316,7 +240,9 @@ public class DataTreeDialog extends DialogComponentProvider
* @param folder {@link DomainFolder} to select when showing the dialog * @param folder {@link DomainFolder} to select when showing the dialog
*/ */
public void setSelectedFolder(DomainFolder folder) { public void setSelectedFolder(DomainFolder folder) {
pendingDomainFolder = folder; if (folder != null) {
treePanel.selectDomainFolder(folder);
}
} }
/** /**
@ -474,7 +400,6 @@ public class DataTreeDialog extends DialogComponentProvider
treePanel.dispose(); treePanel.dispose();
} }
treePanel = null; treePanel = null;
comboModelInitialized = false;
} }
protected JPanel buildMainPanel() { protected JPanel buildMainPanel() {
@ -482,19 +407,26 @@ public class DataTreeDialog extends DialogComponentProvider
JPanel panel = new JPanel(); JPanel panel = new JPanel();
panel.setLayout(new BorderLayout()); panel.setLayout(new BorderLayout());
JPanel namePanel = createNamePanel();
// data tree panel must be created before the combo box // data tree panel must be created before the combo box
JPanel dataTreePanel = createDataTreePanel(); JPanel dataTreePanel = createDataTreePanel();
ProjectData pd = project.getProjectData();
treePanel.setProjectData(project.getName(), pd);
treePanel.selectRootDataFolder();
if (type == OPEN) { if (type == OPEN) {
JPanel comboPanel = createComboBoxPanel(); JPanel comboPanel = createComboBoxPanel();
panel.add(comboPanel, BorderLayout.NORTH); panel.add(comboPanel, BorderLayout.NORTH);
populateProjectModel();
} }
panel.add(dataTreePanel, BorderLayout.CENTER);
JPanel namePanel = createNamePanel(); panel.add(dataTreePanel, BorderLayout.CENTER);
panel.add(namePanel, BorderLayout.SOUTH); panel.add(namePanel, BorderLayout.SOUTH);
// can't add tree listeners until everything is built
addTreeListeners();
return panel; return panel;
} }
@ -537,7 +469,9 @@ public class DataTreeDialog extends DialogComponentProvider
treePanel.addTreeSelectionListener(this); treePanel.addTreeSelectionListener(this);
treePanel.setPreferredTreePanelSize(new Dimension(150, 150)); treePanel.setPreferredTreePanelSize(new Dimension(150, 150));
addTreeListeners(); // don't put the filter in the dialog when the user can/must type a name, as it's confusing
boolean userChoosesName = (type == SAVE) || (type == CREATE);
treePanel.setTreeFilterEnabled(!userChoosesName);
panel.add(treePanel, BorderLayout.CENTER); panel.add(treePanel, BorderLayout.CENTER);
return panel; return panel;
@ -633,9 +567,6 @@ public class DataTreeDialog extends DialogComponentProvider
nameField.setEditable(userChoosesName); nameField.setEditable(userChoosesName);
nameField.setEnabled(userChoosesName); nameField.setEnabled(userChoosesName);
// don't put the filter in the dialog when the user can/must type a name, as it's confusing
treePanel.setTreeFilterEnabled(!userChoosesName);
JPanel namePanel = new JPanel(new PairLayout(2, 5, 100)); JPanel namePanel = new JPanel(new PairLayout(2, 5, 100));
if (!userChoosesName) { if (!userChoosesName) {
@ -688,12 +619,24 @@ public class DataTreeDialog extends DialogComponentProvider
map = null; map = null;
} }
public void findAndSelect(String s) { public void setSearchText(String s) {
treePanel.findAndSelect(s); if (searchString != null) {
treePanel.findAndSelect(s);
}
} }
public void setSearchText(String string) { private static DomainFileFilter getDefaultFilter(int type) {
searchString = string; if (type == CHOOSE_FOLDER || type == OPEN) {
// return filter which forces folder selection and allow navigation into linked-folders
return new DomainFileFilter() {
@Override
public boolean accept(DomainFile df) {
return true; // show all files (legacy behavior)
}
};
}
return null;
} }
private class FieldKeyListener extends KeyAdapter { private class FieldKeyListener extends KeyAdapter {
@ -702,4 +645,5 @@ public class DataTreeDialog extends DialogComponentProvider
clearStatusText(); clearStatusText();
} }
} }
} }

View file

@ -79,9 +79,20 @@ public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDia
super(tool.getToolFrame(), title, DataTreeDialog.OPEN, f -> { super(tool.getToolFrame(), title, DataTreeDialog.OPEN, f -> {
return domainObjectClass.isAssignableFrom(f.getDomainObjectClass()); return domainObjectClass.isAssignableFrom(f.getDomainObjectClass());
}); });
this.tool = tool; this.tool = tool;
this.domainObjectClass = domainObjectClass; this.domainObjectClass = domainObjectClass;
init(); updateOkTooltip();
checkIfHistoryWasOpen();
}
private void checkIfHistoryWasOpen() {
String showHistory =
Preferences.getProperty(SHOW_HISTORY_PREFERENCES_KEY, Boolean.FALSE.toString(), true);
if (Boolean.parseBoolean(showHistory)) {
showHistoryPanel(true);
}
} }
/** /**
@ -164,6 +175,10 @@ public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDia
@Override @Override
protected JPanel buildMainPanel() { protected JPanel buildMainPanel() {
historyButton = new JButton("History>>");
historyButton.addActionListener(e -> showHistoryPanel(!historyIsShowing));
rootPanel.setPreferredSize(getPreferredSizeForHistoryState());
mainPanel = new JPanel(new BorderLayout()); mainPanel = new JPanel(new BorderLayout());
mainPanel.add(super.buildMainPanel(), BorderLayout.CENTER); mainPanel.add(super.buildMainPanel(), BorderLayout.CENTER);
@ -183,18 +198,9 @@ public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDia
JPanel projectFilePanel = new JPanel(new BorderLayout()); JPanel projectFilePanel = new JPanel(new BorderLayout());
projectFilePanel.add(splitPane); projectFilePanel.add(splitPane);
String showHistory =
Preferences.getProperty(SHOW_HISTORY_PREFERENCES_KEY, Boolean.FALSE.toString(), true);
if (Boolean.parseBoolean(showHistory)) {
showHistoryPanel(true);
}
openObjectsTable = null; openObjectsTable = null;
tabbedPane = null; tabbedPane = null;
updateOkTooltip();
if (openDomainObjects == null) { if (openDomainObjects == null) {
return projectFilePanel; // return Project File selection panel only return projectFilePanel; // return Project File selection panel only
} }
@ -245,7 +251,7 @@ public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDia
openObjectsTable = new GFilterTable<>(new OpenObjectsTableModel()); openObjectsTable = new GFilterTable<>(new OpenObjectsTableModel());
GTable table = openObjectsTable.getTable(); GTable table = openObjectsTable.getTable();
table.getSelectionModel() table.getSelectionModel()
.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); .setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
openObjectsTable.addSelectionListener(e -> { openObjectsTable.addSelectionListener(e -> {
setOkEnabled(true); setOkEnabled(true);
okButton.setToolTipText("Use the selected " + domainObjectClass.getSimpleName()); okButton.setToolTipText("Use the selected " + domainObjectClass.getSimpleName());
@ -376,13 +382,6 @@ public class OpenVersionedFileDialog<T extends DomainObject> extends DataTreeDia
return true; return true;
} }
private void init() {
historyButton = new JButton("History>>");
historyButton.addActionListener(e -> showHistoryPanel(!historyIsShowing));
rootPanel.setPreferredSize(getPreferredSizeForHistoryState());
}
@Override @Override
protected void addTreeListeners() { protected void addTreeListeners() {
super.addTreeListeners(); super.addTreeListeners();

View file

@ -665,8 +665,12 @@ public class DiffTestAdapter extends AbstractGhidraHeadedIntegrationTest {
void pickSecondProgram(final Program program2) { void pickSecondProgram(final Program program2) {
OpenVersionedFileDialogTestFake dialog = new OpenVersionedFileDialogTestFake(program2); OpenVersionedFileDialogTestFake dialog = runSwing(() -> {
diffPlugin.setDiffOpenVersionedFileDialog(dialog); OpenVersionedFileDialogTestFake openDialog =
new OpenVersionedFileDialogTestFake(program2);
diffPlugin.setDiffOpenVersionedFileDialog(openDialog);
return openDialog;
});
launchDiffByAction(); launchDiffByAction();