diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/DirectoryList.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/DirectoryList.java index c31518fc18..d41929e1c7 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/DirectoryList.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/DirectoryList.java @@ -25,6 +25,8 @@ import java.util.ArrayList; import java.util.List; import javax.swing.*; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; import docking.event.mouse.GMouseListenerAdapter; import docking.widgets.label.GDLabel; @@ -57,6 +59,23 @@ class DirectoryList extends GList implements GhidraFileChooserDirectoryMod setLayoutOrientation(JList.VERTICAL_WRAP); 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() { @Override @@ -160,7 +179,15 @@ class DirectoryList extends GList implements GhidraFileChooserDirectoryMod e.consume(); } 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(); } } @@ -324,6 +351,13 @@ class DirectoryList extends GList implements GhidraFileChooserDirectoryMod return; } + String invalidFilenameMessage = + chooser.getInvalidFilenameMessage(listEditorField.getText()); + if (invalidFilenameMessage != null) { + chooser.setStatusText("Rename aborted - " + invalidFilenameMessage); + return; + } + File editedFileCopy = editedFile; int index = model.indexOfFile(editedFileCopy); if (index < 0) { @@ -332,6 +366,7 @@ class DirectoryList extends GList implements GhidraFileChooserDirectoryMod File dest = new File(editedFileCopy.getParentFile(), listEditorField.getText()); cancelListEdit(); if (chooser.getModel().renameFile(editedFileCopy, dest)) { + chooser.setStatusText(""); model.set(index, dest); //chooser.updateFiles(chooser.getCurrentDirectory(), true); chooser.setSelectedFileAndUpdateDisplay(dest); @@ -350,26 +385,25 @@ class DirectoryList extends GList implements GhidraFileChooserDirectoryMod * @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. */ - void recomputeListCellDimensions(List files) { + private void recomputeListCellDimensions(List files) { files = (files != null) ? files : model.getAllFiles(); - Dimension cellDims = + Dimension d = 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 // width if (getParent().getParent() instanceof JScrollPane) { JScrollPane parent = (JScrollPane) getParent().getParent(); Dimension parentSize = parent.getSize(); Insets insets = parent.getInsets(); - cellDims.width = - parentSize.width - (insets != null ? insets.right + insets.left : 0); + d.width = parentSize.width - (insets != null ? insets.right + insets.left : 0); } } else { - cellDims.width += DEFAULT_ICON_SIZE + WIDTH_PADDING; + d.width += DEFAULT_ICON_SIZE + WIDTH_PADDING; } - setFixedCellWidth(cellDims.width); - setFixedCellHeight(cellDims.height + HEIGHT_PADDING); + setFixedCellWidth(d.width); + setFixedCellHeight(d.height + HEIGHT_PADDING); } /*junit*/ JTextField getListEditorText() { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileEditor.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileEditor.java index 4968df99a9..7675176475 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileEditor.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/FileEditor.java @@ -63,6 +63,14 @@ class FileEditor extends AbstractCellEditor implements TableCellEditor { directoryTable.editingCanceled(new ChangeEvent(FileEditor.this)); e.consume(); } + else if (e.getKeyCode() == KeyEvent.VK_ENTER) { + String invalidFilenameMessage = + chooser.getInvalidFilenameMessage(nameField.getText()); + if (invalidFilenameMessage != null) { + chooser.setStatusText(invalidFilenameMessage); + e.consume(); + } + } } @Override @@ -72,7 +80,14 @@ class FileEditor extends AbstractCellEditor implements TableCellEditor { e.consume(); } 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(); } } @@ -145,6 +160,11 @@ class FileEditor extends AbstractCellEditor implements TableCellEditor { } private File getNewFile() { + String invalidFilenameMessage = chooser.getInvalidFilenameMessage(nameField.getText()); + if (invalidFilenameMessage != null) { + chooser.setStatusText("Rename aborted - " + invalidFilenameMessage); + return originalFile; + } GhidraFileChooserModel fileChooserModel = chooser.getModel(); File newFile = new GhidraFile(originalFile.getParentFile(), nameField.getText(), fileChooserModel.getSeparator()); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java index 73655abf08..e247a1571a 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/GhidraFileChooser.java @@ -22,22 +22,23 @@ import java.io.FileFilter; import java.text.SimpleDateFormat; import java.util.*; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.swing.*; -import javax.swing.border.Border; -import javax.swing.event.*; +import javax.swing.event.CellEditorListener; +import javax.swing.event.ChangeEvent; import javax.swing.filechooser.FileSystemView; import docking.*; -import docking.framework.DockingApplicationConfiguration; import docking.widgets.*; import docking.widgets.combobox.GComboBox; import docking.widgets.label.GDLabel; import docking.widgets.label.GLabel; import docking.widgets.list.GListCellRenderer; -import ghidra.GhidraApplicationLayout; -import ghidra.framework.*; +import ghidra.framework.OperatingSystem; +import ghidra.framework.Platform; import ghidra.framework.preferences.Preferences; import ghidra.util.Msg; import ghidra.util.SystemUtilities; @@ -86,6 +87,7 @@ public class GhidraFileChooser extends DialogComponentProvider static final String DOT = "."; static final String DOTDOT = ".."; static final String NEW_FOLDER = "New Folder"; + static final Pattern INVALID_FILENAME_PATTERN = Pattern.compile("[/\\\\*?]"); private static final int PAD = 5; @@ -551,24 +553,6 @@ public class GhidraFileChooser extends DialogComponentProvider private JScrollPane buildDirectoryList() { 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.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 (currentDirectory().equals(directory)) { // recompute list cell dims before causing an update to the model - directoryList.recomputeListCellDimensions(files); directoryTableModel.setFiles(files); directoryTable.scrollRectToVisible(new Rectangle(0, 0, 0, 0)); directoryListModel.setFiles(files); @@ -2130,12 +2113,17 @@ public class GhidraFileChooser extends DialogComponentProvider } } - public static void main(String[] args) throws Exception { - - GhidraApplicationLayout layout = new GhidraApplicationLayout(); - Application.initializeApplication(layout, new DockingApplicationConfiguration()); - GhidraFileChooser chooser = new GhidraFileChooser(null); - chooser.show(); - System.exit(0); + String getInvalidFilenameMessage(String filename) { + switch (filename) { + case ".": + case "..": + return "Reserved name '" + filename + "'"; + default: + Matcher m = GhidraFileChooser.INVALID_FILENAME_PATTERN.matcher(filename); + if (m.find()) { + return "Invalid characters: " + m.group(); + } + } + return null; } }