GT-3547 - Patch dir fix - review fixes

This commit is contained in:
dragonmacher 2020-02-19 18:50:52 -05:00
parent 3dced733df
commit 87bda2b34d
14 changed files with 149 additions and 531 deletions

View file

@ -1,205 +0,0 @@
/* ###
* 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.
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.framework.main;
import java.awt.BorderLayout;
import java.awt.event.*;
import java.io.File;
import javax.swing.*;
import docking.DockingUtils;
import docking.options.editor.ButtonPanelFactory;
import docking.widgets.filechooser.GhidraFileChooser;
/**
* Helper class that restricts the width of the textField to the size of the
* scrolled paths list; also provides the listener for the textfield if user
* presses Enter or Tab in a textfield.
*
*/
class BrowsePathPanel extends JPanel {
private boolean changed;
private GhidraFileChooser fileChooser;
private JTextField pathTextField;
private EditPluginPathDialog dialog;
private JButton browseButton;
/**
* Construct a new BrowsePathPanel.
* @param editDialog parent dialog
* @param sizeComp component to use for size in creating text field
* @param button browse button
* @param dirOnly
* @param textFieldLabel
* @param fieldName name of text field component
*/
BrowsePathPanel(EditPluginPathDialog editDialog, ActionListener buttonListener, String fieldName) {
super();
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
dialog = editDialog;
create(fieldName);
addListeners(buttonListener);
}
/**
* Create the components
* @param sizeComp component to use when creating the text field to get the
* size
* @param textFieldLabel label for the field
*/
private void create(String fieldName) {
pathTextField = new JTextField();
pathTextField.setName(fieldName);
pathTextField.setEditable(false);
pathTextField.setBackground(getBackground());
browseButton = ButtonPanelFactory.createButton(ButtonPanelFactory.BROWSE_TYPE);
browseButton.setToolTipText("Choose Directory");
// construct the panel with text field and browse button
JPanel browsePathPanel = new JPanel(new BorderLayout(5, 5));
browsePathPanel.add(pathTextField, BorderLayout.CENTER);
browsePathPanel.add(browseButton, BorderLayout.EAST);
add(browsePathPanel);
}
private void createFileChooser() {
// create the fileChooser this panel will use based on its input criteria
fileChooser = new GhidraFileChooser(dialog.getComponent());
fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
fileChooser.setFileSelectionMode(GhidraFileChooser.DIRECTORIES_ONLY);
fileChooser.setApproveButtonToolTipText("Choose Directory With Plugin JAR Files");
fileChooser.setApproveButtonText("Choose JAR Directory");
}
/**
* Add listeners.
* @param listener listener for the browse button
*/
private void addListeners(ActionListener listener) {
browseButton.addActionListener(listener);
pathTextField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
// when Esc or Ctrl-C is pressed, reset the plugin
// jar directory to what is saved in preferences
if (keyCode == KeyEvent.VK_ESCAPE ||
(DockingUtils.isControlModifier(e) && keyCode == KeyEvent.VK_C)) {
dialog.initJarDirectory();
}
else {
dialog.setApplyEnabled(true);
}
}
});
}
String getPath() {
return pathTextField.getText().trim();
}
boolean isChanged() {
return changed;
}
@Override
public boolean hasFocus() {
return pathTextField.hasFocus();
}
@Override
public void requestFocus() {
pathTextField.requestFocus();
pathTextField.selectAll();
}
/**
* Pop up the file chooser.
*/
void showFileChooser() {
if (fileChooser == null) {
createFileChooser();
}
// reset the status message
dialog.setStatusMessage(EditPluginPathDialog.EMPTY_STATUS);
File pluginFile = fileChooser.getSelectedFile();
if (pluginFile != null) {
setPath(pluginFile);
}
else {
pathTextField.requestFocus();
pathTextField.selectAll();
}
}
/**
* Set whether something has changed.
* @param changed true if something changed
*/
void setChanged(boolean changed) {
this.changed = changed;
}
/**
* Set the path field.
* @param path filename for the path field
* @return boolean true if the path is valid
*/
private boolean setPath(File path) {
boolean pathOK = false;
dialog.setStatusMessage(EditPluginPathDialog.EMPTY_STATUS);
if (!path.canRead()) {
pathTextField.selectAll();
dialog.setStatusMessage("Cannot read path: " + path.toString());
}
else {
pathTextField.setText(path.getAbsolutePath());
pathOK = (pathTextField.getText().trim().length() > 0);
}
if (pathOK) {
dialog.setStatusMessage("Press Apply or OK to set JAR directory.");
}
changed = changed || pathOK;
dialog.enableApply();
return pathOK;
}
/**
* sets the text of the text field of the panel without
* any error checking
*/
void setText(String text) {
pathTextField.setText(text);
}
}

