mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
Merge remote-tracking branch
'origin/GP-5964-dragonmacher-file-chooser-accessibility--SQUASHED' (Closes #6310, Closes #7129, Closes #7130)
This commit is contained in:
commit
5fbb052b28
6 changed files with 272 additions and 148 deletions
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -27,7 +27,7 @@ import docking.action.DockingActionIf;
|
|||
import ghidra.docking.util.LookAndFeelUtils;
|
||||
import ghidra.util.StringUtilities;
|
||||
|
||||
class DockingToolBarUtils {
|
||||
public class DockingToolBarUtils {
|
||||
|
||||
private static final String START_KEYBINDING_TEXT = "<BR><HR><CENTER>(";
|
||||
private static final String END_KEYBINDNIG_TEXT = ")</CENTER>";
|
||||
|
@ -37,16 +37,25 @@ class DockingToolBarUtils {
|
|||
* @param button the button
|
||||
* @param action the action
|
||||
*/
|
||||
static void setToolTipText(JButton button, DockingActionIf action) {
|
||||
public static void setToolTipText(JButton button, DockingActionIf action) {
|
||||
String text = createToolTipText(button, action);
|
||||
button.setToolTipText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates tooltip text for the given action and button. This is intended to be used for
|
||||
* buttons that represent the given action.
|
||||
* @param button the button that is the target for the text
|
||||
* @param action the action that is the source of the button
|
||||
* @return the text
|
||||
*/
|
||||
public static String createToolTipText(JButton button, DockingActionIf action) {
|
||||
String toolTipText = getToolTipText(action);
|
||||
String keyBindingText = getKeyBindingAcceleratorText(button, action.getKeyBinding());
|
||||
if (keyBindingText != null) {
|
||||
button.setToolTipText(combingToolTipTextWithKeyBinding(toolTipText, keyBindingText));
|
||||
}
|
||||
else {
|
||||
button.setToolTipText(toolTipText);
|
||||
return combingToolTipTextWithKeyBinding(toolTipText, keyBindingText);
|
||||
}
|
||||
return toolTipText;
|
||||
}
|
||||
|
||||
private static String combingToolTipTextWithKeyBinding(String toolTipText,
|
||||
|
|
|
@ -130,7 +130,7 @@ public class EmptyBorderButton extends JButton {
|
|||
|
||||
@Override
|
||||
public void setBorder(Border border) {
|
||||
// To keep UI from installing a non-appropriate border (such as when switching themes),
|
||||
// To keep UI from installing an incorrect border (such as when switching themes),
|
||||
// only allow borders created by this class to be set.
|
||||
if (border == RAISED_BUTTON_BORDER || border == LOWERED_BUTTON_BORDER ||
|
||||
border == FOCUSED_BUTTON_BORDER || border == NO_BUTTON_BORDER) {
|
||||
|
@ -171,6 +171,12 @@ public class EmptyBorderButton extends JButton {
|
|||
setBorder(NO_BUTTON_BORDER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean b) {
|
||||
setBorder(NO_BUTTON_BORDER);
|
||||
super.setEnabled(b);
|
||||
}
|
||||
|
||||
protected void updateBorderBasedOnState() {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -15,36 +15,45 @@
|
|||
*/
|
||||
package docking.widgets.filechooser;
|
||||
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.Color;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.io.File;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import generic.theme.GColor;
|
||||
import generic.theme.GThemeDefaults.Colors;
|
||||
|
||||
public class FileChooserToggleButton extends JToggleButton {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
static final Border RAISED_BORDER = BorderFactory.createCompoundBorder(
|
||||
BorderFactory.createRaisedBevelBorder(),
|
||||
BorderFactory.createEmptyBorder(1, 1, 1, 1));
|
||||
//
|
||||
// All border sizes are based on trial-and-error, adjusted to prevent the UI from moving as the
|
||||
// user hovers and moves around with the keyboard.
|
||||
//
|
||||
private static final Border RAISED_BORDER = BorderFactory.createCompoundBorder(
|
||||
BorderFactory.createRaisedBevelBorder(), BorderFactory.createEmptyBorder(2, 2, 2, 2));
|
||||
|
||||
static final Border NO_BORDER = new EmptyBorder(RAISED_BORDER.getBorderInsets(new JButton()));
|
||||
private static final Border LOWERED_BORDER = BorderFactory.createCompoundBorder(
|
||||
BorderFactory.createLoweredBevelBorder(), BorderFactory.createEmptyBorder(2, 2, 2, 2));
|
||||
|
||||
static final Border LOWERED_BORDER = BorderFactory.createCompoundBorder(
|
||||
BorderFactory.createLoweredBevelBorder(),
|
||||
BorderFactory.createEmptyBorder(1, 1, 1, 1));
|
||||
// The focused border is a blue line with some padding on the outside so it is easy to see when
|
||||
// the button has focus. This is similar to other buttons in the system.
|
||||
private static final Color FOCUS_COLOR = new GColor("color.border.button.focused");
|
||||
private static final Border FOCUSED_BORDER = BorderFactory.createCompoundBorder(
|
||||
BorderFactory.createEmptyBorder(1, 1, 1, 1), BorderFactory.createLineBorder(FOCUS_COLOR));
|
||||
private static final Border UNFOCUSED_BORDER = BorderFactory.createEmptyBorder(2, 2, 2, 2);
|
||||
|
||||
public FileChooserToggleButton(String text) {
|
||||
private static final Border NO_BORDER = new EmptyBorder(4, 4, 4, 4);
|
||||
|
||||
private GhidraFileChooser fileChooser;
|
||||
|
||||
public FileChooserToggleButton(String text, GhidraFileChooser fileChooser) {
|
||||
super(text);
|
||||
initBorder();
|
||||
}
|
||||
|
||||
public FileChooserToggleButton(Action action) {
|
||||
super(action);
|
||||
this.fileChooser = fileChooser;
|
||||
initBorder();
|
||||
}
|
||||
|
||||
|
@ -59,88 +68,92 @@ public class FileChooserToggleButton extends JToggleButton {
|
|||
setContentAreaFilled(false);
|
||||
|
||||
// changes the border on hover and click
|
||||
addMouseListener(new ButtonMouseListener());
|
||||
addChangeListener(new ButtonStateListener());
|
||||
|
||||
// works in conjunction with the mouse listener to properly set the border
|
||||
addChangeListener(e -> {
|
||||
if (isSelected()) {
|
||||
setBorder(LOWERED_BORDER);
|
||||
}
|
||||
else {
|
||||
setBorder(NO_BORDER);
|
||||
}
|
||||
});
|
||||
addChangeListener(e -> updateBorderBasedOnState());
|
||||
|
||||
setFocusable(false); // this prevents the focus box from being drawn over the button
|
||||
addFocusListener(new ButtonFocusListener());
|
||||
|
||||
updateBorderBasedOnState();
|
||||
}
|
||||
|
||||
void clearBorder() {
|
||||
@Override
|
||||
public void setBorder(Border border) {
|
||||
// To keep UI from installing an incorrect border (such as when switching themes),
|
||||
// only allow borders created by this class to be set.
|
||||
if (border == RAISED_BORDER || border == LOWERED_BORDER || border == NO_BORDER ||
|
||||
border instanceof FocusedBorder) {
|
||||
super.setBorder(border);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearBorder() {
|
||||
setBorder(NO_BORDER);
|
||||
}
|
||||
|
||||
/** Returns the directory with which this button is associated. */
|
||||
/** {@return Returns the directory with which this button is associated.} */
|
||||
File getFile() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private class ButtonMouseListener extends MouseAdapter {
|
||||
private boolean inside = false;
|
||||
private void updateBorderBasedOnState() {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
private Border defaultBorder;
|
||||
ButtonModel buttonModel = getModel();
|
||||
boolean pressed = buttonModel.isPressed();
|
||||
boolean rollover = buttonModel.isRollover();
|
||||
boolean armed = buttonModel.isArmed();
|
||||
boolean selected = buttonModel.isSelected();
|
||||
|
||||
Border border = NO_BORDER;
|
||||
|
||||
if (selected) {
|
||||
border = LOWERED_BORDER;
|
||||
}
|
||||
else if (pressed && (rollover || armed)) {
|
||||
border = LOWERED_BORDER;
|
||||
}
|
||||
else if (rollover) {
|
||||
border = RAISED_BORDER;
|
||||
}
|
||||
|
||||
border = createFocusedBorder(border, isFocusOwner());
|
||||
|
||||
setBorder(border);
|
||||
}
|
||||
|
||||
private Border createFocusedBorder(Border outside, boolean isFocused) {
|
||||
Border inside = isFocused ? FOCUSED_BORDER : UNFOCUSED_BORDER;
|
||||
return new FocusedBorder(outside, inside);
|
||||
}
|
||||
|
||||
private class ButtonStateListener implements ChangeListener {
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
updateBorderBasedOnState();
|
||||
}
|
||||
}
|
||||
|
||||
private class ButtonFocusListener implements FocusListener {
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent me) {
|
||||
if (isSelected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
defaultBorder = getBorder();
|
||||
setBorder(RAISED_BORDER);
|
||||
inside = true;
|
||||
public void focusGained(FocusEvent e) {
|
||||
updateBorderBasedOnState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent me) {
|
||||
if (isSelected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
inside = false;
|
||||
restoreBorder();
|
||||
public void focusLost(FocusEvent e) {
|
||||
updateBorderBasedOnState();
|
||||
fileChooser.updateShortcutPanel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (isSelected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.getButton() == MouseEvent.BUTTON1) {
|
||||
setBorder(LOWERED_BORDER);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
if (isSelected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (inside) {
|
||||
setBorder(RAISED_BORDER);
|
||||
}
|
||||
else {
|
||||
restoreBorder();
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreBorder() {
|
||||
if (defaultBorder != null) {
|
||||
setBorder(defaultBorder);
|
||||
}
|
||||
else {
|
||||
setBorder(NO_BORDER);
|
||||
}
|
||||
private class FocusedBorder extends CompoundBorder {
|
||||
FocusedBorder(Border outsideBorder, Border insideBorder) {
|
||||
super(outsideBorder, insideBorder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -19,7 +19,6 @@ import javax.swing.*;
|
|||
|
||||
import docking.ReusableDialogComponentProvider;
|
||||
import docking.widgets.checkbox.GCheckBox;
|
||||
import docking.widgets.label.GLabel;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.util.layout.PairLayout;
|
||||
|
||||
|
@ -47,17 +46,13 @@ class GFileChooserOptionsDialog extends ReusableDialogComponentProvider {
|
|||
private JComponent buildComponent() {
|
||||
JPanel panel = new JPanel(new PairLayout());
|
||||
|
||||
showDotFilesCheckBox = new GCheckBox();
|
||||
showDotFilesCheckBox = new GCheckBox("Show '.' files");
|
||||
showDotFilesCheckBox.setToolTipText("When toggled on the file chooser will show files " +
|
||||
"with names that begin with a '.' character");
|
||||
showDotFilesCheckBox.getAccessibleContext().setAccessibleName("Show Dot Files");
|
||||
showDotFilesCheckBox.setSelected(true);
|
||||
|
||||
JLabel label = new GLabel("Show '.' files");
|
||||
label.getAccessibleContext().setAccessibleName("Show Files");
|
||||
label.setToolTipText("When toggled on the file chooser will show files " +
|
||||
"with names that begin with a '.' character");
|
||||
|
||||
panel.add(showDotFilesCheckBox);
|
||||
panel.add(label);
|
||||
panel.getAccessibleContext().setAccessibleName("GFile Chooser Options");
|
||||
return panel;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ package docking.widgets.filechooser;
|
|||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.util.*;
|
||||
|
@ -35,7 +37,11 @@ import javax.swing.text.DefaultFormatterFactory;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.*;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.action.builder.ActionBuilder;
|
||||
import docking.actions.KeyBindingUtils;
|
||||
import docking.menu.DockingToolBarUtils;
|
||||
import docking.widgets.*;
|
||||
import docking.widgets.combobox.GComboBox;
|
||||
import docking.widgets.label.GDLabel;
|
||||
|
@ -166,13 +172,19 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
|
||||
private Component parent;
|
||||
private JPanel waitPanel;
|
||||
private EmptyBorderButton backButton;
|
||||
private EmptyBorderButton forwardButton;
|
||||
private EmptyBorderButton upLevelButton;
|
||||
private EmptyBorderButton newFolderButton;
|
||||
private EmptyBorderButton refreshButton;
|
||||
private JButton backButton;
|
||||
private JButton forwardButton;
|
||||
private JButton upButton;
|
||||
private JButton newFolderButton;
|
||||
private JButton refreshButton;
|
||||
private EmptyBorderToggleButton detailsButton;
|
||||
|
||||
private DockingAction upAction;
|
||||
private DockingAction backAction;
|
||||
private DockingAction forwardAction;
|
||||
private KeyBindingChangeListener keyBindingChangeListener = new KeyBindingChangeListener();
|
||||
|
||||
private JPanel shortcutPanel;
|
||||
private UnselectableButtonGroup shortCutButtonGroup;
|
||||
private FileChooserToggleButton myComputerButton;
|
||||
private FileChooserToggleButton desktopButton;
|
||||
|
@ -261,12 +273,43 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
setPreferredSize(800, 600);
|
||||
|
||||
updateDirOnly(newModel.getHomeDirectory(), true);
|
||||
|
||||
createActions();
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Setup Methods
|
||||
//==================================================================================================
|
||||
|
||||
private void createActions() {
|
||||
|
||||
String owner = getClass().getSimpleName();
|
||||
upAction = new ActionBuilder("Up One Level", owner)
|
||||
.keyBinding("Alt Up")
|
||||
.onAction(c -> goUp())
|
||||
.build();
|
||||
|
||||
backAction = new ActionBuilder("Last Folder Visited", owner)
|
||||
.keyBinding("Alt Left")
|
||||
.onAction(c -> goBack())
|
||||
.build();
|
||||
|
||||
forwardAction = new ActionBuilder("Previous Folder Visited", owner)
|
||||
.keyBinding("Alt Right")
|
||||
.onAction(c -> goForward())
|
||||
.build();
|
||||
|
||||
upAction.addPropertyChangeListener(keyBindingChangeListener);
|
||||
backAction.addPropertyChangeListener(keyBindingChangeListener);
|
||||
forwardAction.addPropertyChangeListener(keyBindingChangeListener);
|
||||
|
||||
addAction(upAction);
|
||||
addAction(backAction);
|
||||
addAction(forwardAction);
|
||||
|
||||
updateNavigationButtonToolTips();
|
||||
}
|
||||
|
||||
private JComponent buildWorkPanel() {
|
||||
buildWaitPanel();
|
||||
|
||||
|
@ -302,7 +345,8 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
}
|
||||
|
||||
private JPanel buildShortCutPanel() {
|
||||
myComputerButton = new FileChooserToggleButton("My Computer") {
|
||||
|
||||
myComputerButton = new FileChooserToggleButton("My Computer", this) {
|
||||
@Override
|
||||
File getFile() {
|
||||
return MY_COMPUTER;
|
||||
|
@ -314,7 +358,7 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
myComputerButton.addActionListener(e -> updateMyComputer());
|
||||
myComputerButton.setForeground(FOREROUND_COLOR);
|
||||
|
||||
desktopButton = new FileChooserToggleButton("Desktop") {
|
||||
desktopButton = new FileChooserToggleButton("Desktop", this) {
|
||||
@Override
|
||||
File getFile() {
|
||||
return fileChooserModel.getDesktopDirectory();
|
||||
|
@ -327,7 +371,7 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
desktopButton.setForeground(FOREROUND_COLOR);
|
||||
desktopButton.setEnabled(fileChooserModel.getDesktopDirectory() != null);
|
||||
|
||||
homeButton = new FileChooserToggleButton("Home") {
|
||||
homeButton = new FileChooserToggleButton("Home", this) {
|
||||
@Override
|
||||
File getFile() {
|
||||
return fileChooserModel.getHomeDirectory();
|
||||
|
@ -339,7 +383,7 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
homeButton.addActionListener(e -> updateHome());
|
||||
homeButton.setForeground(FOREROUND_COLOR);
|
||||
|
||||
downloadsButton = new FileChooserToggleButton("Downloads") {
|
||||
downloadsButton = new FileChooserToggleButton("Downloads", this) {
|
||||
@Override
|
||||
File getFile() {
|
||||
return fileChooserModel.getDownloadsDirectory();
|
||||
|
@ -350,7 +394,7 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
downloadsButton.addActionListener(e -> updateDownloads());
|
||||
downloadsButton.setForeground(FOREROUND_COLOR);
|
||||
|
||||
recentButton = new FileChooserToggleButton("Recent") {
|
||||
recentButton = new FileChooserToggleButton("Recent", this) {
|
||||
@Override
|
||||
File getFile() {
|
||||
return RECENT;
|
||||
|
@ -369,27 +413,30 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
shortCutButtonGroup.add(downloadsButton);
|
||||
shortCutButtonGroup.add(recentButton);
|
||||
|
||||
JPanel shortCutPanel = new JPanel(new GridLayout(0, 1));
|
||||
shortCutPanel.getAccessibleContext().setAccessibleName("Short Cut");
|
||||
DockingUtils.setTransparent(shortCutPanel);
|
||||
shortCutPanel.add(myComputerButton);
|
||||
shortCutPanel.add(desktopButton);
|
||||
shortCutPanel.add(homeButton);
|
||||
shortCutPanel.add(downloadsButton);
|
||||
shortCutPanel.add(recentButton);
|
||||
shortcutPanel = new JPanel(new GridLayout(0, 1));
|
||||
shortcutPanel.getAccessibleContext().setAccessibleName("Short Cut");
|
||||
DockingUtils.setTransparent(shortcutPanel);
|
||||
shortcutPanel.add(myComputerButton);
|
||||
shortcutPanel.add(desktopButton);
|
||||
shortcutPanel.add(homeButton);
|
||||
shortcutPanel.add(downloadsButton);
|
||||
shortcutPanel.add(recentButton);
|
||||
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(BorderFactory.createLoweredBevelBorder());
|
||||
panel.setBackground(SHORTCUT_BACKGROUND_COLOR);
|
||||
panel.add(shortCutPanel, BorderLayout.NORTH);
|
||||
panel.add(shortcutPanel, BorderLayout.NORTH);
|
||||
panel.getAccessibleContext().setAccessibleName("Short Cut");
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
private JPanel buildFileNamePanel() {
|
||||
JLabel filenameLabel = new GDLabel("File name:");
|
||||
JLabel filenameLabel = new GDLabel("Filename:");
|
||||
|
||||
FileDropDownSelectionDataModel model = new FileDropDownSelectionDataModel(this);
|
||||
filenameTextField = new DropDownSelectionTextField<>(model);
|
||||
filenameLabel.setLabelFor(filenameTextField);
|
||||
filenameTextField.setMatchingWindowHeight(200);
|
||||
filenameTextField.getAccessibleContext().setAccessibleName("Filename");
|
||||
filenameTextField.addCellEditorListener(new CellEditorListener() {
|
||||
|
@ -427,9 +474,10 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
JLabel filterLabel = new GLabel("Type:");
|
||||
filterLabel.getAccessibleContext().setAccessibleName("Filter");
|
||||
filterCombo = new GComboBox<>();
|
||||
filterLabel.setLabelFor(filterCombo);
|
||||
filterCombo.setRenderer(GListCellRenderer.createDefaultTextRenderer(
|
||||
fileFilter -> fileFilter != null ? fileFilter.getDescription() : ""));
|
||||
filterCombo.getAccessibleContext().setAccessibleName("Filter");
|
||||
filterCombo.getAccessibleContext().setAccessibleName("File Type Filter");
|
||||
filterModel = (DefaultComboBoxModel<GhidraFileFilter>) filterCombo.getModel();
|
||||
addFileFilter(GhidraFileFilter.ALL);
|
||||
filterCombo.addItemListener(e -> rescanCurrentDirectory());
|
||||
|
@ -444,22 +492,12 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
return filenamePanel;
|
||||
}
|
||||
|
||||
private class SelectionListener<T> implements DropDownSelectionChoiceListener<File> {
|
||||
|
||||
@Override
|
||||
public void selectionChanged(File file) {
|
||||
// take the selection and close the dialog
|
||||
worker.schedule(new SetSelectedFileAndAcceptSelection(file));
|
||||
}
|
||||
}
|
||||
|
||||
private JPanel buildHeaderPanel() {
|
||||
|
||||
JPanel headerPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
|
||||
gbc.gridx = 0;
|
||||
// gbc.insets = new Insets(PAD, PAD, PAD, PAD);
|
||||
JButton[] navButtons = buildNavigationButtons();
|
||||
for (JButton element : navButtons) {
|
||||
headerPanel.add(element, gbc);
|
||||
|
@ -613,6 +651,7 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
}
|
||||
|
||||
private JButton[] buildNavigationButtons() {
|
||||
|
||||
backButton = new EmptyBorderButton(ICON_BACK);
|
||||
backButton.setName("BACK_BUTTON");
|
||||
backButton.setEnabled(false);
|
||||
|
@ -625,12 +664,13 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
forwardButton.setToolTipText("Go to previous folder visited");
|
||||
forwardButton.addActionListener(e -> goForward());
|
||||
|
||||
upLevelButton = new EmptyBorderButton(ICON_UP);
|
||||
upLevelButton.setName(UP_BUTTON_NAME);
|
||||
upLevelButton.setToolTipText("Up one level");
|
||||
upLevelButton.addActionListener(e -> goUpOneDirectoryLevel());
|
||||
upButton = new EmptyBorderButton(ICON_UP);
|
||||
upButton.setName(UP_BUTTON_NAME);
|
||||
upButton.setEnabled(false);
|
||||
upButton.setToolTipText("Up one level");
|
||||
upButton.addActionListener(e -> goUp());
|
||||
|
||||
return new JButton[] { backButton, forwardButton, upLevelButton };
|
||||
return new JButton[] { backButton, forwardButton, upButton };
|
||||
}
|
||||
|
||||
private JButton[] buildNonNavigationButtons() {
|
||||
|
@ -1382,15 +1422,17 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
}
|
||||
|
||||
private void doSetSelectedFileAndUpdateDisplay(File file) {
|
||||
if (lastInputFocus != null) {
|
||||
lastInputFocus.requestFocusInWindow();
|
||||
|
||||
Component toFocus = getRestoreFocusComponent();
|
||||
if (toFocus != null) {
|
||||
toFocus.requestFocusInWindow();
|
||||
}
|
||||
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// SCR 4513 - exception if we don't cancel edits before changing the display
|
||||
// exception if we don't cancel edits before changing the display
|
||||
cancelEdits();
|
||||
selectedFiles.setFile(file);
|
||||
updateTextFieldForFile(file);
|
||||
|
@ -1398,6 +1440,22 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
directoryModel.setSelectedFile(file); // the list or table display
|
||||
}
|
||||
|
||||
private Component getRestoreFocusComponent() {
|
||||
// ensure we transfer focus to the directory or table when the view switches
|
||||
if (isTableShowing()) {
|
||||
if (lastInputFocus == directoryList) {
|
||||
lastInputFocus = directoryTable;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (lastInputFocus == directoryTable) {
|
||||
lastInputFocus = directoryList;
|
||||
}
|
||||
}
|
||||
|
||||
return lastInputFocus;
|
||||
}
|
||||
|
||||
private void updateTextFieldForFile(File file) {
|
||||
if (file == null) {
|
||||
return;
|
||||
|
@ -1452,7 +1510,7 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
return false;
|
||||
}
|
||||
|
||||
private void goUpOneDirectoryLevel() {
|
||||
private void goUp() {
|
||||
cancelEdits();
|
||||
|
||||
if (currentDirectory() == null) {
|
||||
|
@ -1521,8 +1579,16 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
updateDirAndSelectFile(currentDir, currentSelectedFile, true, false);
|
||||
}
|
||||
|
||||
private void updateShortcutPanel() {
|
||||
// make sure that if one of the shortcut buttons is selected, the directory matches that button
|
||||
void updateShortcutPanel() {
|
||||
|
||||
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||
Component focusOwner = kfm.getFocusOwner();
|
||||
if (focusOwner != null && !SwingUtilities.isDescendingFrom(focusOwner, shortcutPanel)) {
|
||||
// only synchronize the button state if the user is not interacting with the buttons
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure the selected button matches the current directory
|
||||
File currentDirectory = currentDirectory();
|
||||
checkShortCutButton(myComputerButton, currentDirectory);
|
||||
checkShortCutButton(homeButton, currentDirectory);
|
||||
|
@ -1556,13 +1622,24 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
history.clear();
|
||||
}
|
||||
|
||||
private void updateNavigationButtonToolTips() {
|
||||
String tip = DockingToolBarUtils.createToolTipText(backButton, backAction);
|
||||
backButton.setToolTipText(tip);
|
||||
|
||||
tip = DockingToolBarUtils.createToolTipText(forwardButton, forwardAction);
|
||||
forwardButton.setToolTipText(tip);
|
||||
|
||||
tip = DockingToolBarUtils.createToolTipText(upButton, upAction);
|
||||
upButton.setToolTipText(tip);
|
||||
}
|
||||
|
||||
private void updateNavigationButtons() {
|
||||
backButton.setEnabled(history.hasPrevious());
|
||||
forwardButton.setEnabled(history.hasNext());
|
||||
|
||||
File dir = currentDirectory();
|
||||
boolean enable = dir != null && dir.getParentFile() != null;
|
||||
upLevelButton.setEnabled(enable);
|
||||
upButton.setEnabled(enable);
|
||||
}
|
||||
|
||||
private void updateHistoryWithSelectedFiles(HistoryEntry historyEntry) {
|
||||
|
@ -2235,7 +2312,7 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
public void runSwing() {
|
||||
setDirectoryList(myComputerFile, roots);
|
||||
setWaitPanelVisible(false);
|
||||
Swing.runLater(() -> doSetSelectedFileAndUpdateDisplay(null));
|
||||
setSelectedFileAndUpdateDisplay(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2254,6 +2331,7 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
setCurrentDirectoryDisplay(recentFile, addToHistory);
|
||||
List<File> list = CollectionUtils.asList(recentList, File.class);
|
||||
setDirectoryList(recentFile, list);
|
||||
setSelectedFileAndUpdateDisplay(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2430,4 +2508,26 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement
|
|||
return parentDir.getName() + selectedFilesText;
|
||||
}
|
||||
}
|
||||
|
||||
private class SelectionListener<T> implements DropDownSelectionChoiceListener<File> {
|
||||
|
||||
@Override
|
||||
public void selectionChanged(File file) {
|
||||
// take the selection and close the dialog
|
||||
worker.schedule(new SetSelectedFileAndAcceptSelection(file));
|
||||
}
|
||||
}
|
||||
|
||||
private class KeyBindingChangeListener implements PropertyChangeListener {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent e) {
|
||||
String name = e.getPropertyName();
|
||||
if (name.equals(DockingActionIf.KEYBINDING_DATA_PROPERTY)) {
|
||||
updateNavigationButtonToolTips();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue