mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-27 23:17:03 +08:00
GP-508 fixing program actions enablement with regard to debugger program context not working
This commit is contained in:
+99
@@ -0,0 +1,99 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.progmgr;
|
||||||
|
|
||||||
|
import docking.ActionContext;
|
||||||
|
import docking.action.DockingAction;
|
||||||
|
import ghidra.app.context.ProgramActionContext;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class for program actions that change their menu name depending on the the active
|
||||||
|
* program. There are two types of actions that extend this class; those that only work
|
||||||
|
* on programs that are managed by Ghidra, and those that can work on any program even those
|
||||||
|
* whose life cycles are managed by individual plugins.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractProgramNameSwitchingAction extends DockingAction {
|
||||||
|
|
||||||
|
protected ProgramManagerPlugin plugin;
|
||||||
|
protected Program lastContextProgram;
|
||||||
|
private boolean requiresManagedProgram;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param plugin the ProgramManagerPlugin (i.e. the global Ghidra manager for programs)
|
||||||
|
* @param name the name of the action
|
||||||
|
* @param requiresManagedProgram true if the action is only used on globally managed
|
||||||
|
* programs
|
||||||
|
*/
|
||||||
|
public AbstractProgramNameSwitchingAction(ProgramManagerPlugin plugin, String name,
|
||||||
|
boolean requiresManagedProgram) {
|
||||||
|
super(name, plugin.getName());
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.requiresManagedProgram = requiresManagedProgram;
|
||||||
|
addToWindowWhen(ProgramActionContext.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidContext(ActionContext context) {
|
||||||
|
Program program = getProgram(context);
|
||||||
|
if (program != lastContextProgram) {
|
||||||
|
lastContextProgram = program;
|
||||||
|
programChanged(program);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isEnabledForContext(ActionContext context) {
|
||||||
|
return isEnabledForContext(getProgram(context));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isEnabledForContext(Program program) {
|
||||||
|
return program != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionContext context) {
|
||||||
|
Program program = getProgram(context);
|
||||||
|
if (program != null) {
|
||||||
|
actionPerformed(program);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void actionPerformed(Program program);
|
||||||
|
|
||||||
|
protected abstract void programChanged(Program program);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the program for the given context. If this actions requires the program
|
||||||
|
* to be globally managed, then it will only use the context program if it is
|
||||||
|
* managed; otherwise it will return the global current program.
|
||||||
|
* @param context the action context from which to get the program
|
||||||
|
* @return the appropriate program to use for this action.
|
||||||
|
*/
|
||||||
|
protected Program getProgram(ActionContext context) {
|
||||||
|
if (context instanceof ProgramActionContext) {
|
||||||
|
Program program = ((ProgramActionContext) context).getProgram();
|
||||||
|
if (plugin.isManaged(program) || !requiresManagedProgram) {
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
// otherwise, just return the global current program.
|
||||||
|
}
|
||||||
|
return plugin.getCurrentProgram();
|
||||||
|
}
|
||||||
|
}
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.progmgr;
|
||||||
|
|
||||||
|
import docking.action.KeyBindingData;
|
||||||
|
import docking.action.MenuData;
|
||||||
|
import docking.tool.ToolConstants;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.util.HTMLUtilities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action class for the "Close Program" action
|
||||||
|
*/
|
||||||
|
public class CloseProgramAction extends AbstractProgramNameSwitchingAction {
|
||||||
|
|
||||||
|
public CloseProgramAction(ProgramManagerPlugin plugin, String group, int subGroup) {
|
||||||
|
super(plugin, "Close File", true);
|
||||||
|
MenuData menuData = new MenuData(new String[] { ToolConstants.MENU_FILE, "&Close" });
|
||||||
|
menuData.setMenuGroup(group);
|
||||||
|
menuData.setMenuSubGroup(Integer.toString(subGroup));
|
||||||
|
setMenuBarData(menuData);
|
||||||
|
setKeyBindingData(new KeyBindingData("ctrl o"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void programChanged(Program program) {
|
||||||
|
if (program == null) {
|
||||||
|
getMenuBarData().setMenuItemName("&Close");
|
||||||
|
setDescription("Close Program");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String programName = "'" + program.getDomainFile().getName() + "'";
|
||||||
|
getMenuBarData().setMenuItemName("&Close " + programName);
|
||||||
|
setDescription("<html>Close " + HTMLUtilities.escapeHTML(programName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(Program program) {
|
||||||
|
plugin.closeProgram(program, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+29
-1
@@ -64,7 +64,7 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
|
|||||||
if (tool == null) {
|
if (tool == null) {
|
||||||
return; // we have been disposed
|
return; // we have been disposed
|
||||||
}
|
}
|
||||||
plugin.updateProgramActions();
|
plugin.undoStackChanged();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,4 +501,32 @@ class MultiProgramManager implements DomainObjectListener, TransactionListener {
|
|||||||
int openVersion = openFile.isReadOnly() ? openFile.getVersion() : -1;
|
int openVersion = openFile.isReadOnly() ? openFile.getVersion() : -1;
|
||||||
return version == openVersion;
|
return version == openVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this ProgramManager is managing the given program
|
||||||
|
* @param program the program to check
|
||||||
|
* @return true if this ProgramManager is managing the given programs
|
||||||
|
*/
|
||||||
|
public boolean hasProgram(Program program) {
|
||||||
|
return programMap.containsKey(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if there is at least one program that has unsaved changes.
|
||||||
|
* @return true if there is at least one program that has unsaved changes.
|
||||||
|
*/
|
||||||
|
public boolean hasUnsavedPrograms() {
|
||||||
|
// first check the current program as that is the one most likely to have changes
|
||||||
|
Program currentProgram = getCurrentProgram();
|
||||||
|
if (currentProgram != null && currentProgram.isChanged()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// look at all the open programs to see if any have changes
|
||||||
|
for (ProgramInfo programInfo : openProgramList) {
|
||||||
|
if (programInfo.program.isChanged()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+58
-168
@@ -81,17 +81,9 @@ import ghidra.util.task.TaskLauncher;
|
|||||||
public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
||||||
|
|
||||||
private static final String SAVE_GROUP = "DomainObjectSave";
|
private static final String SAVE_GROUP = "DomainObjectSave";
|
||||||
private static final String OPEN_GROUP = "DomainObjectOpen";
|
static final String OPEN_GROUP = "DomainObjectOpen";
|
||||||
private MultiProgramManager programMgr;
|
private MultiProgramManager programMgr;
|
||||||
private ProgramSaveManager programSaveMgr;
|
private ProgramSaveManager programSaveMgr;
|
||||||
private DockingAction openAction;
|
|
||||||
private DockingAction saveAllAction;
|
|
||||||
private DockingAction closeAction;
|
|
||||||
private DockingAction saveAction;
|
|
||||||
private DockingAction saveAsAction;
|
|
||||||
private DockingAction optionsAction;
|
|
||||||
private DockingAction closeOthersAction;
|
|
||||||
private DockingAction closeAllAction;
|
|
||||||
private int transactionID = -1;
|
private int transactionID = -1;
|
||||||
private OpenVersionedFileDialog openDialog;
|
private OpenVersionedFileDialog openDialog;
|
||||||
private boolean locked = false;
|
private boolean locked = false;
|
||||||
@@ -174,11 +166,11 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
Program openProgram = programMgr.getOpenProgram(ghidraURL);
|
Program openProgram = programMgr.getOpenProgram(ghidraURL);
|
||||||
if (openProgram != null) {
|
if (openProgram != null) {
|
||||||
programMgr.addProgram(openProgram, GhidraURL.getNormalizedURL(ghidraURL), openState);
|
programMgr.addProgram(openProgram, GhidraURL.getNormalizedURL(ghidraURL), openState);
|
||||||
updateActions();
|
|
||||||
if (openState == ProgramManager.OPEN_CURRENT) {
|
if (openState == ProgramManager.OPEN_CURRENT) {
|
||||||
gotoProgramRef(openProgram, ghidraURL.getRef());
|
gotoProgramRef(openProgram, ghidraURL.getRef());
|
||||||
programMgr.saveLocation();
|
programMgr.saveLocation();
|
||||||
}
|
}
|
||||||
|
contextChanged();
|
||||||
return openProgram;
|
return openProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +207,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
programMgr.addProgram(openProgram, GhidraURL.getNormalizedURL(ghidraURL), openState);
|
programMgr.addProgram(openProgram, GhidraURL.getNormalizedURL(ghidraURL), openState);
|
||||||
updateActions();
|
contextChanged();
|
||||||
openProgram.release(this);
|
openProgram.release(this);
|
||||||
if (openState == ProgramManager.OPEN_CURRENT) {
|
if (openState == ProgramManager.OPEN_CURRENT) {
|
||||||
gotoProgramRef(openProgram, ghidraURL.getRef());
|
gotoProgramRef(openProgram, ghidraURL.getRef());
|
||||||
@@ -310,7 +302,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
|
|
||||||
Program program = Swing.runNow(() -> {
|
Program program = Swing.runNow(() -> {
|
||||||
Program p = doOpenProgram(domainFile, version, state);
|
Program p = doOpenProgram(domainFile, version, state);
|
||||||
updateActions();
|
contextChanged();
|
||||||
return p;
|
return p;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -347,16 +339,16 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean closeOtherPrograms(final boolean ignoreChanges) {
|
public boolean closeOtherPrograms(boolean ignoreChanges) {
|
||||||
final Program[] otherPrograms = programMgr.getOtherPrograms();
|
Program[] otherPrograms = programMgr.getOtherPrograms();
|
||||||
Runnable r = () -> doCloseAllPrograms(otherPrograms, ignoreChanges);
|
Runnable r = () -> doCloseAllPrograms(otherPrograms, ignoreChanges);
|
||||||
SystemUtilities.runSwingNow(r);
|
SystemUtilities.runSwingNow(r);
|
||||||
return programMgr.isEmpty();
|
return programMgr.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean closeAllPrograms(final boolean ignoreChanges) {
|
public boolean closeAllPrograms(boolean ignoreChanges) {
|
||||||
final Program[] openPrograms = programMgr.getAllPrograms();
|
Program[] openPrograms = programMgr.getAllPrograms();
|
||||||
Runnable r = () -> doCloseAllPrograms(openPrograms, ignoreChanges);
|
Runnable r = () -> doCloseAllPrograms(openPrograms, ignoreChanges);
|
||||||
SystemUtilities.runSwingNow(r);
|
SystemUtilities.runSwingNow(r);
|
||||||
return programMgr.isEmpty();
|
return programMgr.isEmpty();
|
||||||
@@ -396,11 +388,11 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
for (Program program : toRemove) {
|
for (Program program : toRemove) {
|
||||||
programMgr.removeProgram(program);
|
programMgr.removeProgram(program);
|
||||||
}
|
}
|
||||||
updateActions();
|
contextChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean closeProgram(final Program program, final boolean ignoreChanges) {
|
public boolean closeProgram(Program program, boolean ignoreChanges) {
|
||||||
if (program == null) {
|
if (program == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -411,7 +403,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
if (ignoreChanges || program.isClosed() || programMgr.isPersistent(program) ||
|
if (ignoreChanges || program.isClosed() || programMgr.isPersistent(program) ||
|
||||||
(tool.canCloseDomainObject(program) && programSaveMgr.canClose(program))) {
|
(tool.canCloseDomainObject(program) && programSaveMgr.canClose(program))) {
|
||||||
programMgr.removeProgram(program);
|
programMgr.removeProgram(program);
|
||||||
updateActions();
|
contextChanged();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
SystemUtilities.runSwingNow(r);
|
SystemUtilities.runSwingNow(r);
|
||||||
@@ -434,16 +426,16 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
if (currentProgram != null) {
|
if (currentProgram != null) {
|
||||||
programMgr.removeProgram(currentProgram);
|
programMgr.removeProgram(currentProgram);
|
||||||
}
|
}
|
||||||
updateActions();
|
contextChanged();
|
||||||
tool.setSubTitle("");
|
tool.setSubTitle("");
|
||||||
tool.clearLastEvents();
|
tool.clearLastEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCurrentProgram(final Program p) {
|
public void setCurrentProgram(Program p) {
|
||||||
Runnable r = () -> {
|
Runnable r = () -> {
|
||||||
programMgr.setCurrentProgram(p);
|
programMgr.setCurrentProgram(p);
|
||||||
updateActions();
|
contextChanged();
|
||||||
};
|
};
|
||||||
SystemUtilities.runSwingNow(r);
|
SystemUtilities.runSwingNow(r);
|
||||||
}
|
}
|
||||||
@@ -483,7 +475,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
if (state == ProgramManager.OPEN_CURRENT) {
|
if (state == ProgramManager.OPEN_CURRENT) {
|
||||||
programMgr.saveLocation();
|
programMgr.saveLocation();
|
||||||
}
|
}
|
||||||
updateActions();
|
contextChanged();
|
||||||
};
|
};
|
||||||
SystemUtilities.runSwingNow(r);
|
SystemUtilities.runSwingNow(r);
|
||||||
}
|
}
|
||||||
@@ -496,7 +488,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
@Override
|
@Override
|
||||||
protected boolean saveData() {
|
protected boolean saveData() {
|
||||||
boolean result = programSaveMgr.canCloseAll();
|
boolean result = programSaveMgr.canCloseAll();
|
||||||
updateActions();
|
contextChanged();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -513,100 +505,57 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
|
|
||||||
private void createActions() {
|
private void createActions() {
|
||||||
|
|
||||||
int subMenuGroupOrder = 1;
|
int subMenuGroup = 1;
|
||||||
|
|
||||||
openAction = new ActionBuilder("Open File", getName())
|
DockingAction openAction = new ActionBuilder("Open File", getName())
|
||||||
.menuPath(ToolConstants.MENU_FILE, "&Open...")
|
.menuPath(ToolConstants.MENU_FILE, "&Open...")
|
||||||
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroupOrder++))
|
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroup++))
|
||||||
.keyBinding("ctrl O")
|
.keyBinding("ctrl O")
|
||||||
|
.enabledWhen(c -> !locked)
|
||||||
.onAction(c -> open())
|
.onAction(c -> open())
|
||||||
.buildAndInstall(tool);
|
.buildAndInstall(tool);
|
||||||
|
|
||||||
// .withContext(ProgramActionContext.class)
|
|
||||||
// .inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
|
||||||
// openAction doesn't really use a context, but we want it to be in windows that
|
|
||||||
// have providers that use programs.
|
|
||||||
openAction.addToWindowWhen(ProgramActionContext.class);
|
openAction.addToWindowWhen(ProgramActionContext.class);
|
||||||
|
|
||||||
closeAction = new ActionBuilder("Close File", getName())
|
tool.addAction(new CloseProgramAction(this, OPEN_GROUP, subMenuGroup++));
|
||||||
.menuPath(ToolConstants.MENU_FILE, "&Close")
|
new ActionBuilder("Close Others", getName())
|
||||||
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroupOrder++))
|
|
||||||
.withContext(ProgramActionContext.class)
|
|
||||||
.supportsDefaultToolContext(true)
|
|
||||||
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
|
||||||
.onAction(c -> closeProgram(c.getProgram(), false))
|
|
||||||
.keyBinding("ctrl W")
|
|
||||||
.buildAndInstall(tool);
|
|
||||||
|
|
||||||
closeOthersAction = new ActionBuilder("Close Others", getName())
|
|
||||||
.menuPath(ToolConstants.MENU_FILE, "Close &Others")
|
.menuPath(ToolConstants.MENU_FILE, "Close &Others")
|
||||||
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroupOrder++))
|
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroup++))
|
||||||
.enabled(false)
|
.enabled(false)
|
||||||
.withContext(ProgramActionContext.class)
|
.withContext(ProgramActionContext.class)
|
||||||
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
||||||
|
.enabledWhen(c -> programMgr.hasProgram(c.getProgram()))
|
||||||
.onAction(c -> closeOtherPrograms(false))
|
.onAction(c -> closeOtherPrograms(false))
|
||||||
.buildAndInstall(tool);
|
.buildAndInstall(tool);
|
||||||
|
|
||||||
closeAllAction = new ActionBuilder("Close All", getName())
|
DockingAction closeAllAction = new ActionBuilder("Close All", getName())
|
||||||
.menuPath(ToolConstants.MENU_FILE, "Close &All")
|
.menuPath(ToolConstants.MENU_FILE, "Close &All")
|
||||||
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroupOrder++))
|
.menuGroup(OPEN_GROUP, Integer.toString(subMenuGroup++))
|
||||||
.withContext(ProgramActionContext.class)
|
.enabledWhen(c -> !programMgr.isEmpty())
|
||||||
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
|
||||||
.onAction(c -> closeAllPrograms(false))
|
.onAction(c -> closeAllPrograms(false))
|
||||||
.enabled(false)
|
|
||||||
.buildAndInstall(tool);
|
.buildAndInstall(tool);
|
||||||
|
closeAllAction.addToWindowWhen(ProgramActionContext.class);
|
||||||
|
|
||||||
saveAction = new ActionBuilder("Save File", getName())
|
tool.addAction(new SaveProgramAction(this, SAVE_GROUP, subMenuGroup));
|
||||||
.menuPath(ToolConstants.MENU_FILE, "Save File")
|
tool.addAction(new SaveAsProgramAction(this, SAVE_GROUP, subMenuGroup));
|
||||||
.description("Save Program")
|
|
||||||
.menuGroup(SAVE_GROUP, Integer.toString(subMenuGroupOrder++))
|
|
||||||
.menuIcon(null)
|
|
||||||
.toolBarIcon("images/disk.png")
|
|
||||||
.toolBarGroup(ToolConstants.TOOLBAR_GROUP_ONE)
|
|
||||||
.keyBinding("ctrl S")
|
|
||||||
.withContext(ProgramActionContext.class)
|
|
||||||
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
|
||||||
.supportsDefaultToolContext(true)
|
|
||||||
.enabledWhen(c -> c.getProgram() != null && c.getProgram().isChanged())
|
|
||||||
.onAction(c -> programSaveMgr.saveProgram(c.getProgram()))
|
|
||||||
.buildAndInstall(tool);
|
|
||||||
|
|
||||||
saveAsAction = new ActionBuilder("Save As File", getName())
|
DockingAction saveAllAction = new ActionBuilder("Save All Files", getName())
|
||||||
.menuPath(ToolConstants.MENU_FILE, "Save &As...")
|
|
||||||
.menuGroup(SAVE_GROUP, Integer.toString(subMenuGroupOrder++))
|
|
||||||
.withContext(ProgramActionContext.class)
|
|
||||||
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
|
||||||
.supportsDefaultToolContext(true)
|
|
||||||
.onAction(c -> programSaveMgr.saveAs(c.getProgram()))
|
|
||||||
.buildAndInstall(tool);
|
|
||||||
|
|
||||||
saveAllAction = new ActionBuilder("Save All Files", getName())
|
|
||||||
.menuPath(ToolConstants.MENU_FILE, "Save All")
|
.menuPath(ToolConstants.MENU_FILE, "Save All")
|
||||||
.description("Save All Programs")
|
.description("Save All Programs")
|
||||||
.menuGroup(SAVE_GROUP, Integer.toString(subMenuGroupOrder++))
|
.menuGroup(SAVE_GROUP, Integer.toString(subMenuGroup++))
|
||||||
.withContext(ProgramActionContext.class)
|
.enabledWhen(c -> programMgr.hasUnsavedPrograms())
|
||||||
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
|
||||||
.onAction(c -> programSaveMgr.saveChangedPrograms())
|
.onAction(c -> programSaveMgr.saveChangedPrograms())
|
||||||
.buildAndInstall(tool);
|
.buildAndInstall(tool);
|
||||||
|
saveAllAction.addToWindowWhen(ProgramActionContext.class);
|
||||||
|
|
||||||
optionsAction = new ActionBuilder("Program Options", getName())
|
tool.addAction(new ProgramOptionsAction(this));
|
||||||
.menuPath(ToolConstants.MENU_EDIT, "P&rogram Options...")
|
|
||||||
.description("Edit Options for current program")
|
|
||||||
.menuGroup(ToolConstants.TOOL_OPTIONS_MENU_GROUP,
|
|
||||||
ToolConstants.TOOL_OPTIONS_MENU_GROUP + "b")
|
|
||||||
.withContext(ProgramActionContext.class)
|
|
||||||
.inWindow(ActionBuilder.When.CONTEXT_MATCHES)
|
|
||||||
.supportsDefaultToolContext(true)
|
|
||||||
.onAction(c -> showProgramOptions(c.getProgram()))
|
|
||||||
.buildAndInstall(tool);
|
|
||||||
|
|
||||||
undoAction = new UndoAction(tool, getName());
|
undoAction = new UndoAction(this, tool);
|
||||||
redoAction = new RedoAction(tool, getName());
|
redoAction = new RedoAction(this, tool);
|
||||||
tool.addAction(undoAction);
|
tool.addAction(undoAction);
|
||||||
tool.addAction(redoAction);
|
tool.addAction(redoAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showProgramOptions(final Program currentProgram) {
|
void showProgramOptions(final Program currentProgram) {
|
||||||
List<String> names = currentProgram.getOptionsNames();
|
List<String> names = currentProgram.getOptionsNames();
|
||||||
Options[] options = new Options[names.size()];
|
Options[] options = new Options[names.size()];
|
||||||
for (int i = 0; i < names.size(); i++) {
|
for (int i = 0; i < names.size(); i++) {
|
||||||
@@ -664,64 +613,14 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateActions() {
|
void undoStackChanged() {
|
||||||
Program p = programMgr.getCurrentProgram();
|
undoAction.updateActionMenuName();
|
||||||
updateCloseAction(p);
|
redoAction.updateActionMenuName();
|
||||||
updateProgramOptionsAction(p);
|
|
||||||
updateProgramActions();
|
|
||||||
closeAllAction.setEnabled(p != null);
|
|
||||||
optionsAction.setEnabled(p != null);
|
|
||||||
Program[] programList = programMgr.getAllPrograms();
|
|
||||||
closeOthersAction.setEnabled(programList.length > 1);
|
|
||||||
tool.contextChanged(null);
|
tool.contextChanged(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSaveAction(Program p) {
|
void contextChanged() {
|
||||||
if (p == null) {
|
tool.contextChanged(null);
|
||||||
saveAction.getMenuBarData().setMenuItemName("&Save");
|
|
||||||
saveAction.setDescription("Save Program");
|
|
||||||
saveAction.setEnabled(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
String programName = "'" + p.getDomainFile().getName() + "'";
|
|
||||||
saveAction.getMenuBarData().setMenuItemName("&Save " + programName);
|
|
||||||
saveAction.setDescription("Save " + programName);
|
|
||||||
saveAction.setEnabled(p.isChanged());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateSaveAsAction(Program p) {
|
|
||||||
if (p == null) {
|
|
||||||
saveAsAction.getMenuBarData().setMenuItemName("Save &As...");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
String programName = "'" + p.getDomainFile().getName() + "'";
|
|
||||||
saveAsAction.getMenuBarData().setMenuItemName("Save " + programName + " &As...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateProgramOptionsAction(Program p) {
|
|
||||||
if (p == null) {
|
|
||||||
optionsAction.getMenuBarData().setMenuItemName("Program Options");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
String programName = "'" + p.getDomainFile().getName() + "'";
|
|
||||||
optionsAction.getMenuBarData().setMenuItemName("Options for " + programName + "...");
|
|
||||||
}
|
|
||||||
optionsAction.setEnabled(p != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateCloseAction(Program p) {
|
|
||||||
if (p == null) {
|
|
||||||
closeAction.getMenuBarData().setMenuItemName("&Close");
|
|
||||||
closeAction.setDescription("Close Program");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
String programName = "'" + p.getDomainFile().getName() + "'";
|
|
||||||
closeAction.getMenuBarData().setMenuItemName("&Close " + programName);
|
|
||||||
closeAction.setDescription("<html>Close " + HTMLUtilities.escapeHTML(programName));
|
|
||||||
}
|
|
||||||
closeAction.setEnabled(p != null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void open() {
|
private void open() {
|
||||||
@@ -746,7 +645,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
openDialog.addOkActionListener(listener);
|
openDialog.addOkActionListener(listener);
|
||||||
}
|
}
|
||||||
tool.showDialog(openDialog);
|
tool.showDialog(openDialog);
|
||||||
updateActions();
|
contextChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void openPrograms(List<DomainFile> filesToOpen) {
|
public void openPrograms(List<DomainFile> filesToOpen) {
|
||||||
@@ -792,27 +691,6 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
return openProgram;
|
return openProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateProgramActions() {
|
|
||||||
updateSaveAllAction();
|
|
||||||
Program p = getCurrentProgram();
|
|
||||||
updateSaveAction(getCurrentProgram());
|
|
||||||
updateSaveAsAction(getCurrentProgram());
|
|
||||||
undoAction.update(p);
|
|
||||||
redoAction.update(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateSaveAllAction() {
|
|
||||||
boolean saveAllEnable = false;
|
|
||||||
Program[] programList = programMgr.getAllPrograms();
|
|
||||||
for (Program element : programList) {
|
|
||||||
if (element.isChanged()) {
|
|
||||||
saveAllEnable = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
saveAllAction.setEnabled(saveAllEnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write out my data state.
|
* Write out my data state.
|
||||||
*/
|
*/
|
||||||
@@ -870,7 +748,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
programMgr.setCurrentProgram(programs[0]);
|
programMgr.setCurrentProgram(programs[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateActions();
|
contextChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1162,7 +1040,19 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
|
|||||||
@Override
|
@Override
|
||||||
public void lockDown(boolean state) {
|
public void lockDown(boolean state) {
|
||||||
locked = state;
|
locked = state;
|
||||||
openAction.setEnabled(!state);
|
contextChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isManaged(Program program) {
|
||||||
|
return programMgr.contains(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveProgram(Program program) {
|
||||||
|
programSaveMgr.saveProgram(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveProgramAs(Program program) {
|
||||||
|
programSaveMgr.saveAs(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.progmgr;
|
||||||
|
|
||||||
|
import docking.action.MenuData;
|
||||||
|
import docking.tool.ToolConstants;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action class for the "Edit Program Options" action
|
||||||
|
*/
|
||||||
|
public class ProgramOptionsAction extends AbstractProgramNameSwitchingAction {
|
||||||
|
|
||||||
|
public ProgramOptionsAction(ProgramManagerPlugin plugin) {
|
||||||
|
super(plugin, "Program Options", true);
|
||||||
|
MenuData menuData =
|
||||||
|
new MenuData(new String[] { ToolConstants.MENU_EDIT, "P&rogram Options..." });
|
||||||
|
menuData.setMenuGroup(ToolConstants.TOOL_OPTIONS_MENU_GROUP);
|
||||||
|
menuData.setMenuSubGroup(ToolConstants.TOOL_OPTIONS_MENU_GROUP + "b");
|
||||||
|
setMenuBarData(menuData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void programChanged(Program program) {
|
||||||
|
if (program == null) {
|
||||||
|
getMenuBarData().setMenuItemName("Program Options");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String programName = "'" + program.getDomainFile().getName() + "'";
|
||||||
|
getMenuBarData().setMenuItemName("Options for " + programName + "...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(Program program) {
|
||||||
|
plugin.showProgramOptions(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -21,8 +21,6 @@ import javax.swing.Icon;
|
|||||||
|
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
import docking.tool.ToolConstants;
|
import docking.tool.ToolConstants;
|
||||||
import ghidra.app.context.ProgramActionContext;
|
|
||||||
import ghidra.app.context.ProgramContextAction;
|
|
||||||
import ghidra.app.services.GoToService;
|
import ghidra.app.services.GoToService;
|
||||||
import ghidra.app.services.NavigationHistoryService;
|
import ghidra.app.services.NavigationHistoryService;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
@@ -30,11 +28,14 @@ import ghidra.program.model.listing.Program;
|
|||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
|
|
||||||
public class RedoAction extends ProgramContextAction {
|
/**
|
||||||
|
* Action class for the "redo" action
|
||||||
|
*/
|
||||||
|
public class RedoAction extends AbstractProgramNameSwitchingAction {
|
||||||
private final PluginTool tool;
|
private final PluginTool tool;
|
||||||
|
|
||||||
public RedoAction(PluginTool tool, String owner) {
|
public RedoAction(ProgramManagerPlugin plugin, PluginTool tool) {
|
||||||
super("Redo", owner);
|
super(plugin, "Redo", true);
|
||||||
this.tool = tool;
|
this.tool = tool;
|
||||||
setHelpLocation(new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Redo"));
|
setHelpLocation(new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Redo"));
|
||||||
String[] menuPath = { ToolConstants.MENU_EDIT, "&Redo" };
|
String[] menuPath = { ToolConstants.MENU_EDIT, "&Redo" };
|
||||||
@@ -46,15 +47,10 @@ public class RedoAction extends ProgramContextAction {
|
|||||||
setToolBarData(new ToolBarData(icon, group));
|
setToolBarData(new ToolBarData(icon, group));
|
||||||
setKeyBindingData(new KeyBindingData("ctrl shift Z"));
|
setKeyBindingData(new KeyBindingData("ctrl shift Z"));
|
||||||
setDescription("Redo");
|
setDescription("Redo");
|
||||||
setSupportsDefaultToolContext(true);
|
|
||||||
|
|
||||||
// we want this action to appear in all windows that can produce a program context
|
|
||||||
addToWindowWhen(ProgramActionContext.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void actionPerformed(ProgramActionContext programContext) {
|
protected void actionPerformed(Program program) {
|
||||||
Program program = programContext.getProgram();
|
|
||||||
try {
|
try {
|
||||||
saveCurrentLocationToHistory();
|
saveCurrentLocationToHistory();
|
||||||
program.redo();
|
program.redo();
|
||||||
@@ -64,41 +60,30 @@ public class RedoAction extends ProgramContextAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void updateActionMenuName() {
|
||||||
* updates the menu name of the action as the undo stack changes
|
updateActionMenuName(lastContextProgram);
|
||||||
* <P>
|
}
|
||||||
* NOTE: currently, we must manage the enablement explicitly
|
|
||||||
* because contextChanged is not called for data changes. Ideally, the enablement
|
|
||||||
* would be handled by the context, but for now it doesn't work
|
|
||||||
*
|
|
||||||
* @param program the program
|
|
||||||
*/
|
|
||||||
public void update(Program program) {
|
|
||||||
|
|
||||||
if (program == null) {
|
void updateActionMenuName(Program program) {
|
||||||
getMenuBarData().setMenuItemName("Redo ");
|
String actionName = "Redo " + (program == null ? "" : program.getDomainFile().getName());
|
||||||
setDescription("");
|
String description = actionName;
|
||||||
setEnabled(false);
|
|
||||||
}
|
if (program != null && program.canRedo()) {
|
||||||
else if (program.canRedo()) {
|
description = HTMLUtilities
|
||||||
String programName = program.getDomainFile().getName();
|
.toWrappedHTML("Redo " + HTMLUtilities.escapeHTML(program.getRedoName()));
|
||||||
getMenuBarData().setMenuItemName("Redo " + programName);
|
|
||||||
String tip = HTMLUtilities.toWrappedHTML(
|
|
||||||
"Redo " + HTMLUtilities.escapeHTML(program.getRedoName()));
|
|
||||||
setDescription(tip);
|
|
||||||
setEnabled(true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setDescription("Redo");
|
|
||||||
setEnabled(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMenuBarData().setMenuItemName(actionName);
|
||||||
|
setDescription(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void programChanged(Program program) {
|
||||||
|
updateActionMenuName(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isEnabledForContext(ProgramActionContext context) {
|
protected boolean isEnabledForContext(Program program) {
|
||||||
Program program = context.getProgram();
|
return program != null && program.canRedo();
|
||||||
return program.canRedo();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveCurrentLocationToHistory() {
|
private void saveCurrentLocationToHistory() {
|
||||||
@@ -108,5 +93,4 @@ public class RedoAction extends ProgramContextAction {
|
|||||||
historyService.addNewLocation(goToService.getDefaultNavigatable());
|
historyService.addNewLocation(goToService.getDefaultNavigatable());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.progmgr;
|
||||||
|
|
||||||
|
import docking.action.MenuData;
|
||||||
|
import docking.tool.ToolConstants;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action class for the "Save As" action
|
||||||
|
*/
|
||||||
|
public class SaveAsProgramAction extends AbstractProgramNameSwitchingAction {
|
||||||
|
|
||||||
|
public SaveAsProgramAction(ProgramManagerPlugin plugin, String group, int subGroup) {
|
||||||
|
super(plugin, "Save As File", true);
|
||||||
|
MenuData menuData = new MenuData(new String[] { ToolConstants.MENU_FILE, "Save &As..." });
|
||||||
|
menuData.setMenuGroup(group);
|
||||||
|
menuData.setMenuSubGroup(Integer.toString(subGroup));
|
||||||
|
setMenuBarData(menuData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void programChanged(Program program) {
|
||||||
|
if (program == null) {
|
||||||
|
getMenuBarData().setMenuItemName("Save &As...");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String programName = "'" + program.getDomainFile().getName() + "'";
|
||||||
|
getMenuBarData().setMenuItemName("Save " + programName + " &As...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(Program program) {
|
||||||
|
plugin.saveProgramAs(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+64
@@ -0,0 +1,64 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.progmgr;
|
||||||
|
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
|
|
||||||
|
import docking.action.*;
|
||||||
|
import docking.tool.ToolConstants;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import resources.ResourceManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action class for the "Save Program" action
|
||||||
|
*/
|
||||||
|
public class SaveProgramAction extends AbstractProgramNameSwitchingAction {
|
||||||
|
|
||||||
|
public SaveProgramAction(ProgramManagerPlugin plugin, String group, int subGroup) {
|
||||||
|
super(plugin, "Save File", true);
|
||||||
|
MenuData menuData = new MenuData(new String[] { ToolConstants.MENU_FILE, "Save File" });
|
||||||
|
menuData.setMenuGroup(group);
|
||||||
|
menuData.setMenuSubGroup(Integer.toString(subGroup));
|
||||||
|
setMenuBarData(menuData);
|
||||||
|
ImageIcon icon = ResourceManager.loadImage("images/disk.png");
|
||||||
|
setToolBarData(new ToolBarData(icon, ToolConstants.TOOLBAR_GROUP_ONE));
|
||||||
|
setKeyBindingData(new KeyBindingData("ctrl S"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void programChanged(Program program) {
|
||||||
|
if (program == null) {
|
||||||
|
getMenuBarData().setMenuItemName("&Save");
|
||||||
|
setDescription("Save Program");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String programName = "'" + program.getDomainFile().getName() + "'";
|
||||||
|
getMenuBarData().setMenuItemName("&Save " + programName);
|
||||||
|
setDescription("Save " + programName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabledForContext(Program program) {
|
||||||
|
return program != null && program.isChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(Program program) {
|
||||||
|
plugin.saveProgram(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -21,8 +21,6 @@ import javax.swing.Icon;
|
|||||||
|
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
import docking.tool.ToolConstants;
|
import docking.tool.ToolConstants;
|
||||||
import ghidra.app.context.ProgramActionContext;
|
|
||||||
import ghidra.app.context.ProgramContextAction;
|
|
||||||
import ghidra.app.services.GoToService;
|
import ghidra.app.services.GoToService;
|
||||||
import ghidra.app.services.NavigationHistoryService;
|
import ghidra.app.services.NavigationHistoryService;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
@@ -30,11 +28,14 @@ import ghidra.program.model.listing.Program;
|
|||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
|
|
||||||
public class UndoAction extends ProgramContextAction {
|
/**
|
||||||
|
* Action class for the "Undo" action
|
||||||
|
*/
|
||||||
|
public class UndoAction extends AbstractProgramNameSwitchingAction {
|
||||||
private final PluginTool tool;
|
private final PluginTool tool;
|
||||||
|
|
||||||
public UndoAction(PluginTool tool, String owner) {
|
public UndoAction(ProgramManagerPlugin plugin, PluginTool tool) {
|
||||||
super("Undo", owner);
|
super(plugin, "Undo", true);
|
||||||
this.tool = tool;
|
this.tool = tool;
|
||||||
setHelpLocation(new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Undo"));
|
setHelpLocation(new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Undo"));
|
||||||
String[] menuPath = { ToolConstants.MENU_EDIT, "&Undo" };
|
String[] menuPath = { ToolConstants.MENU_EDIT, "&Undo" };
|
||||||
@@ -45,15 +46,10 @@ public class UndoAction extends ProgramContextAction {
|
|||||||
setToolBarData(new ToolBarData(icon, "Undo"));
|
setToolBarData(new ToolBarData(icon, "Undo"));
|
||||||
setDescription("Undo");
|
setDescription("Undo");
|
||||||
setKeyBindingData(new KeyBindingData("ctrl Z"));
|
setKeyBindingData(new KeyBindingData("ctrl Z"));
|
||||||
setSupportsDefaultToolContext(true);
|
|
||||||
|
|
||||||
// we want this action to appear in all windows that can produce a program context
|
|
||||||
addToWindowWhen(ProgramActionContext.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void actionPerformed(ProgramActionContext programContext) {
|
protected void actionPerformed(Program program) {
|
||||||
Program program = programContext.getProgram();
|
|
||||||
try {
|
try {
|
||||||
saveCurrentLocationToHistory();
|
saveCurrentLocationToHistory();
|
||||||
program.undo();
|
program.undo();
|
||||||
@@ -71,39 +67,30 @@ public class UndoAction extends ProgramContextAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* updates the menu name of the action as the undo stack changes
|
protected void programChanged(Program program) {
|
||||||
* <P>
|
updateActionMenuName(program);
|
||||||
* NOTE: currently, we must manage the enablement explicitly
|
}
|
||||||
* because contextChanged is not called for data changes. Ideally, the enablement
|
|
||||||
* would be handled by the context, but for now it doesn't work
|
void updateActionMenuName() {
|
||||||
*
|
updateActionMenuName(lastContextProgram);
|
||||||
* @param program the program
|
}
|
||||||
*/
|
|
||||||
public void update(Program program) {
|
void updateActionMenuName(Program program) {
|
||||||
|
String actionName = "Undo " + (program == null ? "" : program.getDomainFile().getName());
|
||||||
|
String description = actionName;
|
||||||
|
|
||||||
if (program == null) {
|
|
||||||
getMenuBarData().setMenuItemName("Undo ");
|
|
||||||
setDescription("");
|
|
||||||
setEnabled(false);
|
|
||||||
}
|
|
||||||
if (program != null && program.canUndo()) {
|
if (program != null && program.canUndo()) {
|
||||||
String programName = program.getDomainFile().getName();
|
description = HTMLUtilities
|
||||||
getMenuBarData().setMenuItemName("Undo " + programName);
|
.toWrappedHTML("Undo " + HTMLUtilities.escapeHTML(program.getUndoName()));
|
||||||
String tip = HTMLUtilities.toWrappedHTML(
|
|
||||||
"Undo " + HTMLUtilities.escapeHTML(program.getUndoName()));
|
|
||||||
setDescription(tip);
|
|
||||||
setEnabled(true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setDescription("Undo");
|
|
||||||
setEnabled(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMenuBarData().setMenuItemName(actionName);
|
||||||
|
setDescription(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isEnabledForContext(ProgramActionContext context) {
|
protected boolean isEnabledForContext(Program program) {
|
||||||
Program program = context.getProgram();
|
return program != null && program.canUndo();
|
||||||
return program.canUndo();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user