diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/EditArchivePathAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/EditArchivePathAction.java index 650a9c2f13..64ccd6c157 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/EditArchivePathAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/actions/EditArchivePathAction.java @@ -15,15 +15,12 @@ */ package ghidra.app.plugin.core.datamgr.actions; -import java.util.List; - import docking.ActionContext; import docking.DialogComponentProvider; import docking.action.DockingAction; import docking.action.MenuData; import docking.widgets.filechooser.GhidraFileChooserMode; import docking.widgets.pathmanager.PathManager; -import generic.util.Path; import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin; import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler; import ghidra.framework.preferences.Preferences; @@ -83,10 +80,6 @@ public class EditArchivePathAction extends DockingAction { super.close(); pathManager.dispose(); } - - List getPaths() { - return pathManager.getPaths(); - } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java index e54d1d0499..19768383da 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/archive/DataTypeManagerHandler.java @@ -197,6 +197,9 @@ public class DataTypeManagerHandler { } } + /** + * @return all archive search paths (both enabled and disabled are included) + */ private Path[] getArchivePaths() { return PathManager.getPathsFromPreferences(DATA_TYPE_ARCHIVE_PATH_KEY, null, DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY); @@ -230,7 +233,7 @@ public class DataTypeManagerHandler { Path[] pathsFromPreferences = getArchivePaths(); for (Path path : pathsFromPreferences) { - if (!isAllowedArchivePath(path.getPathAsString()) || !path.isEnabled()) { + if (!path.isEnabled() || !isAllowedArchivePath(path.getPathAsString())) { continue; } ResourceFile archiveFile = new ResourceFile(path.getPath(), archiveFileName); @@ -282,6 +285,7 @@ public class DataTypeManagerHandler { Archive archive = new FileArchive(this, file); addArchivePath(new ResourceFile(file)); addArchive(archive); + userOpenedFileArchiveNames.add(getSaveableArchive(file.getAbsolutePath())); return archive; } catch (Exception e) { @@ -400,7 +404,8 @@ public class DataTypeManagerHandler { if (path.equals(newPath)) { if (!path.isEnabled()) { path.setEnabled(true); - PathManager.savePathsToPreferences(DATA_TYPE_ARCHIVE_PATH_KEY, null, paths); + PathManager.savePathsToPreferences(DATA_TYPE_ARCHIVE_PATH_KEY, + DISABLED_DATA_TYPE_ARCHIVE_PATH_KEY, paths); } return; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathManager.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathManager.java index ac323129e3..08761ababf 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/pathmanager/PathManager.java @@ -43,6 +43,7 @@ import resources.ResourceManager; * behave. If the table entries should not be edited, call setEditingEnabled(false). */ public class PathManager { + private JPanel panel; private GTable pathTable; private PathManagerModel pathModel; @@ -99,13 +100,6 @@ public class PathManager { this.fileChooser = null; } - /** - * Return enabled paths in the table. - */ - public List getPaths() { - return pathModel.getPaths(); - } - /** * Add a new file path and set its enablement * @param file @@ -400,69 +394,123 @@ public class PathManager { ss.putBooleans("PathManagerPanel_READ", readArr); } + /** + * Restore paths from user Preferences using the specified keys. + * If preferences have never been saved, the specified {@code defaultEnablePaths} + * will be used. Note: the encoded path list must have been stored + * using the same keys using the {@link #savePathsToPreferences(String, String, Path[])} + * or {@link #saveToPreferences(String, String)} methods. + * @param enablePathKey preference key for storing enabled paths + * @param defaultEnablePaths default paths + * @param disabledPathKey preference key for storing disabled paths + */ public void restoreFromPreferences(String enablePathKey, Path[] defaultEnablePaths, String disabledPathKey) { + pathModel.clear(); for (Path path : getPathsFromPreferences(enablePathKey, defaultEnablePaths, disabledPathKey)) { pathModel.addPath(path, addToTop); } } + /** + * Restore paths from user Preferences using the specified keys. + * If preferences have never been saved, the specified {@code defaultEnablePaths} + * will be returned. Note: the encoded path list must have been stored + * using the same keys using the {@link #savePathsToPreferences(String, String, Path[])} + * or {@link #saveToPreferences(String, String)} methods. + * @param enablePathKey preference key for storing enabled paths + * @param defaultEnablePaths default paths + * @param disabledPathKey preference key for storing disabled paths + * @return ordered paths from Preferences + */ public static Path[] getPathsFromPreferences(String enablePathKey, Path[] defaultEnablePaths, String disabledPathKey) { String enablePath = Preferences.getProperty(enablePathKey, null, true); if (enablePath != null && enablePath.length() == 0) { enablePath = null; } - String[] enabledPaths; - if (defaultEnablePaths != null && enablePath == null) { - enabledPaths = new String[defaultEnablePaths.length]; - for (int i = 0; i < enabledPaths.length; i++) { - enabledPaths[i] = defaultEnablePaths[i].getPathAsString(); - } - } - else { - enabledPaths = - enablePath != null ? enablePath.split(File.pathSeparator) : new String[0]; - } String disabledPath = Preferences.getProperty(disabledPathKey, null); if (disabledPath != null && disabledPath.length() == 0) { disabledPath = null; } - String[] disabledPaths = + String[] enabledPaths = null; + String[] disabledPaths = null; + if (defaultEnablePaths != null && enablePath == null && disabledPath == null) { + return defaultEnablePaths; + } + + enabledPaths = enablePath != null ? enablePath.split(File.pathSeparator) : new String[0]; + + disabledPaths = disabledPath != null ? disabledPath.split(File.pathSeparator) : new String[0]; - Path[] paths = new Path[enabledPaths.length + disabledPaths.length]; - int index = 0; + + ArrayList list = new ArrayList<>(); + int disabledIndex = 0; for (String p : enabledPaths) { - paths[index++] = new Path(p); + if (p.length() == 0) { + // insert next disabled path at empty placeholder + if (disabledIndex < disabledPaths.length) { + list.add(new Path(disabledPaths[disabledIndex++], false)); + } + } + else { + list.add(new Path(p, true)); + } } - for (String p : disabledPaths) { - paths[index++] = new Path(p); + // add remaining disabled paths + for (int i = disabledIndex; i < disabledPaths.length; i++) { + list.add(new Path(disabledPaths[i], false)); } - return paths; + Path[] paths = new Path[list.size()]; + return list.toArray(paths); } public boolean saveToPreferences(String enablePathKey, String disabledPathKey) { - List pathList = getPaths(); + List pathList = pathModel.getAllPaths(); return savePathsToPreferences(enablePathKey, disabledPathKey, pathList.toArray(new Path[pathList.size()])); } + private static void appendPath(StringBuilder buf, String path, boolean previousPathIsEmpty) { + if (buf.length() != 0 || previousPathIsEmpty) { + buf.append(File.pathSeparatorChar); + } + buf.append(path); + } + + /** + * Save the specified paths to the user Preferences using the specified keys. + * Note: The encoded path Preferences are intended to be decoded by the + * {@link #restoreFromPreferences(String, Path[], String)} and + * {@link #getPathsFromPreferences(String, Path[], String)} methods. + * @param enablePathKey preference key for storing enabled paths + * @param disabledPathKey preference key for storing disabled paths + * @param paths paths to be saved + * @return true if Preference saved properly + */ public static boolean savePathsToPreferences(String enablePathKey, String disabledPathKey, Path[] paths) { - StringBuffer enabledPathBuffer = new StringBuffer(); - StringBuffer disabledPathBuffer = new StringBuffer(); + StringBuilder enabledPathBuffer = new StringBuilder(); + StringBuilder disabledPathBuffer = new StringBuilder(); + boolean previousPathDisabled = false; for (Path path : paths) { - StringBuffer buf = path.isEnabled() ? enabledPathBuffer : disabledPathBuffer; - if (buf.length() != 0) { - buf.append(File.pathSeparatorChar); + if (path.isEnabled()) { + appendPath(enabledPathBuffer, path.getPathAsString(), previousPathDisabled); + previousPathDisabled = false; + } + else { + appendPath(disabledPathBuffer, path.getPathAsString(), false); + appendPath(enabledPathBuffer, "", previousPathDisabled); + previousPathDisabled = true; } - buf.append(path.getPathAsString()); } if (enablePathKey != null) { Preferences.setProperty(enablePathKey, enabledPathBuffer.toString()); } - Preferences.setProperty(disabledPathKey, disabledPathBuffer.toString()); + if (disabledPathKey != null) { + Preferences.setProperty(disabledPathKey, disabledPathBuffer.toString()); + } return Preferences.store(); } diff --git a/Ghidra/Test/IntegrationTest/src/test/java/ghidra/util/bean/PathManagerTest.java b/Ghidra/Test/IntegrationTest/src/test/java/ghidra/util/bean/PathManagerTest.java index 9020a44b75..8fdb268d56 100644 --- a/Ghidra/Test/IntegrationTest/src/test/java/ghidra/util/bean/PathManagerTest.java +++ b/Ghidra/Test/IntegrationTest/src/test/java/ghidra/util/bean/PathManagerTest.java @@ -256,4 +256,29 @@ public class PathManagerTest extends AbstractDockingTest { runSwing(() -> table.setRowSelectionInterval(row, row)); } + @Test + public void testPathPreferenceRetention() { + + Preferences.setProperty("ENABLED_PATHS", null); + Preferences.setProperty("DISABLED_PATHS", null); + + Path[] defaultPaths = new Path[] { + new Path("/foo"), new Path("/bar") + }; + + Path[] restoredPaths = + PathManager.getPathsFromPreferences("ENABLED_PATHS", defaultPaths, "DISABLED_PATHS"); + assertArrayEquals(defaultPaths, restoredPaths); + + Path[] paths = new Path[] { + new Path("/jim", false), new Path("/joe", false), new Path("/bob", true), + new Path("/sam", false), new Path("/tom", true), new Path("/tim", false) + }; + PathManager.savePathsToPreferences("ENABLED_PATHS", "DISABLED_PATHS", paths); + + restoredPaths = + PathManager.getPathsFromPreferences("ENABLED_PATHS", defaultPaths, "DISABLED_PATHS"); + assertArrayEquals(paths, restoredPaths); + } + }