GT-2855 - GhidraFileChooser code improvements

This commit is contained in:
dev747368
2019-05-08 17:40:57 -04:00
parent 131228a250
commit 463b74b60d
3 changed files with 83 additions and 41 deletions
@@ -25,6 +25,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import docking.event.mouse.GMouseListenerAdapter; import docking.event.mouse.GMouseListenerAdapter;
import docking.widgets.label.GDLabel; import docking.widgets.label.GDLabel;
@@ -57,6 +59,23 @@ class DirectoryList extends GList<File> implements GhidraFileChooserDirectoryMod
setLayoutOrientation(JList.VERTICAL_WRAP); setLayoutOrientation(JList.VERTICAL_WRAP);
setCellRenderer((cellRenderer = new FileListCellRenderer(getFont(), chooser))); setCellRenderer((cellRenderer = new FileListCellRenderer(getFont(), chooser)));
model.addListDataListener(new ListDataListener() {
@Override
public void contentsChanged(ListDataEvent e) {
// called when the list changes because a new file is inserted (ie. create new folder action)
recomputeListCellDimensions(null);
}
@Override
public void intervalAdded(ListDataEvent e) {
recomputeListCellDimensions(null);
}
@Override
public void intervalRemoved(ListDataEvent e) {
// don't care
}
});
addMouseListener(new MouseAdapter() { addMouseListener(new MouseAdapter() {
@Override @Override
@@ -160,7 +179,15 @@ class DirectoryList extends GList<File> implements GhidraFileChooserDirectoryMod
e.consume(); e.consume();
} }
else if (e.getKeyCode() == KeyEvent.VK_ENTER) { else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
stopListEdit(); String invalidFilenameMessage =
chooser.getInvalidFilenameMessage(listEditorField.getText());
if (invalidFilenameMessage != null) {
chooser.setStatusText(invalidFilenameMessage);
// keep the user in the field
}
else {
stopListEdit();
}
e.consume(); e.consume();
} }
} }
@@ -324,6 +351,13 @@ class DirectoryList extends GList<File> implements GhidraFileChooserDirectoryMod
return; return;
} }
String invalidFilenameMessage =
chooser.getInvalidFilenameMessage(listEditorField.getText());
if (invalidFilenameMessage != null) {
chooser.setStatusText("Rename aborted - " + invalidFilenameMessage);
return;
}
File editedFileCopy = editedFile; File editedFileCopy = editedFile;
int index = model.indexOfFile(editedFileCopy); int index = model.indexOfFile(editedFileCopy);
if (index < 0) { if (index < 0) {
@@ -332,6 +366,7 @@ class DirectoryList extends GList<File> implements GhidraFileChooserDirectoryMod
File dest = new File(editedFileCopy.getParentFile(), listEditorField.getText()); File dest = new File(editedFileCopy.getParentFile(), listEditorField.getText());
cancelListEdit(); cancelListEdit();
if (chooser.getModel().renameFile(editedFileCopy, dest)) { if (chooser.getModel().renameFile(editedFileCopy, dest)) {
chooser.setStatusText("");
model.set(index, dest); model.set(index, dest);
//chooser.updateFiles(chooser.getCurrentDirectory(), true); //chooser.updateFiles(chooser.getCurrentDirectory(), true);
chooser.setSelectedFileAndUpdateDisplay(dest); chooser.setSelectedFileAndUpdateDisplay(dest);
@@ -350,26 +385,25 @@ class DirectoryList extends GList<File> implements GhidraFileChooserDirectoryMod
* @param files list of files to use to resize the list's fixed cell dimensions. If null, uses * @param files list of files to use to resize the list's fixed cell dimensions. If null, uses
* the model's current set of files. * the model's current set of files.
*/ */
void recomputeListCellDimensions(List<File> files) { private void recomputeListCellDimensions(List<File> files) {
files = (files != null) ? files : model.getAllFiles(); files = (files != null) ? files : model.getAllFiles();
Dimension cellDims = Dimension d =
cellRenderer.computePlainTextListCellDimensions(this, files, 0, DEFAULT_ICON_SIZE); cellRenderer.computePlainTextListCellDimensions(this, files, 0, DEFAULT_ICON_SIZE);
if (cellDims.width == 0 && getParent() != null) { if (d.width == 0 && getParent() != null) {
// special case: if there were no files to measure, use the containing JScrollPane's // special case: if there were no files to measure, use the containing JScrollPane's
// width // width
if (getParent().getParent() instanceof JScrollPane) { if (getParent().getParent() instanceof JScrollPane) {
JScrollPane parent = (JScrollPane) getParent().getParent(); JScrollPane parent = (JScrollPane) getParent().getParent();
Dimension parentSize = parent.getSize(); Dimension parentSize = parent.getSize();
Insets insets = parent.getInsets(); Insets insets = parent.getInsets();
cellDims.width = d.width = parentSize.width - (insets != null ? insets.right + insets.left : 0);
parentSize.width - (insets != null ? insets.right + insets.left : 0);
} }
} }
else { else {
cellDims.width += DEFAULT_ICON_SIZE + WIDTH_PADDING; d.width += DEFAULT_ICON_SIZE + WIDTH_PADDING;
} }
setFixedCellWidth(cellDims.width); setFixedCellWidth(d.width);
setFixedCellHeight(cellDims.height + HEIGHT_PADDING); setFixedCellHeight(d.height + HEIGHT_PADDING);
} }
/*junit*/ JTextField getListEditorText() { /*junit*/ JTextField getListEditorText() {
@@ -63,6 +63,14 @@ class FileEditor extends AbstractCellEditor implements TableCellEditor {
directoryTable.editingCanceled(new ChangeEvent(FileEditor.this)); directoryTable.editingCanceled(new ChangeEvent(FileEditor.this));
e.consume(); e.consume();
} }
else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
String invalidFilenameMessage =
chooser.getInvalidFilenameMessage(nameField.getText());
if (invalidFilenameMessage != null) {
chooser.setStatusText(invalidFilenameMessage);
e.consume();
}
}
} }
@Override @Override
@@ -72,7 +80,14 @@ class FileEditor extends AbstractCellEditor implements TableCellEditor {
e.consume(); e.consume();
} }
else if (e.getKeyCode() == KeyEvent.VK_ENTER) { else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
directoryTable.editingStopped(new ChangeEvent(FileEditor.this)); String invalidFilenameMessage =
chooser.getInvalidFilenameMessage(nameField.getText());
if (invalidFilenameMessage != null) {
chooser.setStatusText(invalidFilenameMessage);
}
else {
directoryTable.editingStopped(new ChangeEvent(FileEditor.this));
}
e.consume(); e.consume();
} }
} }
@@ -145,6 +160,11 @@ class FileEditor extends AbstractCellEditor implements TableCellEditor {
} }
private File getNewFile() { private File getNewFile() {
String invalidFilenameMessage = chooser.getInvalidFilenameMessage(nameField.getText());
if (invalidFilenameMessage != null) {
chooser.setStatusText("Rename aborted - " + invalidFilenameMessage);
return originalFile;
}
GhidraFileChooserModel fileChooserModel = chooser.getModel(); GhidraFileChooserModel fileChooserModel = chooser.getModel();
File newFile = new GhidraFile(originalFile.getParentFile(), nameField.getText(), File newFile = new GhidraFile(originalFile.getParentFile(), nameField.getText(),
fileChooserModel.getSeparator()); fileChooserModel.getSeparator());
@@ -22,22 +22,23 @@ import java.io.FileFilter;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.Border; import javax.swing.event.CellEditorListener;
import javax.swing.event.*; import javax.swing.event.ChangeEvent;
import javax.swing.filechooser.FileSystemView; import javax.swing.filechooser.FileSystemView;
import docking.*; import docking.*;
import docking.framework.DockingApplicationConfiguration;
import docking.widgets.*; import docking.widgets.*;
import docking.widgets.combobox.GComboBox; import docking.widgets.combobox.GComboBox;
import docking.widgets.label.GDLabel; import docking.widgets.label.GDLabel;
import docking.widgets.label.GLabel; import docking.widgets.label.GLabel;
import docking.widgets.list.GListCellRenderer; import docking.widgets.list.GListCellRenderer;
import ghidra.GhidraApplicationLayout; import ghidra.framework.OperatingSystem;
import ghidra.framework.*; import ghidra.framework.Platform;
import ghidra.framework.preferences.Preferences; import ghidra.framework.preferences.Preferences;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.SystemUtilities; import ghidra.util.SystemUtilities;
@@ -86,6 +87,7 @@ public class GhidraFileChooser extends DialogComponentProvider
static final String DOT = "."; static final String DOT = ".";
static final String DOTDOT = ".."; static final String DOTDOT = "..";
static final String NEW_FOLDER = "New Folder"; static final String NEW_FOLDER = "New Folder";
static final Pattern INVALID_FILENAME_PATTERN = Pattern.compile("[/\\\\*?]");
private static final int PAD = 5; private static final int PAD = 5;
@@ -551,24 +553,6 @@ public class GhidraFileChooser extends DialogComponentProvider
private JScrollPane buildDirectoryList() { private JScrollPane buildDirectoryList() {
directoryListModel = new DirectoryListModel(); directoryListModel = new DirectoryListModel();
directoryListModel.addListDataListener(new ListDataListener() {
@Override
public void contentsChanged(ListDataEvent e) {
// called when the list changes because a new file is inserted (ie. create new folder action)
directoryList.recomputeListCellDimensions(null);
}
@Override
public void intervalAdded(ListDataEvent e) {
// don't care
}
@Override
public void intervalRemoved(ListDataEvent e) {
// don't care
}
});
directoryList = new DirectoryList(this, directoryListModel); directoryList = new DirectoryList(this, directoryListModel);
directoryList.setName("LIST"); directoryList.setName("LIST");
@@ -863,7 +847,6 @@ public class GhidraFileChooser extends DialogComponentProvider
// if the visible listing is still the same directory as this incoming list of files // if the visible listing is still the same directory as this incoming list of files
if (currentDirectory().equals(directory)) { if (currentDirectory().equals(directory)) {
// recompute list cell dims before causing an update to the model // recompute list cell dims before causing an update to the model
directoryList.recomputeListCellDimensions(files);
directoryTableModel.setFiles(files); directoryTableModel.setFiles(files);
directoryTable.scrollRectToVisible(new Rectangle(0, 0, 0, 0)); directoryTable.scrollRectToVisible(new Rectangle(0, 0, 0, 0));
directoryListModel.setFiles(files); directoryListModel.setFiles(files);
@@ -2130,12 +2113,17 @@ public class GhidraFileChooser extends DialogComponentProvider
} }
} }
public static void main(String[] args) throws Exception { String getInvalidFilenameMessage(String filename) {
switch (filename) {
GhidraApplicationLayout layout = new GhidraApplicationLayout(); case ".":
Application.initializeApplication(layout, new DockingApplicationConfiguration()); case "..":
GhidraFileChooser chooser = new GhidraFileChooser(null); return "Reserved name '" + filename + "'";
chooser.show(); default:
System.exit(0); Matcher m = GhidraFileChooser.INVALID_FILENAME_PATTERN.matcher(filename);
if (m.find()) {
return "Invalid characters: " + m.group();
}
}
return null;
} }
} }