View file

@ -18,8 +18,6 @@
package ghidra.framework.main;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@ -34,6 +32,7 @@ import javax.swing.event.ListSelectionListener;
import docking.DialogComponentProvider;
import docking.options.editor.ButtonPanelFactory;
import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.filechooser.GhidraFileChooserMode;
import docking.widgets.label.GDLabel;
import docking.widgets.list.GListCellRenderer;
import ghidra.framework.plugintool.PluginTool;
@ -45,20 +44,18 @@ import ghidra.util.filechooser.GhidraFileFilter;
/**
* Dialog for editing the Plugin path and Jar directory path preferences.
*
* <p>The Plugin Path and Jar directory path are locations where Ghidra searches
* for plugins to load. The Plugin Path is specified exactly as a Java Classpath
* is specified. The Jar directory is searched only for Jar files containing
* Plugins. When changes are made to these fields in the dialog, the
* is specified. When changes are made to these fields in the dialog, the
* preferences file is updated and written to disk. The preferences file is
* located in the .ghidra directory in the user's home directory.
* </P>
* <p> The preferences file also contains the last project that was opened,
* and the positions of the Ghidra Project Window and other tools that were
* running when the user last exited Ghidra.
* </P>
*
*/
class EditPluginPathDialog extends DialogComponentProvider {
static final String ADD_DIR_BUTTON_TEXT = "Add Dir ...";
static final String ADD_JAR_BUTTON_TEXT = "Add Jar ...";
private final static int SIDE_MARGIN = 5;
private final static Color INVALID_PATH_COLOR = Color.red.brighter();
private final static Color INVALID_SELECTED_PATH_COLOR = Color.pink;
@ -80,7 +77,6 @@ class EditPluginPathDialog extends DialogComponentProvider {
// gui members needed for dis/enabling and other state-dependent actions
private JScrollPane scrollPane; // need for preferred size when resizing
private JList<String> pluginPathsList;
private BrowsePathPanel jarPathPanel;
private GhidraFileChooser fileChooser;
private JButton upButton;
private JButton downButton;
@ -94,7 +90,6 @@ class EditPluginPathDialog extends DialogComponentProvider {
* Creates a non-modal dialog with OK, Apply, Cancel buttons.
* The OK and Apply buttons will be enabled when user makes unapplied
* changes to the UserPluginPath or UserPluginJarDirectory property values.
* @param parent parent to this dialog
*/
EditPluginPathDialog() {
super("Edit Plugin Path", true, false, true, false);
@ -134,8 +129,6 @@ class EditPluginPathDialog extends DialogComponentProvider {
// subsequent panels
mainPanel.add(buildPluginPathsPanel());
mainPanel.add(Box.createVerticalStrut(10));
mainPanel.add(buildJarDirectoryPanel());
mainPanel.add(Box.createVerticalStrut(10));
mainPanel.add(Box.createVerticalGlue());
mainPanel.add(statusMessagePanel);
mainPanel.invalidate();
@ -147,33 +140,15 @@ class EditPluginPathDialog extends DialogComponentProvider {
return mainPanel;
}
/**
* Gets called when the user selects Apply
*/
@Override
protected void applyCallback() {
// validate the jar path before applying changes, since the user
// is pressing the Apply button to save this setting
String jarPathname = jarPathPanel.getPath();
if (jarPathname.length() > 0) {
File jarPath = new File(jarPathname);
if (!jarPath.isDirectory() || !jarPath.canRead()) {
setStatusMessage("Bad Jar Directory: " + jarPathname);
jarPathPanel.requestFocus();
return;
}
}
// do the things we need to do to handle the applied changes
handleApply();
}
/**
* Gets called when the user selects Cancel
*/
@Override
protected void cancelCallback() {
close();
// reset original state of dialog for next display of dialog
enableButtons(false);
setStatusMessage(EMPTY_STATUS);
@ -181,17 +156,6 @@ class EditPluginPathDialog extends DialogComponentProvider {
errorMsg = null;
}
/**
* if the jar directory field has focus, don't let the base dialog
* handle it.
*/
@Override
protected void escapeCallback() {
if (!jarPathPanel.hasFocus()) {
super.escapeCallback();
}
}
/**
* Gets called when the user selects Ok
*/
@ -206,30 +170,21 @@ class EditPluginPathDialog extends DialogComponentProvider {
}
/**
* re-set the list of paths each time the dialog is shown
* Reset the list of paths each time the dialog is shown
* @param tool the tool
*/
public void show(PluginTool tool) {
setPluginPathsListData(Preferences.getPluginPaths());
initJarDirectory();
setApplyEnabled(pluginPathsChanged);
setStatusMessage(EMPTY_STATUS);
// setting the path enables the apply, but we know we haven't
// made any changes yet, so disable
setApplyEnabled(false);
tool.showDialog(this);
}
/**
* Method enableApply.
*/
void enableApply() {
setApplyEnabled(pluginPathsChanged || jarPathPanel.isChanged());
}
void initJarDirectory() {
setApplyEnabled(pluginPathsChanged);
setStatusMessage(EMPTY_STATUS);
}
void setStatusMessage(String msg) {
private void setStatusMessage(String msg) {
if (msg == null || msg.length() == 0) {
msg = EMPTY_STATUS;
}
@ -237,15 +192,7 @@ class EditPluginPathDialog extends DialogComponentProvider {
statusMessage.invalidate();
}
/**
* @see ghidra.util.bean.GhidraDialog#setApplyEnabled(boolean)
*/
@Override
protected void setApplyEnabled(boolean state) {
super.setApplyEnabled(state);
}
void addJarCallback() {
private void addJarCallback() {
setStatusMessage(EditPluginPathDialog.EMPTY_STATUS);
@ -253,7 +200,7 @@ class EditPluginPathDialog extends DialogComponentProvider {
fileChooser = new GhidraFileChooser(getComponent());
fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
}
fileChooser.setFileSelectionMode(GhidraFileChooser.FILES_ONLY);
fileChooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY);
fileChooser.setFileFilter(JAR_FILTER);
fileChooser.setApproveButtonToolTipText("Choose Plugin Jar File");
fileChooser.setApproveButtonText("Add Jar File");
@ -277,7 +224,7 @@ class EditPluginPathDialog extends DialogComponentProvider {
}
}
void addDirCallback() {
private void addDirCallback() {
setStatusMessage(EditPluginPathDialog.EMPTY_STATUS);
@ -285,7 +232,7 @@ class EditPluginPathDialog extends DialogComponentProvider {
fileChooser = new GhidraFileChooser(getComponent());
fileChooser.setCurrentDirectory(new File(System.getProperty("user.home")));
}
fileChooser.setFileSelectionMode(GhidraFileChooser.DIRECTORIES_ONLY);
fileChooser.setFileSelectionMode(GhidraFileChooserMode.DIRECTORIES_ONLY);
fileChooser.setFileFilter(GhidraFileFilter.ALL);
fileChooser.setApproveButtonToolTipText("Choose Directory with Plugin class Files");
fileChooser.setApproveButtonText("Add Directory");
@ -310,63 +257,31 @@ class EditPluginPathDialog extends DialogComponentProvider {
}
}
/**
* Returns an array of pathnames where plugins can be found; used by custom
* class loader when searching for plugins.
*/
private String[] getUserPluginPaths() {
String[] pluginsArray = new String[listModel.size()];
listModel.copyInto(pluginsArray);
return pluginsArray;
}
/**
* construct the plugin paths button panel
*/
private JPanel buildPluginPathsPanel() {
// create the UP and DOWN arrows panel
upButton = ButtonPanelFactory.createButton(ButtonPanelFactory.ARROW_UP_TYPE);
upButton.setName("UpArrow");
upButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
handleSelection(UP);
}
});
upButton.addActionListener(e -> handleSelection(UP));
downButton = ButtonPanelFactory.createButton(ButtonPanelFactory.ARROW_DOWN_TYPE);
downButton.setName("DownArrow");
downButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
handleSelection(DOWN);
}
});
downButton.addActionListener(e -> handleSelection(DOWN));
JPanel arrowButtonsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 10));
arrowButtonsPanel.add(upButton);
arrowButtonsPanel.add(downButton);
// create the Add and Remove panel
JButton addJarButton = ButtonPanelFactory.createButton("Add Jar...");
addJarButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
addJarCallback();
}
});
JButton addDirButton = ButtonPanelFactory.createButton("Add Dir...");
addDirButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
addDirCallback();
}
});
JButton addJarButton = ButtonPanelFactory.createButton(ADD_JAR_BUTTON_TEXT);
addJarButton.addActionListener(e -> addJarCallback());
JButton addDirButton = ButtonPanelFactory.createButton(ADD_DIR_BUTTON_TEXT);
addDirButton.addActionListener(e -> addDirCallback());
removeButton = ButtonPanelFactory.createButton("Remove");
removeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
handleSelection(REMOVE);
}
});
removeButton.addActionListener(e -> handleSelection(REMOVE));
Dimension d = addJarButton.getPreferredSize();
addDirButton.setPreferredSize(d);
removeButton.setPreferredSize(d);
@ -415,26 +330,6 @@ class EditPluginPathDialog extends DialogComponentProvider {
return pluginPathListPanel;
}
/**
* construct the jar directory panel
*/
private JPanel buildJarDirectoryPanel() {
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
jarPathPanel.showFileChooser();
enableApply();
}
};
jarPathPanel = new BrowsePathPanel(this, listener, "UserPluginJarDirectory");
jarPathPanel.setText(Preferences.getProperty(Preferences.USER_PLUGIN_JAR_DIRECTORY));
jarPathPanel.setBorder(new TitledBorder("User Plugin Jar Directory"));
return jarPathPanel;
}
private void enableButtons(boolean enabled) {
upButton.setEnabled(enabled);
downButton.setEnabled(enabled);
@ -452,22 +347,12 @@ class EditPluginPathDialog extends DialogComponentProvider {
// update Ghidra Preferences with new paths
Preferences.setPluginPaths(userPluginPaths);
// Get user Jar directory
String jarDirectoryName = jarPathPanel.getPath();
if (jarDirectoryName.trim().length() == 0) {
jarDirectoryName = null;
}
// update Ghidra Preferences with new Jar path
Preferences.setProperty(Preferences.USER_PLUGIN_JAR_DIRECTORY, jarDirectoryName);
errorMsg = null;
// save the new values
if (Preferences.store()) {
setStatusMessage("Saved plugin paths successfully!");
// indicate to user all changes have been applied
setApplyEnabled(false);
jarPathPanel.setChanged(false);
Msg.showInfo(getClass(), rootPanel, "Restart Ghidra",
"You must restart Ghidra in order\n" + "for path changes to take effect.");
@ -479,10 +364,6 @@ class EditPluginPathDialog extends DialogComponentProvider {
}
}
/**
* dispatched method for handling button actions on the
* dialog
*/
private void handleSelection(byte whichAction) {
// if nothing selected, nothing to do
if (selectedInList == null) {
@ -574,8 +455,8 @@ class EditPluginPathDialog extends DialogComponentProvider {
private void setPluginPathsListData(String[] pluginPathNames) {
listModel.clear();
for (int p = 0; p < pluginPathNames.length; p++) {
listModel.addElement(pluginPathNames[p]);
for (String pluginPathName : pluginPathNames) {
listModel.addElement(pluginPathName);
}
}