diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/actions/GotoNextFunctionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/actions/GotoNextFunctionAction.java index 95181e5fa2..6ff1bb3b44 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/actions/GotoNextFunctionAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/actions/GotoNextFunctionAction.java @@ -39,7 +39,7 @@ public class GotoNextFunctionAction extends NavigatableContextAction { private PluginTool tool; public GotoNextFunctionAction(PluginTool tool, String owner) { - super("Go to next function", owner); + super("Go To Next Function", owner); this.tool = tool; MenuData menuData = diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/actions/GotoPreviousFunctionAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/actions/GotoPreviousFunctionAction.java index a8cae35269..14506e62f0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/actions/GotoPreviousFunctionAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/actions/GotoPreviousFunctionAction.java @@ -39,7 +39,7 @@ public class GotoPreviousFunctionAction extends NavigatableContextAction { private PluginTool tool; public GotoPreviousFunctionAction(PluginTool tool, String owner) { - super("Go to previous function", owner); + super("Go To Previous Function", owner); this.tool = tool; MenuData menuData = diff --git a/Ghidra/Features/Base/src/main/java/ghidra/test/TestProgramManager.java b/Ghidra/Features/Base/src/main/java/ghidra/test/TestProgramManager.java index edf100700e..ae8b642f8f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/test/TestProgramManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/test/TestProgramManager.java @@ -33,7 +33,8 @@ import ghidra.program.model.listing.Program; import ghidra.program.util.DefaultLanguageService; import ghidra.util.*; import ghidra.util.exception.*; -import ghidra.util.task.*; +import ghidra.util.task.ConsoleTaskMonitor; +import ghidra.util.task.TaskMonitor; import utilities.util.FileUtilities; /** @@ -123,11 +124,14 @@ public class TestProgramManager { /** * Save a program to the cached program store. A SaveAs will be performed on the * program to its cached storage location. + * * @param progName program name * @param program program object * @param replace if true any existing cached database with the same name will be replaced * @param monitor task monitor + * @throws IOException if the database cannot be created * @throws DuplicateNameException if already cached + * @throws CancelledException if the save operation is cancelled */ public void saveToCache(String progName, ProgramDB program, boolean replace, TaskMonitor monitor) throws IOException, DuplicateNameException, CancelledException { @@ -205,7 +209,9 @@ public class TestProgramManager { * the only reason to use this method vice openProgram(). * * @param project the project into which the file will be restored - * @param programName the name of the program zip file without the ".gzf" extension. + * @param programName the name of the program zip file without the ".gzf" extension + * @return the file + * @throws FileNotFoundException if the file cannot be found */ public DomainFile addProgramToProject(Project project, String programName) throws FileNotFoundException { @@ -221,6 +227,8 @@ public class TestProgramManager { * * @param folder the folder into which the domain file will be inserted * @param programName the name of the program zip file without the ".gzf" extension. + * @return the file + * @throws FileNotFoundException if the file cannot be found */ public DomainFile addProgramToProject(DomainFolder folder, String programName) throws FileNotFoundException { @@ -234,7 +242,7 @@ public class TestProgramManager { int oneUp = 0; while (true) { try { - DomainFile df = folder.createFile(name, gzf, TaskMonitorAdapter.DUMMY_MONITOR); + DomainFile df = folder.createFile(name, gzf, TaskMonitor.DUMMY); AbstractGenericTest.waitForPostedSwingRunnables(); DomainObject dobj = df.getDomainObject(this, true, false, null); try { @@ -281,7 +289,7 @@ public class TestProgramManager { DBHandle dbh = null; boolean success = false; try { - dbh = db.open(TaskMonitorAdapter.DUMMY_MONITOR); + dbh = db.open(TaskMonitor.DUMMY); program = new ProgramDB(dbh, DBConstants.UPDATE, null, this); success = true; } @@ -312,7 +320,7 @@ public class TestProgramManager { } Msg.info(this, message + (endTime - startTime)); - dbh = db.open(TaskMonitorAdapter.DUMMY_MONITOR); + dbh = db.open(TaskMonitor.DUMMY); program = new ProgramDB(dbh, DBConstants.UPDATE, null, this); dbh = null; success = true; @@ -341,7 +349,7 @@ public class TestProgramManager { File gzf = AbstractGenericTest.findTestDataFile(programName + ".gzf"); if (gzf != null && gzf.exists()) { Msg.info(this, "Unpacking: " + gzf); - db = new PrivateDatabase(dbDir, gzf, TaskMonitorAdapter.DUMMY_MONITOR); + db = new PrivateDatabase(dbDir, gzf, TaskMonitor.DUMMY); testPrograms.put(programName, db); return db; } @@ -451,12 +459,12 @@ public class TestProgramManager { private void upgradeDatabase(PrivateDatabase db) throws Exception { - DBHandle dbh = db.openForUpdate(TaskMonitorAdapter.DUMMY_MONITOR); + DBHandle dbh = db.openForUpdate(TaskMonitor.DUMMY); try { ProgramDB program = - new ProgramDB(dbh, DBConstants.UPGRADE, TaskMonitorAdapter.DUMMY_MONITOR, this); + new ProgramDB(dbh, DBConstants.UPGRADE, TaskMonitor.DUMMY, this); if (dbh != null) { - dbh.save(null, null, TaskMonitorAdapter.DUMMY_MONITOR); + dbh.save(null, null, TaskMonitor.DUMMY); } dbh = null; program.release(this); diff --git a/Ghidra/Features/Base/src/test.slow/java/docking/action/KeyEntryDialogTest.java b/Ghidra/Features/Base/src/test.slow/java/docking/action/KeyEntryDialogTest.java index 960756be3f..0d66374ae2 100644 --- a/Ghidra/Features/Base/src/test.slow/java/docking/action/KeyEntryDialogTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/docking/action/KeyEntryDialogTest.java @@ -19,19 +19,20 @@ import static org.junit.Assert.*; import java.awt.event.KeyEvent; import java.util.Map; +import java.util.Set; import javax.swing.*; import org.junit.*; import docking.*; -import docking.actions.DockingToolActions; -import docking.actions.KeyEntryDialog; +import docking.actions.*; import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; import ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin; import ghidra.framework.plugintool.PluginTool; import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.TestEnv; +import util.CollectionUtils; public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest { @@ -91,6 +92,39 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest { assertEquals(acceleratorKey.getKeyCode(), KeyEvent.VK_Q); } + @Test + public void testClearDefaultKeyBinding() throws Exception { + + DockingAction boundAction = getBoundAction_Shared(); + showDialog(boundAction); + + assertEquals("OPEN_BRACKET", keyEntryField.getText()); + triggerBackspaceKey(keyEntryField); + + pressDialogOK(); + KeyStroke ks = boundAction.getKeyBinding(); + assertNull(ks); + } + + @Test + public void testClearDefaultKeyBinding_SharedKeybinding() throws Exception { + + DockingAction boundAction = getBoundAction_Shared(); + showDialog(boundAction); + + KeyStroke oldKs = boundAction.getKeyBinding(); + assertEquals("OPEN_BRACKET", keyEntryField.getText()); + triggerBackspaceKey(keyEntryField); + + pressDialogOK(); + KeyStroke ks = boundAction.getKeyBinding(); + assertNull(ks); + + ToolActions toolActions = (ToolActions) tool.getToolActions(); + Action toolAction = toolActions.getAction(oldKs); + assertNull("Shared actions' keybinding not cleared", toolAction); + } + @Test public void testCollision() throws Exception { // make sure we get a collision for a value that is already bound @@ -185,6 +219,13 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest { return (DockingAction) getInstanceField("action", goToPlugin); } + private DockingAction getBoundAction_Shared() { + Set sharedActions = + getActionsByOwnerAndName(tool, "Shared", "Define Array"); + assertFalse(sharedActions.isEmpty()); + return (DockingAction) CollectionUtils.any(sharedActions); + } + private void pressDialogOK() { JButton okButton = (JButton) getInstanceField("okButton", keyEntryDialog); pressButton(okButton); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/options/ToolPluginOptionsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/options/ToolPluginOptionsTest.java index adc08ac97e..ca07d00193 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/options/ToolPluginOptionsTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/framework/options/ToolPluginOptionsTest.java @@ -21,6 +21,8 @@ import java.awt.Color; import java.io.File; import java.util.*; +import javax.swing.KeyStroke; + import org.junit.*; import generic.stl.Pair; @@ -182,11 +184,11 @@ public class ToolPluginOptionsTest extends AbstractGhidraHeadedIntegrationTest { options = saveAndLoadOptions(); verifyStringOptionsStillChanged_UsingTheOptionsAPI(options, changedOption); - options.registerOption(NEW_TEST_OPTION_NAME, "default", null, null); + options.registerOption(NEW_TEST_OPTION_NAME, "default", null, "description"); options = saveAndLoadOptions(); verifyStringOptionsStillChanged_UsingTheOptionsAPI(options, changedOption); - options.registerOption(NEW_TEST_OPTION_NAME, "default", null, null); + options.registerOption(NEW_TEST_OPTION_NAME, "default", null, "description"); options = saveAndLoadOptions(); verifyStringOptionsStillChanged_UsingTheOptionsAPI(options, changedOption); @@ -198,6 +200,28 @@ public class ToolPluginOptionsTest extends AbstractGhidraHeadedIntegrationTest { verifyUnusedOptionNoLongerHasEntry(options, changedOption.first); } + @Test + public void testClearingKeyBindingOption() { + + Options options = loadKeyBindingOptions(); + + String optionName = clearKeyBinding(options); + + options = saveAndLoadOptions(); + verifyKeyBindingIsStillCleared(options, optionName); + } + + @Test + public void testAccessingOptionWithoutRegistering() { + + ToolOptions options = loadSearchOptions(); + String defaultValue = "default"; + Option option = + options.getOption(NEW_TEST_OPTION_NAME, OptionType.STRING_TYPE, defaultValue); + assertNotNull("unregistered option was not created on access", option); + assertEquals(defaultValue, option.getValue(defaultValue)); + } + @Test public void testSetFileOptionToNull() { // @@ -309,12 +333,24 @@ public class ToolPluginOptionsTest extends AbstractGhidraHeadedIntegrationTest { return tool.getOptions("Search"); } + private Options loadKeyBindingOptions() { + return tool.getOptions("Key Bindings"); + } + private Pair changeStringTestOption(Options options) { - options.registerOption(NEW_TEST_OPTION_NAME, "HEY", null, null); + options.registerOption(NEW_TEST_OPTION_NAME, "HEY", null, "description"); options.setString(NEW_TEST_OPTION_NAME, TEST_OPTION_STRING_VALUE); return new Pair<>(NEW_TEST_OPTION_NAME, TEST_OPTION_STRING_VALUE); } + private String clearKeyBinding(Options options) { + String keyBindingName = "Go To Next Function (CodeBrowserPlugin)"; + KeyStroke ks = options.getKeyStroke(keyBindingName, null); + assertNotNull(ks); + options.setKeyStroke(keyBindingName, null); + return keyBindingName; + } + private void verifyStringOptionStillChanged_WithoutUsingOptionsAPI(Options options, String optionName) { assertTrue("Options does not have an entry for test option", options.contains(optionName)); @@ -340,6 +376,11 @@ public class ToolPluginOptionsTest extends AbstractGhidraHeadedIntegrationTest { } } + private void verifyKeyBindingIsStillCleared(Options options, String optionName) { + KeyStroke ksValue = options.getKeyStroke(optionName, null); + assertNull(ksValue); + } + private List getDiffs(Map initialValues, Map latestValues) { List diffs = new ArrayList<>(); @@ -354,20 +395,4 @@ public class ToolPluginOptionsTest extends AbstractGhidraHeadedIntegrationTest { return diffs; } - // private OptionsPanel showSearchOptions() { -// List actions = tool.getDockingActionsByFullActionName("Tool Options... (Tool)"); -// assertEquals(1, actions.size()); -// -// performAction(actions.get(0), false); -// -// OptionsDialog dialog = waitForDialogComponent(null, OptionsDialog.class, DEFAULT_WINDOW_TIMEOUT); -// -// OptionsPanel optionsPanel = (OptionsPanel) getInstanceField("panel", dialog); -// GTree tree = (GTree) getInstanceField("gTree", optionsPanel); -// tree.setSelectedNodeByNamePath(new String[] { "Options", "Search" }); -// waitForTree(tree); -// -// return optionsPanel; -// } - } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/ProgramUserDataTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/ProgramUserDataTest.java index 3a717e06f6..dc08557b6a 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/ProgramUserDataTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/ProgramUserDataTest.java @@ -22,7 +22,7 @@ import java.util.Random; import org.junit.*; -import generic.test.AbstractGenericTest; +import generic.test.AbstractGTest; import ghidra.framework.data.ProjectFileManager; import ghidra.framework.model.*; import ghidra.program.model.address.Address; @@ -35,12 +35,12 @@ import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.ProjectTestUtils; import ghidra.util.Msg; import ghidra.util.exception.VersionException; -import ghidra.util.task.TaskMonitorAdapter; +import ghidra.util.task.TaskMonitor; import utilities.util.FileUtilities; public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest { - private String TEMP = AbstractGenericTest.getTestDirectoryPath(); + private String TEMP = AbstractGTest.getTestDirectoryPath(); private static Random RAND = new Random(); private ProjectLocator projectLocator; @@ -60,20 +60,22 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest { userDir = new File(projectLocator.getProjectDir(), ProjectFileManager.USER_FOLDER_NAME); ProgramBuilder builder = new ProgramBuilder("Test", ProgramBuilder._TOY); - df = project.getProjectData().getRootFolder().createFile("test", builder.getProgram(), - TaskMonitorAdapter.DUMMY_MONITOR); + df = project.getProjectData() + .getRootFolder() + .createFile("test", builder.getProgram(), + TaskMonitor.DUMMY); builder.dispose(); Program program = null; try { program = - (Program) df.getDomainObject(this, false, false, TaskMonitorAdapter.DUMMY_MONITOR); + (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY); } catch (VersionException e) { assertTrue(e.isUpgradable()); program = - (Program) df.getDomainObject(this, true, false, TaskMonitorAdapter.DUMMY_MONITOR); - program.save("upgrade", TaskMonitorAdapter.DUMMY_MONITOR); + (Program) df.getDomainObject(this, true, false, TaskMonitor.DUMMY); + program.save("upgrade", TaskMonitor.DUMMY); } finally { program.release(this); @@ -141,27 +143,27 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest { DomainFile df2; Program program = - (Program) df.getDomainObject(this, false, false, TaskMonitorAdapter.DUMMY_MONITOR); + (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY); space = program.getAddressFactory().getDefaultAddressSpace(); try { - assertTrue(!program.isChanged()); + assertFalse(program.isChanged()); assertTrue(program.canSave()); // Modify program content - no user data should be saved change(program); assertTrue(program.isChanged()); - program.save("save", TaskMonitorAdapter.DUMMY_MONITOR); - assertTrue(!program.isChanged()); + program.save("save", TaskMonitor.DUMMY); + assertFalse(program.isChanged()); assertFalse("User data directory should be empty", userDataSubDir.isDirectory()); // Modify user data content ProgramUserData userData = program.getProgramUserData(); change(userData, "STRING", space.getAddress(0), "Str0"); change(userData, "STRING", space.getAddress(10), "Str10"); - assertTrue(!program.isChanged()); + assertFalse(program.isChanged()); String newName = df.getName() + ".1"; - df2 = df.getParent().createFile(newName, program, TaskMonitorAdapter.DUMMY_MONITOR); + df2 = df.getParent().createFile(newName, program, TaskMonitor.DUMMY); } finally { @@ -169,9 +171,9 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest { } program = - (Program) df2.getDomainObject(this, false, false, TaskMonitorAdapter.DUMMY_MONITOR); + (Program) df2.getDomainObject(this, false, false, TaskMonitor.DUMMY); try { - assertTrue(!program.isChanged()); + assertFalse(program.isChanged()); // Verify user data content ProgramUserData userData = program.getProgramUserData(); @@ -180,7 +182,7 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest { assertEquals("Str0", map.getString(space.getAddress(0))); assertEquals("Str10", map.getString(space.getAddress(10))); assertNull(map.getString(space.getAddress(20))); - assertTrue(!program.isChanged()); + assertFalse(program.isChanged()); } finally { program.release(this); @@ -203,17 +205,17 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest { int ver; Program program = - (Program) df.getDomainObject(this, false, false, TaskMonitorAdapter.DUMMY_MONITOR); + (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY); space = program.getAddressFactory().getDefaultAddressSpace(); try { - assertTrue(!program.isChanged()); + assertFalse(program.isChanged()); assertTrue(program.canSave()); // Modify program content - no user data should be saved change(program); assertTrue(program.isChanged()); - program.save("save", TaskMonitorAdapter.DUMMY_MONITOR); - assertTrue(!program.isChanged()); + program.save("save", TaskMonitor.DUMMY); + assertFalse(program.isChanged()); assertFalse("User data directory should be empty", userDataSubDir.isDirectory()); ver = getLatestDbVersion(dbDir); @@ -222,7 +224,7 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest { ProgramUserData userData = program.getProgramUserData(); change(userData, "STRING", space.getAddress(0), "Str0"); change(userData, "STRING", space.getAddress(10), "Str10"); - assertTrue(!program.isChanged()); + assertFalse(program.isChanged()); } finally { @@ -234,9 +236,9 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest { getLatestDbVersion(dbDir)); program = - (Program) df.getDomainObject(this, false, false, TaskMonitorAdapter.DUMMY_MONITOR); + (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY); try { - assertTrue(!program.isChanged()); + assertFalse(program.isChanged()); // Verify user data content ProgramUserData userData = program.getProgramUserData(); @@ -245,21 +247,21 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest { assertEquals("Str0", map.getString(space.getAddress(0))); assertEquals("Str10", map.getString(space.getAddress(10))); assertNull(map.getString(space.getAddress(20))); - assertTrue(!program.isChanged()); + assertFalse(program.isChanged()); // Modify user data content change(userData, "STRING", space.getAddress(10), "Str10a"); change(userData, "STRING", space.getAddress(20), "Str20a"); - assertTrue(!program.isChanged()); + assertFalse(program.isChanged()); } finally { program.release(this); } program = - (Program) df.getDomainObject(this, false, false, TaskMonitorAdapter.DUMMY_MONITOR); + (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY); try { - assertTrue(!program.isChanged()); + assertFalse(program.isChanged()); // Verify user data content ProgramUserData userData = program.getProgramUserData(); @@ -268,7 +270,7 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest { assertEquals("Str0", map.getString(space.getAddress(0))); assertEquals("Str10a", map.getString(space.getAddress(10))); assertEquals("Str20a", map.getString(space.getAddress(20))); - assertTrue(!program.isChanged()); + assertFalse(program.isChanged()); } finally { program.release(this); @@ -287,7 +289,7 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest { // TODO: Multi-user repository connect case not tested Program program = - (Program) df.getDomainObject(this, false, false, TaskMonitorAdapter.DUMMY_MONITOR); + (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY); space = program.getAddressFactory().getDefaultAddressSpace(); try { // Create user data content @@ -307,9 +309,9 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest { df = project.getProjectData().getFile("/test"); program = - (Program) df.getDomainObject(this, false, false, TaskMonitorAdapter.DUMMY_MONITOR); + (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY); try { - assertTrue(!program.isChanged()); + assertFalse(program.isChanged()); // Verify user data content ProgramUserData userData = program.getProgramUserData(); @@ -318,7 +320,7 @@ public class ProgramUserDataTest extends AbstractGhidraHeadedIntegrationTest { assertEquals("Str0", map.getString(space.getAddress(0))); assertEquals("Str10", map.getString(space.getAddress(10))); assertNull(map.getString(space.getAddress(20))); - assertTrue(!program.isChanged()); + assertFalse(program.isChanged()); } finally { program.release(this); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionsTest.java b/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionsTest.java index 792f46f2c9..9e0f92868f 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionsTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionsTest.java @@ -43,10 +43,6 @@ public class OptionsTest extends AbstractGenericTest { private ToolOptions options; - public OptionsTest() { - super(); - } - @Before public void setUp() throws Exception { options = new ToolOptions("Test"); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/actions/ToolActions.java b/Ghidra/Framework/Docking/src/main/java/docking/actions/ToolActions.java index 773356ecd2..592d545f81 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/actions/ToolActions.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/actions/ToolActions.java @@ -399,17 +399,14 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener { } KeyBindingData newKeyBindingData = (KeyBindingData) evt.getNewValue(); - KeyStroke newKeyStroke = null; + KeyStroke newKs = null; if (newKeyBindingData != null) { - newKeyStroke = newKeyBindingData.getKeyBinding(); + newKs = newKeyBindingData.getKeyBinding(); } - KeyStroke optKeyStroke = keyBindingOptions.getKeyStroke(action.getFullName(), null); - if (newKeyStroke == null) { - keyBindingOptions.removeOption(action.getFullName()); - } - else if (!newKeyStroke.equals(optKeyStroke)) { - keyBindingOptions.setKeyStroke(action.getFullName(), newKeyStroke); + KeyStroke currentKs = keyBindingOptions.getKeyStroke(action.getFullName(), null); + if (!Objects.equals(currentKs, newKs)) { + keyBindingOptions.setKeyStroke(action.getFullName(), newKs); keyBindingsChanged(); } } diff --git a/Ghidra/Framework/Docking/src/test.slow/java/docking/actions/SharedKeyBindingDockingActionTest.java b/Ghidra/Framework/Docking/src/test.slow/java/docking/actions/SharedKeyBindingDockingActionTest.java index e3cb5222dd..58fdfaff56 100644 --- a/Ghidra/Framework/Docking/src/test.slow/java/docking/actions/SharedKeyBindingDockingActionTest.java +++ b/Ghidra/Framework/Docking/src/test.slow/java/docking/actions/SharedKeyBindingDockingActionTest.java @@ -66,8 +66,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { @Test public void testSharedKeyBinding_SameDefaultKeyBindings() { - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); - TestAction action2 = new TestAction(OWNER_2, DEFAULT_KS_1); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action2 = new SharedNameAction(OWNER_2, DEFAULT_KS_1); tool.addAction(action1); tool.addAction(action2); @@ -81,8 +81,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { @Test public void testSharedKeyBinding_OptionsChange() { - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); - TestAction action2 = new TestAction(OWNER_2, DEFAULT_KS_1); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action2 = new SharedNameAction(OWNER_2, DEFAULT_KS_1); tool.addAction(action1); tool.addAction(action2); @@ -99,8 +99,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { @Test public void testSharedKeyBinding_DifferentDefaultKeyBindings() { - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); - TestAction action2 = new TestAction(OWNER_2, DEFAULT_KS_DIFFERENT_THAN_1); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action2 = new SharedNameAction(OWNER_2, DEFAULT_KS_DIFFERENT_THAN_1); tool.addAction(action1); tool.addAction(action2); @@ -115,8 +115,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { @Test public void testSharedKeyBinding_NoDefaultKeyBindings() { - TestAction action1 = new TestAction(OWNER_1, null); - TestAction action2 = new TestAction(OWNER_2, null); + SharedNameAction action1 = new SharedNameAction(OWNER_1, null); + SharedNameAction action2 = new SharedNameAction(OWNER_2, null); tool.addAction(action1); tool.addAction(action2); @@ -130,8 +130,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { @Test public void testSharedKeyBinding_OneDefaultOneUndefinedDefaultKeyBinding() { - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); - TestAction action2 = new TestAction(OWNER_2, null); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action2 = new SharedNameAction(OWNER_2, null); tool.addAction(action1); tool.addAction(action2); @@ -146,8 +146,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { @Test public void testSharedKeyBinding_RemoveAction() { - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); - TestAction action2 = new TestAction(OWNER_2, DEFAULT_KS_1); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action2 = new SharedNameAction(OWNER_2, DEFAULT_KS_1); tool.addAction(action1); tool.addAction(action2); @@ -166,7 +166,7 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { @Test public void testSharedKeyBinding_AddSameActionTwice() { - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); tool.addAction(action1); @@ -188,8 +188,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { @Test public void testSharedKeyBinding_OnlyOneEntryInOptions() { - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); - TestAction action2 = new TestAction(OWNER_2, DEFAULT_KS_1); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action2 = new SharedNameAction(OWNER_2, DEFAULT_KS_1); tool.addAction(action1); tool.addAction(action2); @@ -205,8 +205,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { @Test public void testSharedKeyBinding_AddActionAfterOptionHasChanged() { - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); - TestAction action2 = new TestAction(OWNER_2, DEFAULT_KS_1); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action2 = new SharedNameAction(OWNER_2, DEFAULT_KS_1); tool.addAction(action1); KeyStroke newKs = KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0); @@ -223,8 +223,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { @Test public void testSharedKeyBinding_AddActionAfterOptionHasChanged_RepeatAddRemove() { - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); - TestAction action2 = new TestAction(OWNER_2, DEFAULT_KS_1); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action2 = new SharedNameAction(OWNER_2, DEFAULT_KS_1); tool.addAction(action1); KeyStroke newKs = KeyStroke.getKeyStroke(KeyEvent.VK_Z, 0); @@ -248,8 +248,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { @Test public void testSharedKeyBinding_SameDefaultKeyBindings_LocalAction() { - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); - TestAction action2 = new TestAction(OWNER_2, DEFAULT_KS_1); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action2 = new SharedNameAction(OWNER_2, DEFAULT_KS_1); DummyComponentProvider provider = new DummyComponentProvider(); tool.addLocalAction(provider, action1); @@ -264,8 +264,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { @Test public void testSharedKeyBinding_RemoveAction_LocalAction() { - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); - TestAction action2 = new TestAction(OWNER_2, DEFAULT_KS_1); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action2 = new SharedNameAction(OWNER_2, DEFAULT_KS_1); DummyComponentProvider provider = new DummyComponentProvider(); tool.addLocalAction(provider, action1); @@ -285,8 +285,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { @Test public void testSharedKeyBinding_RemoveComonentActions() { - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); - TestAction action2 = new TestAction(OWNER_2, DEFAULT_KS_1); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action2 = new SharedNameAction(OWNER_2, DEFAULT_KS_1); DummyComponentProvider provider = new DummyComponentProvider(); tool.addLocalAction(provider, action1); @@ -313,8 +313,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { // same name and owner. // - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); - TestAction action1Copy = new TestAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action1Copy = new SharedNameAction(OWNER_1, DEFAULT_KS_1); tool.addAction(action1); tool.addAction(action1Copy); @@ -342,8 +342,8 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { // same name and owner. // - TestAction action1 = new TestAction(OWNER_1, DEFAULT_KS_1); - TestAction action1Copy = new TestAction(OWNER_1, DEFAULT_KS_DIFFERENT_THAN_1); + SharedNameAction action1 = new SharedNameAction(OWNER_1, DEFAULT_KS_1); + SharedNameAction action1Copy = new SharedNameAction(OWNER_1, DEFAULT_KS_DIFFERENT_THAN_1); tool.addAction(action1); tool.addAction(action1Copy); @@ -484,7 +484,7 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { spyLogger.assertLogMessage("shared", "key", "binding", "actions", "different", "default"); } - private void assertKeyBinding(TestAction action, KeyStroke expectedKs) { + private void assertKeyBinding(SharedNameAction action, KeyStroke expectedKs) { assertEquals(expectedKs, action.getKeyBinding()); } @@ -492,9 +492,9 @@ public class SharedKeyBindingDockingActionTest extends AbstractDockingTest { // Inner Classes //================================================================================================== - private class TestAction extends DockingAction { + private class SharedNameAction extends DockingAction { - public TestAction(String owner, KeyStroke ks) { + public SharedNameAction(String owner, KeyStroke ks) { super(SHARED_NAME, owner, KeyBindingType.SHARED); setKeyBindingData(new KeyBindingData(ks)); } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/AbstractOptions.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/AbstractOptions.java index fd5cb08458..2dc0e52be7 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/AbstractOptions.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/AbstractOptions.java @@ -116,8 +116,8 @@ public abstract class AbstractOptions implements Options { "Attempted to register an unsupported object: " + defaultValue.getClass()); } - registerOption(optionName, OptionType.getOptionType(defaultValue), defaultValue, help, - description); + OptionType type = OptionType.getOptionType(defaultValue); + registerOption(optionName, type, defaultValue, help, description); } @Override @@ -150,16 +150,41 @@ public abstract class AbstractOptions implements Options { valueMap.put(optionName, option); return; } - else if (!currentOption.isRegistered()) { - Option option = + + Option newOption = null; + if (currentOption.isRegistered()) { + // Registered again + newOption = + copyRegisteredOption(currentOption, type, description, defaultValue, help, editor); + } + else { + // option was accessed, but not registered + newOption = createRegisteredOption(optionName, type, description, help, defaultValue, editor); - option.setCurrentValue(currentOption.getCurrentValue()); - valueMap.put(optionName, option); - return; } - // TODO: We probably don't need to do anything special if we are re-registering an - // option, which is what the below code handles. + copyCurrentValue(currentOption, newOption); + valueMap.put(optionName, newOption); + } + + private void copyCurrentValue(Option currentOption, Option newOption) { + + Object currentValue = currentOption.getCurrentValue(); + OptionType type = currentOption.getOptionType(); + if (!isNullable(type) && currentValue == null) { + return; // not allowed to be null + } + + // null is allowed; null can represent a valid 'cleared' state + newOption.setCurrentValue(currentValue); + + } + + private Option copyRegisteredOption(Option currentOption, OptionType type, + String description, Object defaultValue, HelpLocation help, PropertyEditor editor) { + + // We probably don't need to do anything special if we are re-registering an option, + // which is what the below code handles String oldDescription = currentOption.getDescription(); HelpLocation oldHelp = currentOption.getHelpLocation(); Object oldDefaultValue = currentOption.getDefaultValue(); @@ -170,13 +195,9 @@ public abstract class AbstractOptions implements Options { Object newDefaultValue = oldDefaultValue == null ? defaultValue : oldDefaultValue; PropertyEditor newEditor = oldEditor == null ? editor : oldEditor; - Option newOption = createRegisteredOption(optionName, type, newDescripiton, newHelpLocation, + String optionName = currentOption.getName(); + return createRegisteredOption(optionName, type, newDescripiton, newHelpLocation, newDefaultValue, newEditor); - Object currentValue = currentOption.getCurrentValue(); - if (currentValue != null) { - newOption.setCurrentValue(currentValue); - } - valueMap.put(optionName, newOption); } @Override @@ -249,6 +270,10 @@ public abstract class AbstractOptions implements Options { } OptionType type = option.getOptionType(); + return isNullable(type); + } + + private boolean isNullable(OptionType type) { switch (type) { // objects can be null @@ -396,8 +421,8 @@ public abstract class AbstractOptions implements Options { public Font getFont(String optionName, Font defaultValue) { Option option = getOption(optionName, OptionType.FONT_TYPE, defaultValue); try { - return (Font) option.getValue(defaultValue); - } + return (Font) option.getValue(defaultValue); + } catch (ClassCastException e) { return defaultValue; } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/Option.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/Option.java index f5d91631a1..ce5e5c258a 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/Option.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/Option.java @@ -1,6 +1,5 @@ /* ### * 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. @@ -16,10 +15,12 @@ */ package ghidra.framework.options; +import java.beans.PropertyEditor; +import java.util.Objects; + import ghidra.util.HelpLocation; import ghidra.util.SystemUtilities; - -import java.beans.PropertyEditor; +import utilities.util.reflection.ReflectionUtilities; public abstract class Option { private final String name; @@ -68,23 +69,19 @@ public abstract class Option { return helpLocation; } - public boolean hasValue() { - return defaultValue != null || getCurrentValue() != null; - } - public String getDescription() { return description == null ? "Unregistered Option" : description; } public Object getValue(Object passedInDefaultValue) { Object value = getCurrentValue(); - if (value != null) { - return value; + if (value == null && defaultValue == null) { + // Assume that both values being null is an indication that there is no value + // to use. Otherwise, a null current value implies that the user has cleared + // the default value. + return passedInDefaultValue; } - if (defaultValue != null) { - return defaultValue; - } - return passedInDefaultValue; + return value; } public boolean isRegistered() { @@ -97,11 +94,7 @@ public abstract class Option { public boolean isDefault() { Object value = getCurrentValue(); - if (value == null) { - return true; - } - - return value.equals(defaultValue); + return Objects.equals(value, defaultValue); } @Override @@ -125,46 +118,12 @@ public abstract class Option { Throwable throwable = new Throwable(); StackTraceElement[] stackTrace = throwable.getStackTrace(); - String information = getInceptionInformationFromTheFirstClassThatIsNotUs(stackTrace); - inceptionInformation = information; - } - - private String getInceptionInformationFromTheFirstClassThatIsNotUs( - StackTraceElement[] stackTrace) { - - // To find our creation point we can use a simple algorithm: find the name of our class, - // which is in the first stack trace element and then keep walking backwards until that - // name is not ours. - // - String myClassName = getClass().getName(); - int myClassNameStartIndex = -1; - for (int i = 1; i < stackTrace.length; i++) { // start at 1, because we are the first item - StackTraceElement stackTraceElement = stackTrace[i]; - String elementClassName = stackTraceElement.getClassName(); - if (myClassName.equals(elementClassName)) { - myClassNameStartIndex = i; - break; - } - } - - // Finally, go backwards until we find a non-options class in the stack, in order - // to remove infrastructure code from the client that called the options API. - int creatorIndex = myClassNameStartIndex; - for (int i = myClassNameStartIndex; i < stackTrace.length; i++) { // start at 1, because we are the first item - StackTraceElement stackTraceElement = stackTrace[i]; - String elementClassName = stackTraceElement.getClassName(); - - if (elementClassName.toLowerCase().indexOf("option") == -1) { - creatorIndex = i; - break; - } - } - - return stackTrace[creatorIndex].toString(); + StackTraceElement[] filteredTrace = + ReflectionUtilities.filterStackTrace(stackTrace, "option", "OptionsManager"); + inceptionInformation = filteredTrace[0].toString(); } public OptionType getOptionType() { return optionType; } - } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ToolOptions.java b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ToolOptions.java index 46661215b7..ebaf483e2b 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ToolOptions.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/framework/options/ToolOptions.java @@ -41,6 +41,10 @@ import ghidra.util.exception.AssertException; * The Options Dialog shows the hierarchy in tree format. */ public class ToolOptions extends AbstractOptions { + private static final String CLASS_ATTRIBUTE = "CLASS"; + private static final String NAME_ATTRIBUTE = "NAME"; + private static final String WRAPPED_OPTION_NAME = "WRAPPED_OPTION"; + private static final String CLEARED_VALUE_ELEMENT_NAME = "CLEARED_VALUE"; public static final Set> PRIMITIVE_CLASSES = buildPrimitiveClassSet(); public static final Set> WRAPPABLE_CLASSES = buildWrappableClassSet(); @@ -81,34 +85,57 @@ public class ToolOptions extends AbstractOptions { * @param root XML that contains the set of options to restore */ public ToolOptions(Element root) { - this(root.getAttributeValue("NAME")); + this(root.getAttributeValue(NAME_ATTRIBUTE)); SaveState saveState = new SaveState(root); + readNonWrappedOptions(saveState); + + try { + readWrappedOptions(root); + } + catch (ReflectiveOperationException exc) { + Msg.error(this, "Unexpected Exception: " + exc.getMessage(), exc); + } + } + + private void readNonWrappedOptions(SaveState saveState) { for (String optionName : saveState.getNames()) { Object object = saveState.getObject(optionName); Option option = createUnregisteredOption(optionName, OptionType.getOptionType(object), null); option.doSetCurrentValue(object); // use doSet versus set so that it is not registered valueMap.put(optionName, option); - } + } - Iterator iter = root.getChildren("WRAPPED_OPTION").iterator(); - while (iter.hasNext()) { - try { - Element elem = (Element) iter.next(); - String optionName = elem.getAttributeValue("NAME"); - Class c = Class.forName(elem.getAttributeValue("CLASS")); - Constructor constructor = c.getDeclaredConstructor(); - WrappedOption wo = (WrappedOption) constructor.newInstance(); - wo.readState(new SaveState(elem)); - Option option = createUnregisteredOption(optionName, wo.getOptionType(), null); - option.doSetCurrentValue(wo.getObject());// use doSet versus set so that it is not registered - valueMap.put(optionName, option); + private void readWrappedOptions(Element root) throws ReflectiveOperationException { + + Iterator it = root.getChildren(WRAPPED_OPTION_NAME).iterator(); + while (it.hasNext()) { + + Element element = (Element) it.next(); + List children = element.getChildren(); + if (children.isEmpty()) { + continue; // shouldn't happen } - catch (Exception exc) { - Msg.error(this, "Unexpected Exception: " + exc.getMessage(), exc); + + String optionName = element.getAttributeValue(NAME_ATTRIBUTE); + Class c = Class.forName(element.getAttributeValue(CLASS_ATTRIBUTE)); + Constructor constructor = c.getDeclaredConstructor(); + WrappedOption wo = (WrappedOption) constructor.newInstance(); + Option option = createUnregisteredOption(optionName, wo.getOptionType(), null); + valueMap.put(optionName, option); + + Element child = (Element) children.get(0); + String elementName = child.getName(); + if (CLEARED_VALUE_ELEMENT_NAME.equals(elementName)) { + // a signal that the default option value has been cleared + option.doSetCurrentValue(null); // use doSet so that it is not registered + } + else { + wo.readState(new SaveState(element)); + option.doSetCurrentValue(wo.getObject()); // use doSet so that it is not registered } } } @@ -122,8 +149,20 @@ public class ToolOptions extends AbstractOptions { * @return the xml root element */ public Element getXmlRoot(boolean includeDefaultBindings) { + SaveState saveState = new SaveState(XML_ELEMENT_NAME); + writeNonWrappedOptions(includeDefaultBindings, saveState); + + Element root = saveState.saveToXml(); + root.setAttribute(NAME_ATTRIBUTE, name); + + writeWrappedOptions(includeDefaultBindings, root); + + return root; + } + + private void writeNonWrappedOptions(boolean includeDefaultBindings, SaveState saveState) { for (String optionName : valueMap.keySet()) { Option optionValue = valueMap.get(optionName); if (includeDefaultBindings || !optionValue.isDefault()) { @@ -133,27 +172,43 @@ public class ToolOptions extends AbstractOptions { } } } + } - Element root = saveState.saveToXml(); - root.setAttribute("NAME", name); - + private void writeWrappedOptions(boolean includeDefaultBindings, Element root) { for (String optionName : valueMap.keySet()) { - Option optionValue = valueMap.get(optionName); - if (includeDefaultBindings || !optionValue.isDefault()) { - Object value = optionValue.getValue(null); - if (value != null && !isSupportedBySaveState(value)) { - WrappedOption wrappedOption = wrapOption(value); - SaveState ss = new SaveState("WRAPPED_OPTION"); - wrappedOption.writeState(ss); - Element elem = ss.saveToXml(); - elem.setAttribute("NAME", optionName); - elem.setAttribute("CLASS", wrappedOption.getClass().getName()); - root.addContent(elem); + Option option = valueMap.get(optionName); + if (includeDefaultBindings || !option.isDefault()) { + + Object value = option.getCurrentValue(); + if (isSupportedBySaveState(value)) { + // handled above + continue; } + + WrappedOption wrappedOption = wrapOption(option); + if (wrappedOption == null) { + // cannot write an option without a value to determine its type + continue; + } + + SaveState ss = new SaveState(WRAPPED_OPTION_NAME); + Element elem = null; + if (value == null) { + // Handle the null case ourselves, not using the wrapped option (and when + // reading from xml) so that the logic does not need to in each wrapped option + elem = ss.saveToXml(); + elem.addContent(new Element(CLEARED_VALUE_ELEMENT_NAME)); + } + else { + wrappedOption.writeState(ss); + elem = ss.saveToXml(); + } + + elem.setAttribute(NAME_ATTRIBUTE, optionName); + elem.setAttribute(CLASS_ATTRIBUTE, wrappedOption.getClass().getName()); + root.addContent(elem); } } - - return root; } private boolean isSupportedBySaveState(Object obj) { @@ -170,7 +225,19 @@ public class ToolOptions extends AbstractOptions { } - private WrappedOption wrapOption(Object value) { + private WrappedOption wrapOption(Option option) { + + Object value = null; + value = option.getCurrentValue(); + if (value == null) { + value = option.getDefaultValue(); + } + + if (value == null) { + // nothing to wrap + return null; + } + if (value instanceof CustomOption) { return new WrappedCustomOption((CustomOption) value); } @@ -232,44 +299,6 @@ public class ToolOptions extends AbstractOptions { } } - //////////////////////////////////////////////////////////////// - - private class NotifyListenersRunnable implements Runnable { - private String optionName; - private Object oldValue; - private Object newValue; - private boolean vetoed; - - NotifyListenersRunnable(String optionName, Object oldValue, Object newValue) { - this.optionName = optionName; - this.oldValue = oldValue; - this.newValue = newValue; - } - - @Override - public void run() { - List notifiedListeners = new ArrayList<>(); - try { - for (OptionsChangeListener listener : listeners) { - listener.optionsChanged(ToolOptions.this, optionName, oldValue, newValue); - notifiedListeners.add(listener); - } - } - catch (OptionsVetoException e) { - vetoed = true; - for (OptionsChangeListener notifiedListener : notifiedListeners) { - notifiedListener.optionsChanged(ToolOptions.this, optionName, newValue, - oldValue); - } - } - } - - public boolean wasVetoed() { - return vetoed; - } - - } - /** * Adds all the options name/value pairs to this Options. * @param newOptions the new options into which the current options values will be placed @@ -356,6 +385,8 @@ public class ToolOptions extends AbstractOptions { ToolOption(String name, OptionType type, String description, HelpLocation helpLocation, Object defaultValue, boolean isRegistered, PropertyEditor editor) { super(name, type, description, helpLocation, defaultValue, isRegistered, editor); + + this.currentValue = defaultValue; } @Override @@ -385,7 +416,44 @@ public class ToolOptions extends AbstractOptions { protected boolean notifyOptionChanged(String optionName, Object oldValue, Object newValue) { NotifyListenersRunnable runnable = new NotifyListenersRunnable(optionName, oldValue, newValue); - SystemUtilities.runSwingNow(runnable); + Swing.runNow(runnable); return !runnable.wasVetoed(); } + + private class NotifyListenersRunnable implements Runnable { + private String optionName; + private Object oldValue; + private Object newValue; + private boolean vetoed; + + NotifyListenersRunnable(String optionName, Object oldValue, Object newValue) { + this.optionName = optionName; + this.oldValue = oldValue; + this.newValue = newValue; + } + + @Override + public void run() { + List notifiedListeners = new ArrayList<>(); + try { + for (OptionsChangeListener listener : listeners) { + listener.optionsChanged(ToolOptions.this, optionName, oldValue, newValue); + notifiedListeners.add(listener); + } + } + catch (OptionsVetoException e) { + vetoed = true; + for (OptionsChangeListener notifiedListener : notifiedListeners) { + notifiedListener.optionsChanged(ToolOptions.this, optionName, newValue, + oldValue); + } + } + } + + public boolean wasVetoed() { + return vetoed; + } + + } + } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/OptionsDB.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/OptionsDB.java index 942a9c72ae..69381ffaf9 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/OptionsDB.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/OptionsDB.java @@ -26,8 +26,7 @@ import ghidra.util.SystemUtilities; import ghidra.util.exception.ClosedException; /** - * - * + * Database implementation of {@link Option} */ class OptionsDB extends AbstractOptions { @@ -42,8 +41,6 @@ class OptionsDB extends AbstractOptions { private Table propertyTable; private DomainObjectAdapterDB domainObj; - /** - */ OptionsDB(DomainObjectAdapterDB domainObj) { super(""); this.domainObj = domainObj; @@ -59,7 +56,7 @@ class OptionsDB extends AbstractOptions { * the corresponding oldPath properties will be removed. * @throws IllegalStateException if list has been manipulated since construction * @throws IllegalArgumentException if invalid property alterations are provided - * @throws IOException + * @throws IOException if there is an exception moving or deleting a property */ synchronized void performAlterations(Map propertyAlterations) throws IOException { @@ -108,7 +105,7 @@ class OptionsDB extends AbstractOptions { } // move records - ArrayList list = new ArrayList(); + ArrayList list = new ArrayList<>(); rec = propertyTable.getRecord(new StringField(oldPath)); if (rec != null) { propertyTable.deleteRecord(new StringField(oldPath)); @@ -182,7 +179,7 @@ class OptionsDB extends AbstractOptions { @Override public synchronized List getOptionNames() { - Set names = new HashSet(valueMap.keySet()); + Set names = new HashSet<>(valueMap.keySet()); names.addAll(aliasMap.keySet()); try { if (propertyTable != null) { @@ -196,7 +193,7 @@ class OptionsDB extends AbstractOptions { catch (IOException e) { domainObj.dbError(e); } - List optionNames = new ArrayList(names); + List optionNames = new ArrayList<>(names); Collections.sort(optionNames); return optionNames; } @@ -253,16 +250,6 @@ class OptionsDB extends AbstractOptions { } } -// Property getProperty(String propertyName) { -// Record rec = getPropertyRecord(propertyName); -// if (rec == null) { -// return null; -// } -// int propertyOrdinal = rec.getByteValue(TYPE_COL); -// OptionType propertyType = OptionType.values()[propertyOrdinal]; -// return createProperty(propertyName, propertyType, null); -// } - class DBOption extends Option { private Object value = null; private boolean isCached = false; @@ -270,6 +257,8 @@ class OptionsDB extends AbstractOptions { protected DBOption(String name, OptionType type, String description, HelpLocation help, Object defaultValue, boolean isRegistered, PropertyEditor editor) { super(name, type, description, help, defaultValue, isRegistered, editor); + + getCurrentValue(); // initialize our defaults } @Override diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/KeyBindingsPanel.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/KeyBindingsPanel.java index c9276ba358..424d13e454 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/KeyBindingsPanel.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/KeyBindingsPanel.java @@ -123,19 +123,9 @@ public class KeyBindingsPanel extends JPanel { return; } - if (newKeyStroke != null) { - options.setKeyStroke(fullActionName, newKeyStroke); - } - else { - options.removeOption(fullActionName); - } + options.setKeyStroke(fullActionName, newKeyStroke); originalValues.put(fullActionName, newKeyStroke); keyStrokesByFullName.put(fullActionName, newKeyStroke); - - List actions = actionsByFullName.get(fullActionName); - for (DockingActionIf action : actions) { - action.setUnvalidatedKeyBindingData(new KeyBindingData(newKeyStroke)); - } } public void cancel() { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java index fece367ff5..b9f75b8e03 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java @@ -57,7 +57,6 @@ import ghidra.program.util.*; import ghidra.util.*; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; -import ghidra.util.task.TaskMonitorAdapter; /** * Database implementation for Program. @@ -199,10 +198,8 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM private OverlaySpaceAdapterDB overlaySpaceAdapter; - private HashMap addrSetPropertyMap = new HashMap<>(); - private HashMap intRangePropertyMap = new HashMap<>(); - - private HashSet changedFunctionIDs = new HashSet<>(); + private Map addrSetPropertyMap = new HashMap<>(); + private Map intRangePropertyMap = new HashMap<>(); /** * Constructs a new ProgramDB @@ -232,12 +229,12 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM int id = startTransaction("create program"); createDatabase(); - if (createManagers(CREATE, TaskMonitorAdapter.DUMMY_MONITOR) != null) { + if (createManagers(CREATE, TaskMonitor.DUMMY) != null) { throw new AssertException("Unexpected version exception on create"); } listing = new ListingDB(); changeSet = new ProgramDBChangeSet(addrMap, NUM_UNDOS); - initManagers(CREATE, TaskMonitorAdapter.DUMMY_MONITOR); + initManagers(CREATE, TaskMonitor.DUMMY); propertiesCreate(); programUserData = new ProgramUserDataDB(this); endTransaction(id, true); @@ -273,7 +270,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM * @throws IOException if an error accessing the database occurs. * @throws VersionException if database version does not match implementation, UPGRADE may be possible. * @throws CancelledException if instantiation is canceled by monitor - * @throws LanguageNotFoundException + * @throws LanguageNotFoundException if a language cannot be found for this program */ public ProgramDB(DBHandle dbh, int openMode, TaskMonitor monitor, Object consumer) throws IOException, VersionException, LanguageNotFoundException, CancelledException { @@ -281,7 +278,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM super(dbh, "Untitled", 500, 1000, consumer); if (monitor == null) { - monitor = TaskMonitorAdapter.DUMMY; + monitor = TaskMonitor.DUMMY; } boolean success = false; @@ -369,7 +366,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM /** * Initialize program compiler specification. * During a language upgrade this will provide a temporary spec until setLanguage is complete. - * @throws CompilerSpecNotFoundException + * @throws CompilerSpecNotFoundException if the compiler spec cannot be found */ private void initCompilerSpec() throws CompilerSpecNotFoundException { try { @@ -399,8 +396,8 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM * @param openMode one of: * READ_ONLY: the original database will not be modified * UPDATE: the database can be written to. - * UPGRADE: the database is upgraded to the lastest schema as it is opened. - * @throws LanguageNotFoundException + * UPGRADE: the database is upgraded to the latest schema as it is opened. + * @throws LanguageNotFoundException if a language cannot be found for this program * @return VersionException if language upgrade required */ private VersionException checkLanguageVersion(int openMode) throws LanguageNotFoundException { @@ -409,8 +406,9 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM Language newLanguage = language; - Language oldLanguage = OldLanguageFactory.getOldLanguageFactory().getOldLanguage( - languageID, languageVersion); + Language oldLanguage = OldLanguageFactory.getOldLanguageFactory() + .getOldLanguage( + languageID, languageVersion); if (oldLanguage == null) { // Assume minor version behavior - old language does not exist for current major version Msg.error(this, "Old language specification not found: " + languageID + @@ -420,8 +418,9 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM // Ensure that we can upgrade the language languageUpgradeTranslator = - LanguageTranslatorFactory.getLanguageTranslatorFactory().getLanguageTranslator( - oldLanguage, newLanguage); + LanguageTranslatorFactory.getLanguageTranslatorFactory() + .getLanguageTranslator( + oldLanguage, newLanguage); if (languageUpgradeTranslator == null) { // TODO: This is a bad situation!! Most language revisions should be supportable, if not we have no choice but to throw @@ -451,12 +450,12 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM /** * Language specified by languageName was not found. Check for - * valid language translation/migration. Old langauge version specified by + * valid language translation/migration. Old language version specified by * languageVersion. * @param openMode one of: * READ_ONLY: the original database will not be modified * UPDATE: the database can be written to. - * UPGRADE: the database is upgraded to the lastest schema as it is opened. + * UPGRADE: the database is upgraded to the latest schema as it is opened. * @return true if language upgrade required * @throws LanguageNotFoundException if a suitable replacement language not found */ @@ -464,8 +463,9 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM throws LanguageNotFoundException { languageUpgradeTranslator = - LanguageTranslatorFactory.getLanguageTranslatorFactory().getLanguageTranslator( - languageID, languageVersion); + LanguageTranslatorFactory.getLanguageTranslatorFactory() + .getLanguageTranslator( + languageID, languageVersion); if (languageUpgradeTranslator == null) { throw e; } @@ -514,10 +514,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM changed = origChangeState; } - /** - * Set the program user data - * @param programUserData - */ void setProgramUserData(ProgramUserDataDB programUserData) { this.programUserData = programUserData; } @@ -571,9 +567,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM return memoryManager; } - /** - * returns the namespace manager - */ public NamespaceManager getNamespaceManager() { return (NamespaceManager) managers[NAMESPACE_MGR]; } @@ -583,16 +576,10 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM return (ReferenceManager) managers[REF_MGR]; } - /** - * Returns the CodeManager - */ public CodeManager getCodeManager() { return (CodeManager) managers[CODE_MGR]; } - /** - * Returns the TreeManager - */ public TreeManager getTreeManager() { return (TreeManager) managers[TREE_MGR]; } @@ -655,6 +642,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM format = pl.getString(EXECUTABLE_FORMAT, (String) null); } catch (Exception e) { + // handled below } return format == null ? UNKNOWN : format; } @@ -674,6 +662,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM format = pl.getString(EXECUTABLE_MD5, (String) null); } catch (Exception e) { + // handled below } return format == null ? UNKNOWN : format; } @@ -693,6 +682,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM format = pl.getString(EXECUTABLE_SHA256, (String) null); } catch (Exception e) { + // handled below } return format == null ? UNKNOWN : format; } @@ -910,6 +900,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM * Notification that a program tree was changed. * @param id the id of the program tree that was changed. * @param type the type of change + * @param affectedObj the object that was changed * @param oldValue old value depends on the type of the change * @param newValue old value depends on the type of the change */ @@ -960,7 +951,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM * @param symbol the symbol that was changed. * @param type the type of change * @param addr the address of the symbol that changed - * @param affectedObj + * @param affectedObj the object that was changed * @param oldValue old value depends on the type of the change * @param newValue old value depends on the type of the change */ @@ -1023,10 +1014,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM fireEvent(new ProgramChangeRecord(type, addr, addr, null, oldValue, newValue)); } - public HashSet getChangedFunctionTagIDs() { - return this.changedFunctionIDs; - } - @Override public void setRegisterValuesChanged(Register register, Address start, Address end) { if (recordChanges) { @@ -1043,27 +1030,11 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM new ProgramChangeRecord(DOCR_REGISTER_VALUES_CHANGED, start, end, null, null, null)); } - /** - * Mark the state this Program as having changed and generate - * the event. Any or all parameters may be null. - * @param type event type - * @param oldValue original value - * @param newValue new value - */ @Override public void setChanged(int type, Object oldValue, Object newValue) { setChanged(type, (Address) null, (Address) null, oldValue, newValue); } - /** - * Mark the state this Program as having changed and generate - * the event. Any or all parameters may be null. - * @param type event type - * @param start starting address that is affected by the event - * @param end ending address that is affected by the event - * @param oldValue original value - * @param newValue new value - */ @Override public void setChanged(int type, Address start, Address end, Object oldValue, Object newValue) { @@ -1084,37 +1055,12 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM fireEvent(new ProgramChangeRecord(type, newstart, newend, null, oldValue, newValue)); } - /** - * Mark the state of a Program as having changed and generate - * the event. Any or all parameters may be null. - * NOTE: ChangeSet data will not be updated since this a very generic - * change not related to a specific address. - * @param type event type - * @param affectedObj object that is the subject of the event - * @param oldValue original value or an Object that is related to - * the event - * @param newValue new value or an Object that is related to the - * the event - */ @Override public void setObjChanged(int type, Object affectedObj, Object oldValue, Object newValue) { changed = true; fireEvent(new ProgramChangeRecord(type, null, null, affectedObj, oldValue, newValue)); } - /** - * Mark the state of a Program as having changed and generate - * the event. Any or all parameters may be null. - * NOTE: ChangeSet data will not be updated since this a very generic - * change not related to a specific address. - * @param type event type - * @param subType event sub-type - * @param affectedObj object that is the subject of the event - * @param oldValue original value or an Object that is related to - * the event - * @param newValue new value or an Object that is related to the - * the event - */ @Override public void setObjChanged(int type, int subType, Object affectedObj, Object oldValue, Object newValue) { @@ -1123,17 +1069,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM new ProgramChangeRecord(type, subType, null, null, affectedObj, oldValue, newValue)); } - /** - * Mark the state of a Program as having changed and generate - * the event. Any or all parameters may be null. - * @param type event type - * @param addr program address affected - * @param affectedObj object that is the subject of the event - * @param oldValue original value or an Object that is related to - * the event - * @param newValue new value or an Object that is related to the - * the event - */ @Override public void setObjChanged(int type, Address addr, Object affectedObj, Object oldValue, Object newValue) { @@ -1144,18 +1079,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM fireEvent(new ProgramChangeRecord(type, addr, addr, affectedObj, oldValue, newValue)); } - /** - * Mark the state of a Program as having changed and generate - * the event. Any or all parameters may be null. - * @param type event type - * @param subType event sub-type - * @param addr program address affected - * @param affectedObj object that is the subject of the event - * @param oldValue original value or an Object that is related to - * the event - * @param newValue new value or an Object that is related to the - * the event - */ @Override public void setObjChanged(int type, int subType, Address addr, Object affectedObj, Object oldValue, Object newValue) { @@ -1167,17 +1090,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM new ProgramChangeRecord(type, subType, addr, addr, affectedObj, oldValue, newValue)); } - /** - * Mark the state of a Program as having changed and generate - * the event. Any or all parameters may be null. - * @param type event type - * @param addrSet set of program addresses affected - * @param affectedObj object that is the subject of the event - * @param oldValue original value or an Object that is related to - * the event - * @param newValue new value or an Object that is related to the - * the event - */ @Override public void setObjChanged(int type, AddressSetView addrSet, Object affectedObj, Object oldValue, Object newValue) { @@ -1188,9 +1100,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM fireEvent(new ProgramChangeRecord(type, null, null, affectedObj, oldValue, newValue)); } - /** - * Method updateChanges over range - */ private void updateChangeSet(Address start, Address end) { ProgramDBChangeSet pcs = (ProgramDBChangeSet) changeSet; if (start != null) { @@ -1201,23 +1110,12 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM } } - /** - * Method updateChanges over address set - */ private void updateChangeSet(AddressSetView addrSet) { if (addrSet != null) { ((ProgramDBChangeSet) changeSet).add(addrSet); } } - /** - * Mark the state of a Program as having changed and generate - * the DOCR_CODE_UNIT_PROPERTY_CHANGED event. - * @param propertyName - * @param codeUnitAddr address of the code unit with the property change - * @param oldValue old value for the property - * @param newValue new value for the property - */ @Override public void setPropertyChanged(String propertyName, Address codeUnitAddr, Object oldValue, Object newValue) { @@ -1228,13 +1126,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM fireEvent(new CodeUnitPropertyChangeRecord(propertyName, codeUnitAddr, oldValue, newValue)); } - /** - * Mark the state of a Program as having changed and generate - * the DOCR_CODE_UNIT_PROPERTY_RANGE_REMOVED event. - * @param propertyName name of the property - * @param start start of range of the property being removed - * @param end end of the range of the property being removed - */ @Override public void setPropertyRangeRemoved(String propertyName, Address start, Address end) { if (recordChanges) { @@ -1244,25 +1135,12 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM fireEvent(new CodeUnitPropertyChangeRecord(propertyName, start, end)); } - /** - * Notify program of a user data change - * @param propertyName - * @param codeUnitAddr - * @param oldValue - * @param newValue - */ void userDataChanged(String propertyName, Address codeUnitAddr, Object oldValue, Object newValue) { // Do not update change set! fireEvent(new CodeUnitUserDataChangeRecord(propertyName, codeUnitAddr, oldValue, newValue)); } - /** - * Notification of property change - * @param propertyName - * @param oldValue - * @param newValue - */ protected void userDataChanged(String propertyName, Object oldValue, Object newValue) { fireEvent(new UserDataChangeRecord(propertyName, name, name)); } @@ -1309,6 +1187,9 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM * Creates a new OverlayAddressSpace with the given name and base AddressSpace * @param overlaySpaceName the name of the overlay space to create * @param templateSpace the base AddressSpace to overlay + * @param minOffset the min offset of the space + * @param maxOffset the max offset of the space + * @return the new space * @throws DuplicateNameException if an AddressSpace already exists with the given name. * @throws LockException if the program is shared and not checked out exclusively. * @throws MemoryConflictException if image base override is active @@ -1526,8 +1407,8 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM *
  • LanguageMinorVersion
  • * * @param openMode program open mode - * @return version exception if the current version is out of date and can be upgraded. - * @throws IOException + * @return version exception if the current version is out of date and can be upgraded + * @throws IOException if there is an exception at the database level * @throws VersionException if the data is newer than this version of Ghidra and can not be * upgraded or opened. */ @@ -1617,12 +1498,8 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM table.putRecord(record); } - /** - * Perform more complex upgrades which require all language version translation to - * be completed - * @param monitor - * @throws IOException - * @throws CancelledException + /* + * Perform more complex upgrades which require all language version translation to be completed */ private void postUpgrade(int oldVersion, TaskMonitor monitor) throws CancelledException, IOException { @@ -1646,16 +1523,13 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM public int getStoredVersion() throws IOException { Record record = table.getRecord(new StringField(PROGRAM_DB_VERSION)); - - // DB Version was added in 2.1 release (27-May-04) - // if record does not exist return 1; - if (record != null) { String s = record.getString(0); try { return Integer.parseInt(s); } catch (NumberFormatException e) { + // return 1 for invalid value } } return 1; @@ -1705,12 +1579,10 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM } - /** + /* * External function pointers had previously been wrapped in a function. This should know be * handled by creating an external function which corresponds to the pointers external location * reference. - * @param monitor - * @throws IOException */ private void checkFunctionWrappedPointers(TaskMonitor monitor) throws IOException, CancelledException { @@ -1795,11 +1667,11 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM } catch (VersionException e) { if (!e.isUpgradable()) { - // Attempt to instatiate the old function manager which may be used for upgrades + // Attempt to instantiate the old function manager which may be used for upgrades try { oldFunctionMgr = new OldFunctionManager(dbh, this, addrMap); if (openMode != UPGRADE) { - // Indicate that program is upgradeable + // Indicate that program is upgradable oldFunctionMgr = null; versionExc = (new VersionException(true)).combine(versionExc); } @@ -1810,6 +1682,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM } } catch (VersionException e1) { + // TODO why does this happen? should we log this? } } else { @@ -2058,12 +1931,14 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM } /** - * Moves all information stored in the given range to the new location. - * @param fromAddr the first address in the range to be moved. - * @param toAddr the address to move to. - * @param length the number of addresses to move. - * @param monitor the task monitor to use while deleting information in the given range. - * @throws RollbackException if the user cancelled the operation via the task monitor. + * Moves all information stored in the given range to the new location + * + * @param fromAddr the first address in the range to be moved + * @param toAddr the address to move to + * @param length the number of addresses to move + * @param monitor the task monitor to use while deleting information in the given range + * @throws AddressOverflowException if there is a problem moving address ranges + * @throws RollbackException if the user cancelled the operation via the task monitor */ public void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor) throws AddressOverflowException, RollbackException { @@ -2103,23 +1978,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM return globalNamespace; } -// private void updateCompilerSpec(Language currLanguage, CompilerSpecID currCompilerSpecID, TaskMonitor monitor) { -// try { -// compilerSpec = currLanguage.getCompilerSpecByID(currCompilerSpecID); -// if (compilerSpec == null) { -// throw new IllegalArgumentException("Language " -// + currLanguage.getLanguageDescription().getDescription() -// + " does not have a compiler spec " + currCompilerSpecID); -// } -// } -// catch (CompilerSpecNotFoundException e) { -// throw new IllegalArgumentException("Language " -// + currLanguage.getLanguageDescription().getDescription() -// + " does not have a compiler spec " + currCompilerSpecID); -// } -// this.compilerSpecID = currCompilerSpecID; -// } - @Override public void setLanguage(Language newLanguage, CompilerSpecID newCompilerSpecID, boolean forceRedisassembly, TaskMonitor monitor) @@ -2129,8 +1987,9 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM return; } LanguageTranslator languageTranslator = - LanguageTranslatorFactory.getLanguageTranslatorFactory().getLanguageTranslator(language, - newLanguage); + LanguageTranslatorFactory.getLanguageTranslatorFactory() + .getLanguageTranslator(language, + newLanguage); if (languageTranslator == null) { throw new IncompatibleLanguageException("Language translation not supported"); } @@ -2255,13 +2114,9 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM } } - /** - * Repair damaged context prior to language upgrade. - * It is assumed that the context has already been upgrade and that the original - * prototypes and instructions are still intact. - * @param translator optional language translator - * @param monitor - * @throws CancelledException + /* + * Repair damaged context prior to language upgrade. It is assumed that the context has + * already been upgrade and that the original prototypes and instructions are still intact. */ private void repairContext(int oldLanguageVersion, int oldLanguageMinorVersion, LanguageTranslator translator, TaskMonitor monitor) throws CancelledException { @@ -2271,15 +2126,12 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM } } - /** + /* * Repair damaged ARM/THUMB context prior to language upgrade. With the release of Ghidra 5.2 * (which corresponds to the ARM language version of 1.6) the stored context register * value is write-protected where instructions exist. * It is assumed that the context has already been upgrade and that the original * prototypes and instructions are still intact. - * @param translator optional language translator - * @param monitor - * @throws CancelledException */ private void repairARMContext(int oldLanguageVersion, int oldLanguageMinorVersion, LanguageTranslator translator, TaskMonitor monitor) throws CancelledException {