diff --git a/Ghidra/Features/Base/certification.manifest b/Ghidra/Features/Base/certification.manifest index 197fae7184..0fc0541072 100644 --- a/Ghidra/Features/Base/certification.manifest +++ b/Ghidra/Features/Base/certification.manifest @@ -821,6 +821,7 @@ src/main/resources/images/field.header.up.png||GHIDRA||||END| src/main/resources/images/fingerPointer.png||GHIDRA||||END| src/main/resources/images/flag-green.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/flag-yellow.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| +src/main/resources/images/folder-downloads-32.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END| src/main/resources/images/format-text-bold.png||Tango Icons - Public Domain|||tango icon set|END| src/main/resources/images/functionDef.png||GHIDRA||||END| src/main/resources/images/function_graph.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END| diff --git a/Ghidra/Features/Base/src/main/resources/images/folder-downloads-32.png b/Ghidra/Features/Base/src/main/resources/images/folder-downloads-32.png new file mode 100644 index 0000000000..8d4c84c046 Binary files /dev/null and b/Ghidra/Features/Base/src/main/resources/images/folder-downloads-32.png differ diff --git a/Ghidra/Framework/Docking/data/docking.theme.properties b/Ghidra/Framework/Docking/data/docking.theme.properties index fc6bf37645..662e828b60 100644 --- a/Ghidra/Framework/Docking/data/docking.theme.properties +++ b/Ghidra/Framework/Docking/data/docking.theme.properties @@ -103,6 +103,7 @@ icon.filechooser.places.my.computer = computer.png icon.filechooser.places.desktop = desktop.png icon.filechooser.places.home = user-home.png icon.filechooser.places.recent = inode-directory.png {edit-undo.png [move(6,10)]} +icon.filechooser.places.downloads = folder-downloads-32.png icon.filter.options.contains = page_code.png icon.filter.options.exact = page_green.png 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 01727533c2..d99fd98a73 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 @@ -107,6 +107,7 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement private static final Icon ICON_MY_COMPUTER = new GIcon("icon.filechooser.places.my.computer"); private static final Icon ICON_DESKTOP = new GIcon("icon.filechooser.places.desktop"); private static final Icon ICON_HOME = new GIcon("icon.filechooser.places.home"); + private static final Icon ICON_DOWNLOADS = new GIcon("icon.filechooser.places.downloads"); private static final Icon ICON_RECENT = new GIcon("icon.filechooser.places.recent"); private final static Cursor WAIT_CURSOR = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR); @@ -167,6 +168,7 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement private FileChooserToggleButton myComputerButton; private FileChooserToggleButton desktopButton; private FileChooserToggleButton homeButton; + private FileChooserToggleButton downloadsButton; private FileChooserToggleButton recentButton; private JTextField currentPathTextField; @@ -323,6 +325,17 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement homeButton.addActionListener(e -> updateHome()); homeButton.setForeground(FOREROUND_COLOR); + downloadsButton = new FileChooserToggleButton("Downloads") { + @Override + File getFile() { + return fileChooserModel.getDownloadsDirectory(); + } + }; + downloadsButton.setName("DOWNLOADS_BUTTON"); + downloadsButton.setIcon(ICON_DOWNLOADS); + downloadsButton.addActionListener(e -> updateDownloads()); + downloadsButton.setForeground(FOREROUND_COLOR); + recentButton = new FileChooserToggleButton("Recent") { @Override File getFile() { @@ -338,6 +351,7 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement shortCutButtonGroup.add(myComputerButton); shortCutButtonGroup.add(desktopButton); shortCutButtonGroup.add(homeButton); + shortCutButtonGroup.add(downloadsButton); shortCutButtonGroup.add(recentButton); JPanel shortCutPanel = new JPanel(new GridLayout(0, 1)); @@ -345,6 +359,7 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement shortCutPanel.add(myComputerButton); shortCutPanel.add(desktopButton); shortCutPanel.add(homeButton); + shortCutPanel.add(downloadsButton); shortCutPanel.add(recentButton); JPanel panel = new JPanel(new BorderLayout()); @@ -718,6 +733,11 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement updateDirOnly(home, true); } + private void updateDownloads() { + File downloads = downloadsButton.getFile(); + updateDirOnly(downloads, true); + } + void removeRecentFiles(List toRemove) { recentList.removeAll(toRemove); saveRecentList(); @@ -1380,6 +1400,7 @@ public class GhidraFileChooser extends ReusableDialogComponentProvider implement checkShortCutButton(homeButton, currentDirectory); checkShortCutButton(recentButton, currentDirectory); checkShortCutButton(desktopButton, currentDirectory); + checkShortCutButton(downloadsButton, currentDirectory); } private void checkShortCutButton(FileChooserToggleButton button, File currentDirectory) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/LocalFileChooserModel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/LocalFileChooserModel.java index ba439c4396..70b6e050cf 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/LocalFileChooserModel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/filechooser/LocalFileChooserModel.java @@ -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. @@ -79,6 +79,19 @@ public class LocalFileChooserModel implements GhidraFileChooserModel { return desktop.isDirectory() ? desktop : null; } + @Override + public File getDownloadsDirectory() { + String userHomeProp = System.getProperty("user.home"); + if (userHomeProp == null) { + return null; + } + + File home = new File(userHomeProp); + File downloads = new File(home, "Downloads"); + + return downloads.isDirectory() ? downloads : null; + } + @Override public List getRoots(boolean forceUpdate) { if (FS_ROOT_INFO.isEmpty() || forceUpdate) { diff --git a/Ghidra/Framework/Gui/src/main/java/ghidra/util/filechooser/GhidraFileChooserModel.java b/Ghidra/Framework/Gui/src/main/java/ghidra/util/filechooser/GhidraFileChooserModel.java index 83a4fa8133..f4dced7dad 100644 --- a/Ghidra/Framework/Gui/src/main/java/ghidra/util/filechooser/GhidraFileChooserModel.java +++ b/Ghidra/Framework/Gui/src/main/java/ghidra/util/filechooser/GhidraFileChooserModel.java @@ -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. @@ -53,6 +53,15 @@ public interface GhidraFileChooserModel { */ public File getDesktopDirectory(); + /** + * Returns the user's downloads directory, as defined by their operating system and/or their windowing environment, or + * null if there is no downloads directory.

+ * Example: "/home/the_user/Downloads" or "c:/Users/the_user/Downloads" + * + * @return downloads directory + */ + public File getDownloadsDirectory(); + /** * Returns a list of the root drives/directories. *