mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-22 04:05:39 +00:00
Merge remote-tracking branch 'origin/GP-4691-dragonmacher-program-tree-mousing--SQUASHED'
This commit is contained in:
commit
d007200b11
@ -389,32 +389,46 @@
|
||||
View</FONT></B> option.</LI>
|
||||
</UL>
|
||||
|
||||
<H3><A name="Replace_View"></A>Replace the View in the Code Browser with other
|
||||
Folders/Fragments</H3>
|
||||
<H3><A name="Set_View"></A>Set the View in the Code Browser with Folders/Fragments</H3>
|
||||
|
||||
<UL>
|
||||
<LI>
|
||||
To replace the view in the code browser with other folders and fragments,
|
||||
To set the view in the code browser with folders and fragments,
|
||||
|
||||
<OL>
|
||||
<LI>Select a folder or fragment (or select multiple folders and fragments), </LI>
|
||||
|
||||
<LI>Right mouse-click and choose the <B>Replace View</B> option. The code browser now
|
||||
<LI>Right mouse-click and choose the <B>Set View</B> option. The code browser now
|
||||
shows the code units for these folders and fragments.</LI>
|
||||
</OL>
|
||||
</LI>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><IMG src="help/shared/note.png"> The program tree can be configured, via tool
|
||||
options, such that a double-click performs a simple navigation, or the
|
||||
<B>Replace View</B> action. The default
|
||||
behavior for a double-click is to perform the <B>Replace View</B> action.</P>
|
||||
options, such that a double-click performs the <B>Set View</B> action. The default
|
||||
behavior for a double-click is to navigate to the first address of the clicked
|
||||
fragment.</P>
|
||||
|
||||
<P>(Double-clicking on a folder always causes it to expand if it is collapsed and to
|
||||
collapse if it is expanded.)</P>
|
||||
</BLOCKQUOTE>
|
||||
</UL>
|
||||
|
||||
<H3><A name="Add_to_View"></A>Add to the View in the Code Browser</H3>
|
||||
|
||||
<UL>
|
||||
<LI>
|
||||
To add a folder or fragment to the view in the code browser,
|
||||
|
||||
<OL>
|
||||
<LI>Select a folder or fragment (or select multiple folders and fragments), </LI>
|
||||
|
||||
<LI>Right mouse-click and choose the <B>Add to View</B> option. The code browser now
|
||||
shows the code units for these folders and fragments.</LI>
|
||||
</OL>
|
||||
</LI>
|
||||
</UL>
|
||||
|
||||
<H3>Navigation</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -33,12 +33,8 @@ import docking.widgets.textfield.GValidatedTextField;
|
||||
import docking.widgets.textfield.GValidatedTextField.LongField.LongValidator;
|
||||
import docking.widgets.textfield.GValidatedTextField.ValidationFailedException;
|
||||
import docking.widgets.textfield.GValidatedTextField.ValidationMessageListener;
|
||||
import generic.theme.Gui;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.listing.DataTypeArchive;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.table.GhidraTable;
|
||||
|
||||
@ -670,7 +666,7 @@ class EnumEditorPanel extends JPanel {
|
||||
|
||||
private class EnumValueRenderer extends GTableCellRenderer {
|
||||
EnumValueRenderer() {
|
||||
setFont(Gui.getFont("font.monospaced"));
|
||||
setFont(getFixedWidthFont());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -61,7 +61,7 @@ public abstract class DragNDropTree extends JTree implements Draggable, Droppabl
|
||||
// data flavors that this tree can support
|
||||
protected DataFlavor[] acceptableFlavors;
|
||||
|
||||
protected TreeTransferable transferable;
|
||||
protected ProgramTreeTransferable transferable;
|
||||
protected Color nonSelectionDragColor;
|
||||
protected int relativeMousePos; // mouse position within the node
|
||||
|
||||
@ -128,7 +128,7 @@ public abstract class DragNDropTree extends JTree implements Draggable, Droppabl
|
||||
nodes[i] = (ProgramNode) selectionPaths[i].getLastPathComponent();
|
||||
}
|
||||
|
||||
transferable = new TreeTransferable(nodes);
|
||||
transferable = new ProgramTreeTransferable(nodes);
|
||||
draggedNodes = nodes;
|
||||
return transferable;
|
||||
}
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -17,10 +17,9 @@ package ghidra.app.plugin.core.programtree;
|
||||
|
||||
import java.awt.datatransfer.*;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import docking.dnd.GClipboard;
|
||||
@ -29,90 +28,66 @@ import ghidra.util.Msg;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
||||
/**
|
||||
* Manage paste operations for the tree.
|
||||
* Manage paste operations for the Program Tree.
|
||||
*/
|
||||
class PasteManager {
|
||||
|
||||
private ProgramTreeActionManager actionMgr;
|
||||
private ProgramDnDTree tree;
|
||||
private DefaultTreeModel treeModel;
|
||||
private Clipboard cutClipboard;
|
||||
private ProgramTreeActionManager actionManager;
|
||||
private String lastGroupPasted;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
PasteManager(ProgramTreeActionManager actionMgr) {
|
||||
this.actionMgr = actionMgr;
|
||||
cutClipboard = actionMgr.getCutClipboard();
|
||||
PasteManager(ProgramTreeActionManager actionManager) {
|
||||
this.actionManager = actionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the pasteNode can be pasted at the destNode.
|
||||
* @param destNode destination node for where the pasteNode will be pasted
|
||||
* @param pasteNode node to paste
|
||||
* @param isCutOperation true if the operation was "cut" versus "copy"
|
||||
*/
|
||||
boolean isPasteAllowed(ProgramNode destNode, ProgramNode pasteNode, boolean isCutOperation) {
|
||||
if (destNode.getProgram() != pasteNode.getProgram() ||
|
||||
destNode.getRoot() != pasteNode.getRoot()) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if (destNode.getName().equals(pasteNode.getName())) {
|
||||
return false;
|
||||
}
|
||||
if (destNode.isNodeAncestor(pasteNode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (destNode.isFragment() && pasteNode.isModule()) {
|
||||
if (isCutOperation && !pasteNode.getModule().isDescendant(destNode.getFragment())) {
|
||||
if (destNode.getName().equals(pasteNode.getName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true; // pasted module can be flattened onto
|
||||
// destination fragment
|
||||
if (destNode.isNodeAncestor(pasteNode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (destNode.isFragment() && pasteNode.isModule()) {
|
||||
if (isCutOperation && !pasteNode.getModule().isDescendant(destNode.getFragment())) {
|
||||
return true; // pasted module can be flattened onto destination fragment
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (destNode.isFragment() && pasteNode.isFragment()) {
|
||||
if (isCutOperation) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (destNode.isModule()) {
|
||||
ProgramModule destModule = destNode.getModule();
|
||||
|
||||
if (pasteNode.isModule()) {
|
||||
if (pasteNode.getModule().isDescendant(destModule)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (destNode.isFragment() && pasteNode.isFragment()) {
|
||||
if (isCutOperation) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (destNode.isModule()) {
|
||||
ProgramModule destModule = destNode.getModule();
|
||||
|
||||
if (pasteNode.isModule()) {
|
||||
if (pasteNode.getModule().isDescendant(destModule)) {
|
||||
return false;
|
||||
}
|
||||
if (!isCutOperation && destModule.contains(pasteNode.getModule())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!isCutOperation && destModule.contains(pasteNode.getFragment())) {
|
||||
if (!isCutOperation && destModule.contains(pasteNode.getModule())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!isCutOperation && destModule.contains(pasteNode.getFragment())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
// this is a hack for unknown reasons
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the paste operation.
|
||||
* @param destNode destination node for where the paste the contents of
|
||||
* system clipboard.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// cast is OK, it is data that we are expecting
|
||||
void paste(ProgramNode destNode) {
|
||||
@SuppressWarnings("unchecked") // cast is OK, it is data that we are expecting
|
||||
void paste(ProgramDnDTree tree, ProgramNode destNode) {
|
||||
|
||||
int transactionID = tree.startTransaction("Paste");
|
||||
if (transactionID < 0) {
|
||||
@ -125,34 +100,32 @@ class PasteManager {
|
||||
Clipboard systemClipboard = GClipboard.getSystemClipboard();
|
||||
Transferable t = systemClipboard.getContents(tree);
|
||||
try {
|
||||
if (t == null || !t.isDataFlavorSupported(TreeTransferable.localTreeNodeFlavor)) {
|
||||
if (t == null ||
|
||||
!t.isDataFlavorSupported(ProgramTreeTransferable.localTreeNodeFlavor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
tree.setBusyCursor(true);
|
||||
lastGroupPasted = null;
|
||||
ArrayList<ProgramNode> list =
|
||||
(ArrayList<ProgramNode>) t.getTransferData(TreeTransferable.localTreeNodeFlavor);
|
||||
|
||||
List<ProgramNode> list =
|
||||
(List<ProgramNode>) t.getTransferData(ProgramTreeTransferable.localTreeNodeFlavor);
|
||||
if (list == null) {
|
||||
// SCR 7990--something bad has happened to the copy buffer
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
ProgramNode tnode = list.get(i);
|
||||
|
||||
if (destNode.getRoot() != tnode.getRoot()) {
|
||||
for (ProgramNode node : list) {
|
||||
if (destNode.getRoot() != node.getRoot()) {
|
||||
lastGroupPasted = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!destNode.getName().equals(tnode.getName())) {
|
||||
if (pasteGroup(destNode, tnode)) {
|
||||
if (!(destNode.isFragment() && tnode.isModule())) {
|
||||
if (!destNode.getName().equals(node.getName())) {
|
||||
if (pasteGroup(tree, destNode, node)) {
|
||||
if (!(destNode.isFragment() && node.isModule())) {
|
||||
// this was not a "flatten module" operation
|
||||
// so we can leave the busy cursor set
|
||||
// until the domain object event comes in
|
||||
lastGroupPasted = tnode.getName();
|
||||
lastGroupPasted = node.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -163,18 +136,14 @@ class PasteManager {
|
||||
}
|
||||
|
||||
// do "cut" operations now if there are any
|
||||
actionMgr.checkClipboard(true);
|
||||
actionMgr.clearSystemClipboard();
|
||||
actionMgr.enablePasteAction(false);
|
||||
actionManager.cutClipboardNodes(tree);
|
||||
tree.removeSelectionPath(path);
|
||||
tree.addSelectionPath(path);
|
||||
|
||||
}
|
||||
catch (UnsupportedFlavorException e) {
|
||||
// data flavor is not supported
|
||||
Msg.showError(this, null, "Paste from Clipboard Failed",
|
||||
"Data flavor in clipboard is not supported.", e);
|
||||
|
||||
}
|
||||
catch (IOException e) {
|
||||
// data is no longer available
|
||||
@ -182,33 +151,19 @@ class PasteManager {
|
||||
"Data is no longer available for paste operation", e);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.showError(this, null, null, null, e);
|
||||
Msg.showError(this, null, "Unexpected Exception Pasting",
|
||||
"Unexpected exception pasting nodes", e);
|
||||
}
|
||||
finally {
|
||||
tree.endTransaction(transactionID, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the last group that was pasted.
|
||||
*/
|
||||
String getLastGroupPasted() {
|
||||
return lastGroupPasted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method setProgramTreeView.
|
||||
* @param tree
|
||||
*/
|
||||
void setProgramTreeView(ProgramDnDTree tree) {
|
||||
this.tree = tree;
|
||||
treeModel = (DefaultTreeModel) tree.getModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Paste the group at nodeToPaste at destNode.
|
||||
*/
|
||||
private boolean pasteGroup(ProgramNode destNode, ProgramNode nodeToPaste) {
|
||||
private boolean pasteGroup(ProgramDnDTree tree, ProgramNode destNode, ProgramNode nodeToPaste) {
|
||||
|
||||
if (destNode.isFragment()) {
|
||||
// can paste either a fragment or a module onto a fragment;
|
||||
@ -216,11 +171,12 @@ class PasteManager {
|
||||
// descendant fragments are moved to the destination fragment.
|
||||
try {
|
||||
tree.mergeGroup(nodeToPaste.getGroup(), destNode.getFragment());
|
||||
actionMgr.removeFromClipboard(cutClipboard, nodeToPaste);
|
||||
actionManager.removeFromClipboard(tree, nodeToPaste);
|
||||
return true;
|
||||
|
||||
}
|
||||
catch (ConcurrentModificationException e) {
|
||||
// ha!
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.showError(this, null, null, "Error Merging Fragments", e);
|
||||
@ -231,30 +187,24 @@ class PasteManager {
|
||||
ProgramModule targetModule = destNode.getModule();
|
||||
|
||||
if (targetModule == null) {
|
||||
nodeToPaste.setDeleted(false);
|
||||
treeModel.reload(nodeToPaste);
|
||||
actionManager.clearCut(nodeToPaste);
|
||||
Msg.showError(this, null, "Paste from Clipboard Failed",
|
||||
"Paste of " + nodeToPaste + " at\n" + destNode.getName() + " is not allowed.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return pasteNode(destNode, nodeToPaste);
|
||||
return pasteNode(tree, destNode, nodeToPaste);
|
||||
}
|
||||
|
||||
/**
|
||||
* Paste the node at the destination node.
|
||||
*/
|
||||
private boolean pasteNode(ProgramNode destNode, ProgramNode nodeToPaste) {
|
||||
private boolean pasteNode(ProgramDnDTree tree, ProgramNode destNode, ProgramNode nodeToPaste) {
|
||||
|
||||
ProgramModule targetModule = destNode.getModule();
|
||||
// make sure we have something to paste
|
||||
ProgramModule module = nodeToPaste.getModule();
|
||||
ProgramFragment fragment = nodeToPaste.getFragment();
|
||||
|
||||
if (module == null && fragment == null) {
|
||||
nodeToPaste.setDeleted(false);
|
||||
treeModel.reload(nodeToPaste);
|
||||
actionManager.clearCut(nodeToPaste);
|
||||
Msg.showError(this, null, "Paste from Clipboard Failed",
|
||||
"Could not paste " + nodeToPaste + " at " + targetModule.getName());
|
||||
return false;
|
||||
@ -263,10 +213,10 @@ class PasteManager {
|
||||
boolean pasteOK = false;
|
||||
try {
|
||||
if (module != null) {
|
||||
pasteOK = pasteModule(destNode, nodeToPaste, targetModule, module);
|
||||
pasteOK = pasteModule(tree, destNode, nodeToPaste, targetModule, module);
|
||||
}
|
||||
else {
|
||||
pasteOK = pasteFragment(nodeToPaste, targetModule, fragment);
|
||||
pasteOK = pasteFragment(tree, nodeToPaste, targetModule, fragment);
|
||||
}
|
||||
|
||||
// don't match the expansion state unless the destination
|
||||
@ -281,37 +231,35 @@ class PasteManager {
|
||||
|
||||
}
|
||||
catch (CircularDependencyException e) {
|
||||
removeFromClipboard(nodeToPaste);
|
||||
Msg.showError(this, null, "Paste from Clipboard Failed", e.getMessage());
|
||||
}
|
||||
catch (DuplicateGroupException e) {
|
||||
nodeToPaste.setDeleted(false);
|
||||
tree.reloadNode(nodeToPaste);
|
||||
|
||||
// handled below
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
removeFromClipboard(nodeToPaste);
|
||||
nodeToPaste.setDeleted(false);
|
||||
Msg.showError(this, null, "Paste from Clipboard Failed", e.getMessage());
|
||||
}
|
||||
|
||||
removeFromClipboard(tree, nodeToPaste);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paste the fragment at the given module.
|
||||
*/
|
||||
private boolean pasteFragment(ProgramNode nodeToPaste, ProgramModule targetModule,
|
||||
ProgramFragment fragment) throws NotFoundException, DuplicateGroupException {
|
||||
private boolean pasteFragment(ProgramDnDTree tree, ProgramNode nodeToPaste,
|
||||
ProgramModule targetModule, ProgramFragment fragment)
|
||||
throws NotFoundException, DuplicateGroupException {
|
||||
boolean pasteOK = false;
|
||||
|
||||
if (targetModule.contains(fragment)) {
|
||||
if (targetModule.equals(nodeToPaste.getParentModule())) {
|
||||
removeFromClipboard(nodeToPaste);
|
||||
removeFromClipboard(tree, nodeToPaste);
|
||||
}
|
||||
}
|
||||
else if (actionMgr.clipboardContains(nodeToPaste)) {
|
||||
else if (actionManager.clipboardContains(nodeToPaste)) {
|
||||
targetModule.reparent(nodeToPaste.getName(), nodeToPaste.getParentModule());
|
||||
removeFromClipboard(nodeToPaste);
|
||||
removeFromClipboard(tree, nodeToPaste);
|
||||
pasteOK = true;
|
||||
}
|
||||
else {
|
||||
@ -321,7 +269,7 @@ class PasteManager {
|
||||
return pasteOK;
|
||||
}
|
||||
|
||||
private boolean pasteModule(ProgramNode destNode, ProgramNode nodeToPaste,
|
||||
private boolean pasteModule(ProgramDnDTree tree, ProgramNode destNode, ProgramNode nodeToPaste,
|
||||
ProgramModule targetModule, ProgramModule module)
|
||||
throws NotFoundException, CircularDependencyException, DuplicateGroupException {
|
||||
|
||||
@ -332,12 +280,12 @@ class PasteManager {
|
||||
}
|
||||
if (targetModule.contains(module)) {
|
||||
if (targetModule.equals(nodeToPaste.getParentModule())) {
|
||||
removeFromClipboard(nodeToPaste);
|
||||
removeFromClipboard(tree, nodeToPaste);
|
||||
}
|
||||
}
|
||||
else if (actionMgr.clipboardContains(nodeToPaste)) {
|
||||
else if (actionManager.clipboardContains(nodeToPaste)) {
|
||||
targetModule.reparent(nodeToPaste.getName(), nodeToPaste.getParentModule());
|
||||
removeFromClipboard(nodeToPaste);
|
||||
removeFromClipboard(tree, nodeToPaste);
|
||||
pasteOK = true;
|
||||
}
|
||||
else {
|
||||
@ -352,15 +300,9 @@ class PasteManager {
|
||||
return pasteOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given node from the cut clipboard, so that "cut" changes
|
||||
* will not be applied.
|
||||
* @param node node to remove from the cut clipboard
|
||||
*/
|
||||
private void removeFromClipboard(ProgramNode node) {
|
||||
actionMgr.removeFromClipboard(cutClipboard, node);
|
||||
node.setDeleted(false);
|
||||
tree.reloadNode(node);
|
||||
private void removeFromClipboard(ProgramDnDTree tree, ProgramNode node) {
|
||||
actionManager.removeFromClipboard(tree, node);
|
||||
actionManager.clearCut(node);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -29,7 +29,6 @@ import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.tree.*;
|
||||
|
||||
import docking.DockingUtils;
|
||||
import docking.action.DockingAction;
|
||||
import docking.actions.KeyBindingUtils;
|
||||
import docking.dnd.DropTgtAdapter;
|
||||
import docking.widgets.JTreeMouseListenerDelegate;
|
||||
@ -55,8 +54,8 @@ public class ProgramDnDTree extends DragNDropTree {
|
||||
private Program program;
|
||||
private Listing listing;
|
||||
|
||||
private ArrayList<ProgramNode> nodeList; // list of nodes from preorder enumeration
|
||||
private ArrayList<TreePath> viewList; // list of tree paths that are being viewed.
|
||||
private List<ProgramNode> nodeList; // list of nodes from preorder enumeration
|
||||
private List<TreePath> viewList; // list of tree paths that are being viewed.
|
||||
|
||||
//keeps track of module/fragment names to come up with a default name, e.g., New Folder (2)
|
||||
private StringKeyIndexer nameIndexer;
|
||||
@ -272,7 +271,7 @@ public class ProgramDnDTree extends DragNDropTree {
|
||||
}
|
||||
|
||||
static DataFlavor[] getDataFlavors() {
|
||||
return new DataFlavor[] { TreeTransferable.localTreeNodeFlavor,
|
||||
return new DataFlavor[] { ProgramTreeTransferable.localTreeNodeFlavor,
|
||||
GroupTransferable.localGroupFlavor, // a test data flavor
|
||||
DataFlavor.stringFlavor, // a test data flavor
|
||||
SelectionTransferable.localProgramSelectionFlavor };
|
||||
@ -317,7 +316,7 @@ public class ProgramDnDTree extends DragNDropTree {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (chosen.equals(TreeTransferable.localTreeNodeFlavor)) {
|
||||
else if (chosen.equals(ProgramTreeTransferable.localTreeNodeFlavor)) {
|
||||
// fromObject is null, so we know this is
|
||||
// from another tree, so don't allow the drop
|
||||
return false;
|
||||
@ -385,6 +384,8 @@ public class ProgramDnDTree extends DragNDropTree {
|
||||
* that could potentially take a long time. The cursor is reset in the
|
||||
* domain object change listener when the event comes in for the group
|
||||
* that was last "pasted."
|
||||
*
|
||||
* @param busy true to use the busy cursor
|
||||
*/
|
||||
void setBusyCursor(boolean busy) {
|
||||
if (busy) {
|
||||
@ -406,19 +407,11 @@ public class ProgramDnDTree extends DragNDropTree {
|
||||
treeListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view list.
|
||||
*
|
||||
* @return ArrayList list of tree paths in the view
|
||||
*/
|
||||
ArrayList<TreePath> getViewList() {
|
||||
List<TreePath> getViewList() {
|
||||
return viewList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the node list.
|
||||
*/
|
||||
ArrayList<ProgramNode> getNodeList() {
|
||||
List<ProgramNode> getNodeList() {
|
||||
return nodeList;
|
||||
}
|
||||
|
||||
@ -435,10 +428,6 @@ public class ProgramDnDTree extends DragNDropTree {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds path to the view.
|
||||
* @param path
|
||||
*/
|
||||
void addToView(TreePath path) {
|
||||
if (path == null) {
|
||||
return;
|
||||
@ -666,36 +655,6 @@ public class ProgramDnDTree extends DragNDropTree {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given action should be added to popup, based
|
||||
* on what is currently selected. Called by the ProgramTreeAction.
|
||||
*/
|
||||
boolean addActionToPopup(DockingAction action) {
|
||||
|
||||
if (!(action instanceof ProgramTreeAction)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ProgramTreeAction a = (ProgramTreeAction) action;
|
||||
|
||||
int selectionCount = getSelectionCount();
|
||||
if (a.getSelectionType() == ProgramTreeAction.SINGLE_SELECTION) {
|
||||
|
||||
if (selectionCount == 1) {
|
||||
return true;
|
||||
}
|
||||
else if (selectionCount == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// allow 1 or many in selection
|
||||
if (selectionCount > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique name to be used as the default when
|
||||
* a Module or Fragment is created.
|
||||
@ -730,25 +689,6 @@ public class ProgramDnDTree extends DragNDropTree {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a list of selected ProgramNodes in postorder.
|
||||
*/
|
||||
// our data; we know it's good
|
||||
ArrayList<ProgramNode> getSortedSelection() {
|
||||
ArrayList<ProgramNode> list = new ArrayList<>();
|
||||
Enumeration<? extends TreeNode> it = root.postorderEnumeration();
|
||||
while (it.hasMoreElements()) {
|
||||
ProgramNode node = (ProgramNode) it.nextElement();
|
||||
if (isPathSelected(node.getTreePath())) {
|
||||
list.add(node);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand all descendants starting at node.
|
||||
*/
|
||||
void expandNode(ProgramNode node) {
|
||||
|
||||
expandPath(node.getTreePath());
|
||||
@ -837,7 +777,7 @@ public class ProgramDnDTree extends DragNDropTree {
|
||||
* @param sb string buffer to use if there was an error
|
||||
* @return true if group was removed
|
||||
*/
|
||||
boolean removeGroup(ProgramNode node, StringBuffer sb) {
|
||||
boolean removeGroup(ProgramNode node, StringBuilder sb) {
|
||||
|
||||
boolean changesMade = false;
|
||||
|
||||
@ -869,6 +809,7 @@ public class ProgramDnDTree extends DragNDropTree {
|
||||
* @param parent parent of the group to be inserted
|
||||
* @param group group to add
|
||||
* @param index index of new child
|
||||
* @return the new child node
|
||||
*/
|
||||
ProgramNode insertGroup(ProgramNode parent, Group group, int index) {
|
||||
|
||||
@ -1086,64 +1027,45 @@ public class ProgramDnDTree extends DragNDropTree {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable all actions.
|
||||
*/
|
||||
void disableActions() {
|
||||
actionManager.disableActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the selection based on the given popupPoint.
|
||||
* @param event mouse event
|
||||
* @return node that is selected
|
||||
*/
|
||||
ProgramNode prepareSelectionForPopup(MouseEvent event) {
|
||||
// adjust the selection based on the popup location
|
||||
ProgramNode adjustSelectionForPopup(MouseEvent event) {
|
||||
|
||||
synchronized (root) {
|
||||
|
||||
if (event != null && event.getSource() != this) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Point popupPoint = event != null ? event.getPoint() : null;
|
||||
int nselected = getSelectionCount();
|
||||
TreePath selPath = null;
|
||||
if (popupPoint != null) {
|
||||
selPath = getPathForLocation((int) popupPoint.getX(), (int) popupPoint.getY());
|
||||
}
|
||||
else {
|
||||
selPath = getSelectionPath();
|
||||
}
|
||||
ProgramNode node = null;
|
||||
if (selPath != null) {
|
||||
node = (ProgramNode) selPath.getLastPathComponent();
|
||||
return getMouseNode(popupPoint);
|
||||
}
|
||||
|
||||
if (nselected <= 1) {
|
||||
int nselected = getSelectionCount();
|
||||
if (nselected < 1) {
|
||||
return null; // nothing selected in the tree
|
||||
}
|
||||
|
||||
if (selPath != null && !isPathSelected(selPath)) {
|
||||
setSelectionPath(selPath);
|
||||
actionManager.adjustSingleActions(node);
|
||||
return node;
|
||||
}
|
||||
if (selPath != null) {
|
||||
actionManager.adjustSingleActions(node);
|
||||
return node;
|
||||
}
|
||||
actionManager.disableActions();
|
||||
return null;
|
||||
TreePath activePath = getSelectionPath();
|
||||
return (ProgramNode) activePath.getLastPathComponent();
|
||||
}
|
||||
}
|
||||
|
||||
private ProgramNode getMouseNode(Point popupPoint) {
|
||||
|
||||
TreePath mousePath = getPathForLocation((int) popupPoint.getX(), (int) popupPoint.getY());
|
||||
if (mousePath != null) {
|
||||
ProgramNode node = (ProgramNode) mousePath.getLastPathComponent();
|
||||
if (!isPathSelected(mousePath)) {
|
||||
setSelectionPath(mousePath); // add the right-clicked node to the selection
|
||||
}
|
||||
// if the path at the mouse pointer is in the selection OR
|
||||
// the path is null, then adjust the multi-popup menu.
|
||||
if ((selPath != null && isPathSelected(selPath)) || selPath == null) {
|
||||
actionManager.adjustMultiActions();
|
||||
return node;
|
||||
}
|
||||
// force the selection to be where the mouse pointer is
|
||||
setSelectionPath(selPath);
|
||||
actionManager.adjustSingleActions(node);
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1171,9 +1093,7 @@ public class ProgramDnDTree extends DragNDropTree {
|
||||
|
||||
ArrayList<ProgramNode> list = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < nodeList.size(); i++) {
|
||||
ProgramNode node = nodeList.get(i);
|
||||
|
||||
for (ProgramNode node : nodeList) {
|
||||
if (node.getName().equals(groupName)) {
|
||||
list.add(node);
|
||||
}
|
||||
@ -1358,9 +1278,7 @@ public class ProgramDnDTree extends DragNDropTree {
|
||||
|
||||
ArrayList<ProgramNode> list = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < nodeList.size(); i++) {
|
||||
ProgramNode node = nodeList.get(i);
|
||||
|
||||
for (ProgramNode node : nodeList) {
|
||||
Group group = node.getGroup();
|
||||
if (group != null && group.equals(g)) {
|
||||
list.add(node);
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -45,6 +45,8 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Construct a new ProgramNode with the given Group.
|
||||
* @param program the program
|
||||
* @param g the group
|
||||
*/
|
||||
ProgramNode(Program program, Group g) {
|
||||
this(program, g, g.getName());
|
||||
@ -52,6 +54,8 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Construct a new ProgramNode with the given name.
|
||||
* @param program the program
|
||||
* @param name the name
|
||||
*/
|
||||
ProgramNode(Program program, String name) {
|
||||
this(program, null, name);
|
||||
@ -60,6 +64,9 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
/**
|
||||
* Create a new ProgramNode with the given group and name;
|
||||
* use name for the displayed name of this node.
|
||||
* @param program the program
|
||||
* @param g the group
|
||||
* @param name the name
|
||||
*/
|
||||
ProgramNode(Program program, Group g, String name) {
|
||||
super(name);
|
||||
@ -148,6 +155,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Get the name for this node.
|
||||
* @return he name for this node.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
@ -155,6 +163,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Get the group for this node.
|
||||
* @return the group for this node.
|
||||
*/
|
||||
public Group getGroup() {
|
||||
return group;
|
||||
@ -162,6 +171,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Returns true if this node represents a Fragment.
|
||||
* @return true if this node represents a Fragment.
|
||||
*/
|
||||
public boolean isFragment() {
|
||||
return fragment != null;
|
||||
@ -169,6 +179,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Returns true if this node represents a Module.
|
||||
* @return true if this node represents a Module.
|
||||
*/
|
||||
public boolean isModule() {
|
||||
return module != null;
|
||||
@ -192,6 +203,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Get the program for this node.
|
||||
* @return the program for this node.
|
||||
*/
|
||||
public Program getProgram() {
|
||||
return program;
|
||||
@ -199,6 +211,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Return true if the node is in the view.
|
||||
* @return true if the node is in the view.
|
||||
*/
|
||||
public boolean isInView() {
|
||||
return isInView;
|
||||
@ -206,14 +219,12 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Get the group path for this node.
|
||||
* @return the group path for this node.
|
||||
*/
|
||||
public GroupPath getGroupPath() {
|
||||
return groupPath;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// package-level methods
|
||||
/////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Mark this node as having been populated (visited).
|
||||
*/
|
||||
@ -227,6 +238,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Return true if this node was visited.
|
||||
* @return true if this node was visited.
|
||||
*/
|
||||
boolean wasVisited() {
|
||||
return visited;
|
||||
@ -238,6 +250,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Get the tree path for this node.
|
||||
* @return the tree path for this node.
|
||||
*/
|
||||
TreePath getTreePath() {
|
||||
return path;
|
||||
@ -245,6 +258,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Set the tree path for this node.
|
||||
* @param path the tree path for this node.
|
||||
*/
|
||||
void setTreePath(TreePath path) {
|
||||
this.path = path;
|
||||
@ -252,6 +266,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Get the parent module for this node.
|
||||
* @return the parent module for this node.
|
||||
*/
|
||||
ProgramModule getParentModule() {
|
||||
return parentModule;
|
||||
@ -259,6 +274,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Set the parent module for this node.
|
||||
* @param parent the parents
|
||||
*/
|
||||
void setParentModule(ProgramModule parent) {
|
||||
parentModule = parent;
|
||||
@ -266,6 +282,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Set the name for this node.
|
||||
* @param name the name
|
||||
*/
|
||||
void setName(String name) {
|
||||
this.name = name;
|
||||
@ -273,8 +290,8 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this node to be deleted so that it can be
|
||||
* rendered as such.
|
||||
* Set this node to be deleted so that it can be rendered as such.
|
||||
* @param deleted true if deleted
|
||||
*/
|
||||
void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
@ -282,6 +299,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Returns whether this node is marked as deleted.
|
||||
* @return whether this node is marked as deleted.
|
||||
*/
|
||||
boolean isDeleted() {
|
||||
return deleted;
|
||||
@ -289,6 +307,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Set the group path for this node.
|
||||
* @param groupPath the path
|
||||
*/
|
||||
void setGroupPath(GroupPath groupPath) {
|
||||
this.groupPath = groupPath;
|
||||
@ -296,6 +315,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Mark this node as being in some view.
|
||||
* @param isInView true if in some view.
|
||||
*/
|
||||
void setInView(boolean isInView) {
|
||||
this.isInView = isInView;
|
||||
@ -326,6 +346,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Set the tree; this method is only called on the root node.
|
||||
* @param tree the tree
|
||||
*/
|
||||
void setTree(ProgramDnDTree tree) {
|
||||
this.tree = tree;
|
||||
@ -358,7 +379,7 @@ public class ProgramNode extends DefaultMutableTreeNode {
|
||||
|
||||
/**
|
||||
* Get the node named childName.
|
||||
* @param childName
|
||||
* @param childName the name
|
||||
* @return null if the node does not allow children, or the name was
|
||||
* not found.
|
||||
*/
|
||||
|
@ -1,13 +1,12 @@
|
||||
/* ###
|
||||
* 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.
|
||||
* 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.
|
||||
@ -28,38 +27,40 @@ import docking.action.KeyBindingData;
|
||||
*/
|
||||
abstract class ProgramTreeAction extends DockingAction {
|
||||
|
||||
final static int SINGLE_SELECTION=0;
|
||||
final static int MULTI_SELECTION=1;
|
||||
final static int SINGLE_SELECTION = 0;
|
||||
final static int MULTI_SELECTION = 1;
|
||||
|
||||
private int selectionType;
|
||||
private int selectionType;
|
||||
|
||||
ProgramTreeAction(String name, String owner, String[] defaultPopupPath, KeyStroke defaultKeyBinding) {
|
||||
this(name, owner, defaultPopupPath,
|
||||
defaultKeyBinding, MULTI_SELECTION);
|
||||
}
|
||||
ProgramTreeAction(String name, String owner,
|
||||
String[] defaultPopupPath,
|
||||
KeyStroke defaultKeyBinding,int selectionType) {
|
||||
super(name, owner);
|
||||
|
||||
this.selectionType = selectionType;
|
||||
if (defaultKeyBinding != null) {
|
||||
setKeyBindingData( new KeyBindingData( defaultKeyBinding ) );
|
||||
}
|
||||
setEnabled(false);
|
||||
}
|
||||
@Override
|
||||
public boolean isValidContext(ActionContext context) {
|
||||
return context.getContextObject() instanceof ProgramNode;
|
||||
}
|
||||
@Override
|
||||
public boolean isAddToPopup(ActionContext context) {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Get the selection type associated with this action.
|
||||
*/
|
||||
int getSelectionType() {
|
||||
return selectionType;
|
||||
}
|
||||
ProgramTreeAction(String name, String owner, KeyStroke defaultKeyBinding) {
|
||||
this(name, owner, defaultKeyBinding, MULTI_SELECTION);
|
||||
}
|
||||
|
||||
ProgramTreeAction(String name, String owner, KeyStroke defaultKeyBinding, int selectionType) {
|
||||
super(name, owner);
|
||||
|
||||
this.selectionType = selectionType;
|
||||
if (defaultKeyBinding != null) {
|
||||
setKeyBindingData(new KeyBindingData(defaultKeyBinding));
|
||||
}
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidContext(ActionContext context) {
|
||||
return context.getContextObject() instanceof ProgramNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAddToPopup(ActionContext context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the selection type associated with this action.
|
||||
* @return the selection type
|
||||
*/
|
||||
int getSelectionType() {
|
||||
return selectionType;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,170 @@
|
||||
/* ###
|
||||
* 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.programtree;
|
||||
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import ghidra.app.context.ProgramActionContext;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
/**
|
||||
* A context object for the {@link ProgramTreePlugin}.
|
||||
*/
|
||||
public class ProgramTreeActionContext extends ProgramActionContext {
|
||||
|
||||
private ViewManagerComponentProvider provider;
|
||||
|
||||
public ProgramTreeActionContext(ViewManagerComponentProvider provider, Program program,
|
||||
ViewPanel viewPanel, Object contextObject) {
|
||||
super(provider, program, viewPanel, contextObject);
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public ProgramDnDTree getTree() {
|
||||
ViewProviderService viewProvider = provider.getCurrentViewProvider();
|
||||
if (!(viewProvider instanceof TreeViewProvider treeProvider)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ProgramTreePanel treePanel = treeProvider.getViewComponent();
|
||||
return treePanel.getDnDTree();
|
||||
}
|
||||
|
||||
public TreePath[] getSelectionPaths() {
|
||||
ProgramDnDTree tree = getTree();
|
||||
if (tree == null) {
|
||||
return null;
|
||||
}
|
||||
return tree.getSelectionPaths();
|
||||
}
|
||||
|
||||
public ProgramNode getLeadSelectedNode() {
|
||||
ProgramNode node = getSingleSelectedNode();
|
||||
if (node != null) {
|
||||
return node; // only one node selected
|
||||
}
|
||||
|
||||
ProgramDnDTree tree = getTree();
|
||||
if (tree == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int n = tree.getSelectionCount();
|
||||
if (n == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TreePath path = tree.getSelectionPath();
|
||||
if (n > 1) {
|
||||
path = tree.getLeadSelectionPath();
|
||||
}
|
||||
return (ProgramNode) path.getLastPathComponent();
|
||||
}
|
||||
|
||||
public ProgramNode getSingleSelectedNode() {
|
||||
TreePath[] paths = getSelectionPaths();
|
||||
if (paths == null || paths.length != 1) {
|
||||
return null;
|
||||
}
|
||||
return (ProgramNode) paths[0].getLastPathComponent();
|
||||
}
|
||||
|
||||
public boolean hasSingleNodeSelection() {
|
||||
ProgramDnDTree tree = getTree();
|
||||
if (tree == null) {
|
||||
return false;
|
||||
}
|
||||
return tree.getSelectionCount() == 1;
|
||||
}
|
||||
|
||||
public boolean isOnlyRootNodeSelected() {
|
||||
ProgramDnDTree tree = getTree();
|
||||
if (tree == null) {
|
||||
return false;
|
||||
}
|
||||
TreePath[] paths = tree.getSelectionPaths();
|
||||
if (paths == null || paths.length != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ProgramNode node = (ProgramNode) paths[0].getLastPathComponent();
|
||||
DefaultTreeModel treeModel = (DefaultTreeModel) tree.getModel();
|
||||
ProgramNode root = (ProgramNode) treeModel.getRoot();
|
||||
return node == root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the selected paths: 1) do not contain the root node and 2) for each folder,
|
||||
* either all children are selected or no children are selected.
|
||||
*
|
||||
* @return true if the criteria above are met
|
||||
*/
|
||||
public boolean hasFullNodeMultiSelection() {
|
||||
|
||||
ProgramDnDTree tree = getTree();
|
||||
if (tree == null) {
|
||||
return false;
|
||||
}
|
||||
TreePath[] paths = tree.getSelectionPaths();
|
||||
if (paths == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DefaultTreeModel treeModel = (DefaultTreeModel) tree.getModel();
|
||||
ProgramNode root = (ProgramNode) treeModel.getRoot();
|
||||
for (TreePath path : paths) {
|
||||
ProgramNode node = (ProgramNode) path.getLastPathComponent();
|
||||
|
||||
if (node == root) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasMixedChildSelection(node, paths)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasMixedChildSelection(ProgramNode node, TreePath[] selectedPaths) {
|
||||
|
||||
if (!node.getAllowsChildren()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int nchild = node.getChildCount();
|
||||
int numberSelected = 0;
|
||||
|
||||
for (int i = 0; i < nchild; i++) {
|
||||
ProgramNode child = (ProgramNode) node.getChildAt(i);
|
||||
TreePath childPath = child.getTreePath();
|
||||
|
||||
// see if childPath is in selected list
|
||||
for (TreePath element : selectedPaths) {
|
||||
if (childPath.equals(element)) {
|
||||
++numberSelected;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numberSelected == 0 || numberSelected == nchild) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -19,6 +19,7 @@ import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
@ -56,9 +57,9 @@ class ProgramTreePanel extends JPanel implements ChangeListener {
|
||||
initialize();
|
||||
|
||||
// Disable tree expand/collapse on double-click.
|
||||
if (tree != null) {
|
||||
tree.setToggleClickCount(0);
|
||||
}
|
||||
tree.setToggleClickCount(0);
|
||||
|
||||
tree.addTreeSelectionListener(e -> plugin.contextChanged());
|
||||
}
|
||||
|
||||
// ChangeListener interface method
|
||||
@ -160,10 +161,9 @@ class ProgramTreePanel extends JPanel implements ChangeListener {
|
||||
* Get the currently viewed group paths.
|
||||
*/
|
||||
GroupView getGroupView() {
|
||||
ArrayList<TreePath> viewList = tree.getViewList();
|
||||
List<TreePath> viewList = tree.getViewList();
|
||||
ArrayList<GroupPath> list = new ArrayList<GroupPath>();
|
||||
for (int i = 0; i < viewList.size(); i++) {
|
||||
TreePath p = viewList.get(i);
|
||||
for (TreePath p : viewList) {
|
||||
ProgramNode node = (ProgramNode) p.getLastPathComponent();
|
||||
GroupPath gp = node.getGroupPath();
|
||||
if (gp != null) {
|
||||
@ -191,7 +191,7 @@ class ProgramTreePanel extends JPanel implements ChangeListener {
|
||||
}
|
||||
|
||||
ProgramNode prepareSelectionForPopup(MouseEvent event) {
|
||||
return tree.prepareSelectionForPopup(event);
|
||||
return tree.adjustSelectionForPopup(event);
|
||||
}
|
||||
|
||||
GroupPath[] getViewedGroups() {
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -83,14 +83,15 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
|
||||
private final static Icon NAVIGATION_ICON = Icons.NAVIGATE_ON_INCOMING_EVENT_ICON;
|
||||
|
||||
private ViewManagerComponentProvider componentProvider;
|
||||
private ProgramTreeActionManager actionManager;
|
||||
private TreeViewProvider defaultProvider;
|
||||
private TreeViewProvider currentProvider;
|
||||
private Map<String, TreeViewProvider> providerMap;// map of view providers, key is the name
|
||||
private GoToService goToService;
|
||||
private ViewManagerService viewManagerService;
|
||||
private ProgramTreeActionManager actionManager;
|
||||
private TreeViewProvider currentProvider;
|
||||
private ViewManagerComponentProvider viewProvider;
|
||||
|
||||
private ProgramListener programListener;
|
||||
private TreeViewProvider defaultProvider;
|
||||
private boolean firingGoTo;
|
||||
private RunManager runManager;
|
||||
private DockingAction createAction;
|
||||
@ -99,31 +100,30 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
private JPopupMenu popup;
|
||||
|
||||
/**
|
||||
* Tree signals that a user double-click will replace the view with the
|
||||
* current node
|
||||
* Tree signals that a user double-click will replace the view with the current node
|
||||
*/
|
||||
private boolean isReplaceViewMode = true;
|
||||
private boolean isReplaceViewMode = false;
|
||||
|
||||
public ProgramTreePlugin(PluginTool tool) {
|
||||
super(tool);
|
||||
|
||||
viewProvider = new ViewManagerComponentProvider(tool, getName());
|
||||
registerServiceProvided(ViewManagerService.class, viewProvider);
|
||||
componentProvider = new ViewManagerComponentProvider(tool, getName());
|
||||
registerServiceProvided(ViewManagerService.class, componentProvider);
|
||||
|
||||
providerMap = new HashMap<>();
|
||||
|
||||
actionManager = new ProgramTreeActionManager(this);
|
||||
registerActions();
|
||||
registerProviderActions();
|
||||
|
||||
programListener = new ProgramListener(this);
|
||||
runManager = new RunManager();
|
||||
runManager.showProgressBar(false);
|
||||
createActions();
|
||||
createPluginActions();
|
||||
|
||||
// show default provider
|
||||
defaultProvider = addTreeView(DEFAULT_TREE_NAME);
|
||||
|
||||
initOptions(tool.getOptions(PROGRAM_TREE_OPTION_NAME));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -131,7 +131,7 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
if (interfaceClass != ViewProviderService.class) {
|
||||
return;
|
||||
}
|
||||
viewProvider.serviceAdded((ViewProviderService) service);
|
||||
componentProvider.serviceAdded((ViewProviderService) service);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,7 +142,7 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
if (interfaceClass != ViewProviderService.class) {
|
||||
return;
|
||||
}
|
||||
viewProvider.serviceRemoved((ViewProviderService) service);
|
||||
componentProvider.serviceRemoved((ViewProviderService) service);
|
||||
}
|
||||
|
||||
private void initOptions(ToolOptions options) {
|
||||
@ -218,7 +218,7 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
programListener.dispose();
|
||||
}
|
||||
|
||||
viewProvider.dispose();
|
||||
componentProvider.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@ -246,7 +246,7 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
*/
|
||||
@Override
|
||||
public void writeDataState(SaveState saveState) {
|
||||
viewProvider.writeDataState(saveState);
|
||||
componentProvider.writeDataState(saveState);
|
||||
|
||||
saveState.putInt(NUMBER_OF_VIEWS, providerMap.size());
|
||||
int idx = 0;
|
||||
@ -312,7 +312,7 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
|
||||
restoreTreeViews();
|
||||
|
||||
viewProvider.readDataState(saveState);
|
||||
componentProvider.readDataState(saveState);
|
||||
}
|
||||
|
||||
private void restoreTreeViews() {
|
||||
@ -332,7 +332,7 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
list.add(provider);
|
||||
}
|
||||
|
||||
viewProvider.treeViewsRestored(list);
|
||||
componentProvider.treeViewsRestored(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -369,12 +369,11 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
protected void programActivated(Program program) {
|
||||
program.addListener(programListener);
|
||||
setProgram(program);
|
||||
viewProvider.setCurrentProgram(program);
|
||||
componentProvider.setCurrentProgram(program);
|
||||
}
|
||||
|
||||
private void removeStaleProviders(ArrayList<TreeViewProvider> providerList) {
|
||||
HashMap<String, TreeViewProvider> map = new HashMap<>(providerMap);
|
||||
|
||||
Map<String, TreeViewProvider> map = new HashMap<>(providerMap);
|
||||
for (String treeName : map.keySet()) {
|
||||
TreeViewProvider provider = map.get(treeName);
|
||||
if (!providerList.contains(provider)) {
|
||||
@ -384,9 +383,6 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization method: Get the services we need.
|
||||
*/
|
||||
@Override
|
||||
protected void init() {
|
||||
goToService = tool.getService(GoToService.class);
|
||||
@ -414,6 +410,10 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
}
|
||||
}
|
||||
|
||||
void contextChanged() {
|
||||
tool.contextChanged(componentProvider);
|
||||
}
|
||||
|
||||
void treeViewAdded(String treeName) {
|
||||
TreeViewProvider provider = providerMap.get(treeName);
|
||||
if (provider == null) {
|
||||
@ -430,10 +430,8 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
currentProvider.replaceView(node);
|
||||
}
|
||||
|
||||
// If the node is NOT the root node, just go to the location
|
||||
// of the first address in the fragment. If it's root, we
|
||||
// need to get the lowest address of any item in the
|
||||
// current view.
|
||||
// If the node is NOT the root node, just go to the location of the first address in the
|
||||
// fragment. If it's the root, we need to get the lowest address in the current view.
|
||||
if (node.isFragment()) {
|
||||
goTo(node.getFragment());
|
||||
}
|
||||
@ -445,7 +443,7 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
}
|
||||
}
|
||||
|
||||
void goTo(ProgramFragment fragment) {
|
||||
private void goTo(ProgramFragment fragment) {
|
||||
|
||||
Address minAddress = fragment.getMinAddress();
|
||||
|
||||
@ -671,6 +669,10 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
reloadTree(tree, false);
|
||||
}
|
||||
|
||||
void repaintProvider() {
|
||||
componentProvider.getComponent().repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remember expansion and selection state, and the reload the program
|
||||
* because it just got restored from an undo operation.
|
||||
@ -781,10 +783,10 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
return currentProgram.getListing().getRootModule(treeName) != null;
|
||||
}
|
||||
|
||||
private void registerActions() {
|
||||
private void registerProviderActions() {
|
||||
DockingAction[] actions = actionManager.getActions();
|
||||
for (DockingAction element : actions) {
|
||||
tool.addAction(element);
|
||||
for (DockingAction action : actions) {
|
||||
tool.addLocalAction(componentProvider, action);
|
||||
}
|
||||
}
|
||||
|
||||
@ -936,7 +938,7 @@ public class ProgramTreePlugin extends ProgramPlugin
|
||||
/**
|
||||
* Create the local actions that are shared among all the providers.
|
||||
*/
|
||||
private void createActions() {
|
||||
private void createPluginActions() {
|
||||
|
||||
openAction = new DockingAction("Open Tree View", getName()) {
|
||||
@Override
|
||||
|
@ -0,0 +1,81 @@
|
||||
/* ###
|
||||
* 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.programtree;
|
||||
|
||||
import java.awt.datatransfer.*;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import docking.dnd.GenericDataFlavor;
|
||||
|
||||
/**
|
||||
* Defines data that is available for drag/drop and clipboard transfers.
|
||||
* The data is an ArrayList of ProgramNode objects.
|
||||
*/
|
||||
class ProgramTreeTransferable implements Transferable, ClipboardOwner {
|
||||
|
||||
public static DataFlavor localTreeNodeFlavor = createLocalTreeNodeFlavor();
|
||||
|
||||
// create a data flavor that is an ArrayList of ProgramNode objects
|
||||
private static DataFlavor createLocalTreeNodeFlavor() {
|
||||
return new GenericDataFlavor(
|
||||
DataFlavor.javaJVMLocalObjectMimeType + "; class=java.util.ArrayList",
|
||||
"Local list of Tree Nodes");
|
||||
}
|
||||
|
||||
private static DataFlavor[] flavors = { localTreeNodeFlavor };
|
||||
|
||||
private static List<DataFlavor> flavorList = Arrays.asList(flavors);
|
||||
private List<ProgramNode> nodeList;
|
||||
|
||||
ProgramTreeTransferable(ProgramNode[] nodes) {
|
||||
nodeList = new ArrayList<ProgramNode>(Arrays.asList(nodes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized DataFlavor[] getTransferDataFlavors() {
|
||||
return flavors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataFlavorSupported(DataFlavor f) {
|
||||
return flavorList.contains(f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Object getTransferData(DataFlavor f)
|
||||
throws UnsupportedFlavorException, IOException {
|
||||
|
||||
if (f.equals(localTreeNodeFlavor)) {
|
||||
return nodeList;
|
||||
}
|
||||
throw new UnsupportedFlavorException(f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TreeTransferable";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lostOwnership(Clipboard clipboard, Transferable contents) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
void clearTransferData() {
|
||||
nodeList = null;
|
||||
}
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
/* ###
|
||||
* 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.
|
||||
* 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.programtree;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
import java.awt.datatransfer.ClipboardOwner;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import docking.dnd.GenericDataFlavor;
|
||||
|
||||
/**
|
||||
* Defines data that is available for drag/drop and clipboard transfers.
|
||||
* The data is an ArrayList of ProgramNode objects.
|
||||
*/
|
||||
class TreeTransferable implements Transferable, ClipboardOwner {
|
||||
|
||||
public static DataFlavor localTreeNodeFlavor = createLocalTreeNodeFlavor();
|
||||
|
||||
// create a data flavor that is an ArrayList of
|
||||
// ProgramNode objects
|
||||
private static DataFlavor createLocalTreeNodeFlavor() {
|
||||
try {
|
||||
return new GenericDataFlavor(
|
||||
DataFlavor.javaJVMLocalObjectMimeType+
|
||||
"; class=java.util.ArrayList",
|
||||
"Local list of Tree Nodes");
|
||||
}catch (Exception e) {
|
||||
Msg.showError(TreeTransferable.class, null, null, null, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static DataFlavor []flavors= { localTreeNodeFlavor };
|
||||
|
||||
private static List<DataFlavor> flavorList = Arrays.asList(flavors);
|
||||
private ArrayList<ProgramNode> nodeList;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
TreeTransferable(ProgramNode []nodes) {
|
||||
nodeList = new ArrayList<ProgramNode>(Arrays.asList(nodes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all data flavors that this class supports.
|
||||
*/
|
||||
public synchronized DataFlavor []getTransferDataFlavors() {
|
||||
return flavors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the specified data flavor is supported.
|
||||
*/
|
||||
public boolean isDataFlavorSupported(DataFlavor f) {
|
||||
return flavorList.contains(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transfer data with the given data flavor.
|
||||
*/
|
||||
public synchronized Object getTransferData(DataFlavor f)
|
||||
throws UnsupportedFlavorException, IOException {
|
||||
|
||||
if (f.equals(localTreeNodeFlavor)) {
|
||||
return nodeList;
|
||||
}
|
||||
throw new UnsupportedFlavorException(f);
|
||||
|
||||
}
|
||||
/**
|
||||
* Get the string representation for this transferable.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TreeTransferable";
|
||||
}
|
||||
|
||||
/**
|
||||
* ClipboardOwner interface method.
|
||||
*/
|
||||
public void lostOwnership(Clipboard clipboard, Transferable contents) {
|
||||
}
|
||||
|
||||
void clearTransferData() {
|
||||
nodeList = null;
|
||||
}
|
||||
}
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -19,7 +19,6 @@ import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
|
||||
import docking.ActionContext;
|
||||
@ -76,7 +75,7 @@ class TreeViewProvider implements ViewProviderService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getViewComponent() {
|
||||
public ProgramTreePanel getViewComponent() {
|
||||
return treePanel;
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -16,8 +16,7 @@
|
||||
package ghidra.app.plugin.core.programtree;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
|
||||
@ -40,7 +39,7 @@ public class ViewManagerComponentProvider extends ComponentProviderAdapter
|
||||
public static final String CURRENT_VIEW = "Current Viewname";
|
||||
|
||||
private ViewPanel viewPanel;
|
||||
private ArrayList<ViewChangeListener> listeners;
|
||||
private List<ViewChangeListener> listeners;
|
||||
private Program currentProgram;
|
||||
private String restoredViewName;
|
||||
|
||||
@ -72,6 +71,8 @@ public class ViewManagerComponentProvider extends ComponentProviderAdapter
|
||||
String currentName = NAME;
|
||||
ComponentProvider.registerProviderNameOwnerChange(intermediateName, currentOwner,
|
||||
currentName, currentOwner);
|
||||
|
||||
addToTool();
|
||||
}
|
||||
|
||||
void serviceAdded(ViewProviderService service) {
|
||||
@ -186,11 +187,14 @@ public class ViewManagerComponentProvider extends ComponentProviderAdapter
|
||||
}
|
||||
|
||||
if (event != null) {
|
||||
return new ProgramActionContext(this, currentProgram, viewPanel,
|
||||
getActivePopupObject(event));
|
||||
// this should be a ProgramNode or a tab
|
||||
Object clickedObject = getActivePopupObject(event);
|
||||
return new ProgramTreeActionContext(this, currentProgram, viewPanel, clickedObject);
|
||||
}
|
||||
|
||||
return new ProgramActionContext(this, currentProgram, viewPanel, getFocusedContext());
|
||||
// this should be a ProgramNode
|
||||
Object focusedObject = getFocusedContext();
|
||||
return new ProgramTreeActionContext(this, currentProgram, viewPanel, focusedObject);
|
||||
}
|
||||
|
||||
private Object getFocusedContext() {
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -17,8 +17,7 @@ package ghidra.app.plugin.core.programtree;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
@ -43,7 +42,7 @@ class ViewPanel extends JPanel implements ChangeListener {
|
||||
|
||||
private JTabbedPane tabbedPane;
|
||||
private ViewManagerComponentProvider provider;
|
||||
private HashMap<String, ViewProviderService> map;
|
||||
private Map<String, ViewProviderService> map;
|
||||
private DockingAction closeAction;
|
||||
private DockingAction deleteAction;
|
||||
private DockingAction renameAction;
|
||||
@ -71,10 +70,6 @@ class ViewPanel extends JPanel implements ChangeListener {
|
||||
*/
|
||||
void addView(ViewProviderService vp) {
|
||||
|
||||
if (!provider.isInTool()) {
|
||||
provider.addToTool();
|
||||
}
|
||||
|
||||
String name = vp.getViewName();
|
||||
if (map.remove(name) != null) {
|
||||
map.put(name, vp);
|
||||
@ -127,10 +122,6 @@ class ViewPanel extends JPanel implements ChangeListener {
|
||||
tabbedPane.addChangeListener(this);
|
||||
}
|
||||
|
||||
/*if (isEmpty()) {
|
||||
provider.removeFromTool();
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -15,8 +15,7 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.module;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@ -54,8 +53,7 @@ public class ModuleSortPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
tool.addPlugin(ProgramTreePlugin.class.getName());
|
||||
tool.addPlugin(ModuleSortPlugin.class.getName());
|
||||
List<Plugin> list = tool.getManagedPlugins();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Plugin p = list.get(i);
|
||||
for (Plugin p : list) {
|
||||
if (p.getClass() == ModuleSortPlugin.class) {
|
||||
plugin = (ModuleSortPlugin) p;
|
||||
break;
|
||||
@ -200,8 +198,6 @@ public class ModuleSortPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
ViewManagerService vmService = tool.getService(ViewManagerService.class);
|
||||
ViewProviderService vps = vmService.getCurrentViewProvider();
|
||||
|
||||
Object context = vps.getActivePopupObject(null);
|
||||
|
||||
for (DockingActionIf action : actions) {
|
||||
if (action.getName().indexOf("Address") > 0) {
|
||||
action.actionPerformed(vps.getActionContext(null));
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -18,6 +18,7 @@ package ghidra.app.plugin.core.programtree;
|
||||
import java.awt.Component;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
@ -87,6 +88,15 @@ public abstract class AbstractProgramTreePluginTest extends AbstractGhidraHeaded
|
||||
return context;
|
||||
}
|
||||
|
||||
protected void performTreeAction(DockingActionIf action) {
|
||||
performAction(action, getActionContext(), true);
|
||||
}
|
||||
|
||||
protected void waitForTreeEdit() {
|
||||
BooleanSupplier bs = () -> runSwing(() -> tree.isEditing());
|
||||
waitFor(bs);
|
||||
}
|
||||
|
||||
protected void setTreeView(final String viewName) {
|
||||
tree = plugin.getTree(viewName);
|
||||
root = (ProgramNode) tree.getModel().getRoot();
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -157,7 +157,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
DockingActionIf createFolderAction = getAction("Create Folder");
|
||||
|
||||
String newFolderName = tree.getNewFolderName();
|
||||
performAction(createFolderAction);
|
||||
performTreeAction(createFolderAction);
|
||||
commitEdit();
|
||||
waitForProgram(program);
|
||||
|
||||
@ -181,7 +181,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
DockingActionIf createFragmentAction = getAction("Create Fragment");
|
||||
|
||||
String newFragName = tree.getNewFragmentName();
|
||||
performAction(createFragmentAction);
|
||||
performTreeAction(createFragmentAction);
|
||||
commitEdit();
|
||||
waitForProgram(program);
|
||||
|
||||
@ -206,7 +206,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
int childCount = root.getChildCount();
|
||||
DockingActionIf createFolderAction = getAction("Create Folder");
|
||||
performAction(createFolderAction);
|
||||
performTreeAction(createFolderAction);
|
||||
commitEdit();
|
||||
waitForProgram(program);
|
||||
|
||||
@ -221,9 +221,9 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
String newName = tree.getNewFolderName();
|
||||
|
||||
DockingActionIf createFolderAction = getAction("Create Folder");
|
||||
performAction(createFolderAction, getActionContext(), true);
|
||||
|
||||
performTreeAction(createFolderAction);
|
||||
waitForBusyTool(tool);
|
||||
waitForTreeEdit();
|
||||
|
||||
String currentText = setEditorText("test1");
|
||||
assertEquals(newName, currentText);
|
||||
@ -241,7 +241,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
int childCount = root.getChildCount();
|
||||
|
||||
DockingActionIf createFragmentAction = getAction("Create Fragment");
|
||||
performAction(createFragmentAction, getActionContext(), true);
|
||||
performTreeAction(createFragmentAction);
|
||||
commitEdit();
|
||||
|
||||
waitFor(() -> root.getChildCount() == childCount + 1);
|
||||
@ -256,9 +256,9 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
String newName = tree.getNewFragmentName();
|
||||
|
||||
DockingActionIf createFragmentAction = getAction("Create Fragment");
|
||||
performAction(createFragmentAction, getActionContext(), true);
|
||||
|
||||
performTreeAction(createFragmentAction);
|
||||
waitForBusyTool(tool);
|
||||
waitForTreeEdit();
|
||||
|
||||
String currentText = setEditorText("test1");
|
||||
assertEquals(newName, currentText);
|
||||
@ -278,7 +278,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
setSelectionPath(node);
|
||||
|
||||
DockingActionIf deleteAction = getAction("Delete");
|
||||
performAction(deleteAction, getActionContext(), true);
|
||||
performTreeAction(deleteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
assertEquals(childCount - 1, root.getChildCount());
|
||||
@ -409,7 +409,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
DockingActionIf action = getAction(plugin, "Rename folder/fragment");
|
||||
assertTrue(action.isEnabledForContext(getActionContext()));
|
||||
performAction(action);
|
||||
performTreeAction(action);
|
||||
String currentText = setEditorText("printf");
|
||||
assertEquals("submodule", currentText);
|
||||
}
|
||||
@ -429,7 +429,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
setSelectionPath(nodes[0]);
|
||||
DockingActionIf action = getAction(plugin, "Rename folder/fragment");
|
||||
assertTrue(action.isEnabledForContext(getActionContext()));
|
||||
performAction(action);
|
||||
performTreeAction(action);
|
||||
String currentText = setEditorText(".data");
|
||||
|
||||
ProgramModule module = getModule(root, "Module-1");
|
||||
@ -451,7 +451,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
setSelectionPath(nodes[0]);
|
||||
DockingActionIf action = getAction(plugin, "Rename folder/fragment");
|
||||
assertTrue(action.isEnabledForContext(getActionContext()));
|
||||
performAction(action);
|
||||
performTreeAction(action);
|
||||
String currentText = setEditorText("My Module-1");
|
||||
assertEquals("My Module-1", currentText);
|
||||
waitForProgram(program);
|
||||
@ -648,7 +648,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
DockingActionIf removeAction = getAction("Remove");
|
||||
assertTrue(removeAction.isEnabledForContext(getActionContext()));
|
||||
performAction(removeAction, getActionContext(), true);
|
||||
performTreeAction(removeAction);
|
||||
|
||||
AddressSet set = new AddressSet();
|
||||
set.add(node.getFragment());
|
||||
@ -705,13 +705,13 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
}
|
||||
setSelectionPaths(node);
|
||||
|
||||
DockingActionIf replaceAction = getAction("Replace");
|
||||
performAction(replaceAction);
|
||||
DockingActionIf replaceAction = getAction("Set View");
|
||||
performTreeAction(replaceAction);
|
||||
|
||||
assertTrue(getView().hasSameAddresses(node.getModule().getAddressSet()));
|
||||
|
||||
DockingActionIf removeAction = getAction("Remove");
|
||||
performAction(removeAction);
|
||||
performTreeAction(removeAction);
|
||||
|
||||
assertTrue(getView().isEmpty());
|
||||
assertTrue(cbPlugin.getView().isEmpty());
|
||||
@ -750,7 +750,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
setSelectionPaths(node0, node2);
|
||||
|
||||
DockingActionIf removeAction = getAction("Remove");
|
||||
performAction(removeAction);
|
||||
performTreeAction(removeAction);
|
||||
|
||||
AddressSet set = new AddressSet();
|
||||
set.add(node0.getFragment());
|
||||
@ -799,7 +799,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
setSelectionPath(nodes[0]);
|
||||
|
||||
DockingActionIf removeAction = getAction("Remove");
|
||||
performAction(removeAction);
|
||||
performTreeAction(removeAction);
|
||||
|
||||
// verify that all the descendants of the folder are removed from the view
|
||||
assertFalse(getView().contains(child1.getFragment()));
|
||||
@ -819,8 +819,8 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
ProgramNode child = (ProgramNode) node.getChildAt(0);
|
||||
setSelectionPath(child);
|
||||
|
||||
DockingActionIf replaceAction = getAction("Replace");
|
||||
performAction(replaceAction);
|
||||
DockingActionIf replaceAction = getAction("Set View");
|
||||
performTreeAction(replaceAction);
|
||||
|
||||
assertTrue(getView().hasSameAddresses(child.getFragment()));
|
||||
assertTrue(getView().hasSameAddresses(cbPlugin.getView()));
|
||||
@ -841,9 +841,9 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
ProgramNode node = (ProgramNode) root.getChildAt(6);
|
||||
setSelectionPath(node);
|
||||
|
||||
DockingActionIf replaceAction = getAction("Replace");
|
||||
DockingActionIf replaceAction = getAction("Set View");
|
||||
assertTrue(replaceAction.isEnabledForContext(getActionContext()));
|
||||
performAction(replaceAction, getActionContext(), true);
|
||||
performTreeAction(replaceAction);
|
||||
|
||||
assertTrue(plugin.getView().hasSameAddresses(node.getModule().getAddressSet()));
|
||||
assertPluginViewAppliedToTool();
|
||||
@ -869,8 +869,8 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
// descendant of that folder, and not in the view
|
||||
setSelectionPaths(dllsNode, sscanfNode);
|
||||
|
||||
DockingActionIf replaceAction = getAction("Replace");
|
||||
performAction(replaceAction);
|
||||
DockingActionIf replaceAction = getAction("Set View");
|
||||
performTreeAction(replaceAction);
|
||||
|
||||
AddressSet set = new AddressSet();
|
||||
set.add(dllsNode.getModule().getAddressSet());
|
||||
@ -921,7 +921,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
setSelectionPath(dllsNode);
|
||||
|
||||
DockingActionIf mergeAction = getAction("Merge");
|
||||
performAction(mergeAction);
|
||||
performTreeAction(mergeAction);
|
||||
waitForProgram(program);
|
||||
|
||||
int count = nodes[0].getChildCount();
|
||||
@ -954,7 +954,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
setSelectionPaths(dNodes[0], bNodes[0]);
|
||||
|
||||
DockingActionIf mergeAction = getAction("Merge");
|
||||
performAction(mergeAction, getActionContext(), true);
|
||||
performTreeAction(mergeAction);
|
||||
waitForProgram(program);
|
||||
|
||||
assertEquals(7, root.getChildCount());
|
||||
@ -1104,7 +1104,7 @@ public class ProgramTreePlugin1Test extends AbstractProgramTreePluginTest {
|
||||
assertTrue(showAction.isEnabledForContext(getActionContext()));
|
||||
String[] treeNames = program.getListing().getTreeNames();
|
||||
|
||||
performAction(showAction);
|
||||
performTreeAction(showAction);
|
||||
|
||||
JPopupMenu menu = plugin.getPopupMenu();
|
||||
assertNotNull(menu);
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -24,7 +24,6 @@ import javax.swing.tree.TreePath;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import docking.DefaultActionContext;
|
||||
import docking.action.DockingActionIf;
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
@ -108,14 +107,14 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
setSelectionPath(node);
|
||||
assertTrue(copyAction.isEnabled());
|
||||
performAction(copyAction);
|
||||
performTreeAction(copyAction);
|
||||
|
||||
node = (ProgramNode) root.getChildAt(5);
|
||||
int origCount = node.getChildCount();
|
||||
setSelectionPath(node);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
expandNode(node);
|
||||
@ -142,7 +141,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
ProgramNode node = (ProgramNode) root.getChildAt(0);
|
||||
setSelectionPath(node);
|
||||
assertTrue(copyAction.isEnabled());
|
||||
performAction(copyAction);
|
||||
performTreeAction(copyAction);
|
||||
|
||||
setSelectionPath(root);
|
||||
|
||||
@ -161,7 +160,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
setSelectionPath(node);
|
||||
assertTrue(copyAction.isEnabled());
|
||||
|
||||
performAction(copyAction, true);
|
||||
performTreeAction(copyAction);
|
||||
ProgramNode[] nodes = findNodes("C");
|
||||
setSelectionPath(nodes[0]);
|
||||
|
||||
@ -180,7 +179,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
// select USER32.DLL
|
||||
setSelectionPath(fnode);
|
||||
performAction(copyAction);
|
||||
performTreeAction(copyAction);
|
||||
// select DLLs
|
||||
node = (ProgramNode) root.getChildAt(6);
|
||||
setSelectionPath(node);
|
||||
@ -200,10 +199,10 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
setSelectionPath(cpNode);
|
||||
|
||||
performAction(copyAction);
|
||||
performTreeAction(copyAction);
|
||||
setSelectionPath(pasteNode);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
assertEquals(childCount + 1, pasteNode.getChildCount());
|
||||
@ -228,7 +227,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
ProgramNode cnode2 = (ProgramNode) node.getChildAt(1);
|
||||
setSelectionPaths(cnode1, cnode2);
|
||||
assertTrue(copyAction.isEnabled());
|
||||
performAction(copyAction);
|
||||
performTreeAction(copyAction);
|
||||
// create a new module and paste fragments there
|
||||
tx(program, () -> {
|
||||
root.getModule().createModule("Test");
|
||||
@ -238,7 +237,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
setSelectionPath(destNode);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
visitNode(destNode);
|
||||
@ -253,7 +252,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
ProgramNode cnode2 = (ProgramNode) node.getChildAt(1);
|
||||
setSelectionPaths(cnode1, cnode2);
|
||||
assertTrue(copyAction.isEnabled());
|
||||
performAction(copyAction);
|
||||
performTreeAction(copyAction);
|
||||
// create a new module and paste fragments there
|
||||
tx(program, () -> {
|
||||
ProgramModule m = root.getModule().createModule("Test");
|
||||
@ -266,7 +265,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
setSelectionPath(destNode);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
expandNode(root);
|
||||
@ -300,7 +299,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
ProgramNode cnode2 = (ProgramNode) node.getChildAt(1);
|
||||
setSelectionPaths(cnode1, cnode2);
|
||||
assertTrue(copyAction.isEnabled());
|
||||
performAction(copyAction);
|
||||
performTreeAction(copyAction);
|
||||
|
||||
// get node for DLLs
|
||||
ProgramNode destNode = (ProgramNode) root.getChildAt(5);
|
||||
@ -308,7 +307,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
setSelectionPath(destNode);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
expandNode(root);
|
||||
@ -341,12 +340,12 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
// set the view to Functions
|
||||
setSelectionPath(node);
|
||||
setViewPaths(node);
|
||||
performAction(copyAction);
|
||||
performTreeAction(copyAction);
|
||||
ProgramNode subrNode = (ProgramNode) root.getChildAt(8);
|
||||
|
||||
setSelectionPath(subrNode);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
// verify the view is not affected
|
||||
@ -375,10 +374,10 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
setSelectionPath(subrNode);
|
||||
|
||||
performAction(copyAction);
|
||||
performTreeAction(copyAction);
|
||||
setSelectionPath(node);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
assertTrue(plugin.getView().hasSameAddresses(node.getModule().getAddressSet()));
|
||||
@ -399,12 +398,12 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
ProgramNode child = (ProgramNode) node.getChildAt(0);
|
||||
setSelectionPath(child);
|
||||
performAction(copyAction);
|
||||
performTreeAction(copyAction);
|
||||
ProgramNode subrNode = (ProgramNode) root.getChildAt(8);
|
||||
|
||||
setSelectionPath(subrNode);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
// verify the view is not affected
|
||||
@ -426,14 +425,14 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
setSelectionPath(fnode);
|
||||
assertTrue(cutAction.isEnabled());
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
|
||||
ProgramNode funcNode = (ProgramNode) root.getChildAt(6);// Functions
|
||||
ProgramNode destNode = (ProgramNode) funcNode.getChildAt(0);// doStuff fragment
|
||||
|
||||
// now select the doStuff fragment as the destination node
|
||||
setSelectionPath(destNode);
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
assertTrue(destNode.getFragment().contains(fnodeSet));
|
||||
@ -479,14 +478,14 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
setSelectionPath(fnode);
|
||||
assertTrue(cutAction.isEnabled());
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
|
||||
ProgramNode funcNode = (ProgramNode) root.getChildAt(6);// Functions
|
||||
ProgramNode destNode = (ProgramNode) funcNode.getChildAt(0);// ghidra fragment
|
||||
|
||||
// now select the ghidra fragment as the destination node
|
||||
setSelectionPath(destNode);
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
assertTrue(destNode.getFragment().contains(fnodeSet));
|
||||
@ -523,14 +522,14 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
setSelectionPath(node);
|
||||
assertTrue(cutAction.isEnabled());
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
|
||||
node = (ProgramNode) root.getChildAt(5);//DLLs
|
||||
int origCount = node.getChildCount();
|
||||
setSelectionPath(node);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
expandNode(node);
|
||||
@ -558,10 +557,10 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
setSelectionPath(cNode);
|
||||
// cut Functions
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
setSelectionPath(destNode);// paste at DLLs
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
assertEquals(childCount + 1, destNode.getChildCount());
|
||||
@ -604,12 +603,12 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
setSelectionPath(stringsNode);
|
||||
|
||||
// cut Strings
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
// paste at Functions
|
||||
ProgramNode funcNode = root.getChild("Functions");
|
||||
setSelectionPath(funcNode);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
// Strings, L should be expanded
|
||||
@ -636,13 +635,13 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
setSelectionPath(stringsNode);
|
||||
|
||||
// cut Strings
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
// paste at Functions
|
||||
ProgramNode funcNode = root.getChild("Functions");
|
||||
collapsePath(funcNode.getTreePath());
|
||||
setSelectionPath(funcNode);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
|
||||
// Functions should remain collapsed
|
||||
assertTrue(tree.isCollapsed(funcNode.getTreePath()));
|
||||
@ -663,13 +662,13 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
setSelectionPath(stringsNode);
|
||||
|
||||
// cut Strings
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
// paste at Functions
|
||||
ProgramNode funcNode = root.getChild("Functions");
|
||||
expandPath(funcNode.getTreePath());
|
||||
setSelectionPath(funcNode);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
|
||||
stringsNode = funcNode.getChild("Strings");
|
||||
assertTrue(tree.isCollapsed(stringsNode.getTreePath()));
|
||||
@ -690,14 +689,14 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
setSelectionPath(stringsNode);
|
||||
|
||||
// cut Strings
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
// paste at Functions
|
||||
ProgramNode funcNode = root.getChild("Functions");
|
||||
visitNode(funcNode);
|
||||
collapsePath(funcNode.getTreePath());
|
||||
setSelectionPath(funcNode);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
|
||||
assertTrue(tree.isCollapsed(funcNode.getTreePath()));
|
||||
}
|
||||
@ -721,14 +720,14 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
setSelectionPaths(new TreePath[] { rsrcNode.getTreePath(), textNode.getTreePath() });
|
||||
|
||||
// cut Strings
|
||||
runSwing(() -> cutAction.actionPerformed(new DefaultActionContext()));
|
||||
performTreeAction(cutAction);
|
||||
|
||||
// select Strings (has no fragments)
|
||||
ProgramNode stringsNode = root.getChild("Strings");
|
||||
visitNode(stringsNode);
|
||||
setSelectionPath(stringsNode);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
|
||||
assertEquals(3, stringsNode.getChildCount());
|
||||
assertEquals("rsrc", stringsNode.getChildAt(1).toString());
|
||||
@ -788,7 +787,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
addSelectionPath(cutNodes[i].getTreePath());
|
||||
}
|
||||
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
|
||||
// select a destination fragment
|
||||
ProgramNode stringsNode = root.getChild("Strings");
|
||||
@ -798,7 +797,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
ProgramNode fnode = cNode.getChild("testl");
|
||||
setSelectionPath(fnode);
|
||||
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
|
||||
for (ProgramNode cutNode : cutNodes) {
|
||||
assertNull(listing.getFragment("Main Tree", cutNode.getName()));
|
||||
@ -859,7 +858,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
ProgramNode testNode = root.getChild("Test");
|
||||
setSelectionPath(testNode);
|
||||
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
|
||||
// paste at 010074d4
|
||||
ProgramNode stringsNode = root.getChild("Strings");
|
||||
@ -869,7 +868,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
ProgramNode fnode = cNode.getChild("testl");
|
||||
setSelectionPath(fnode);
|
||||
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
root = (ProgramNode) tree.getModel().getRoot();
|
||||
@ -937,12 +936,12 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
// set the view to DLLs
|
||||
setSelectionPath(node);
|
||||
setViewPaths(new TreePath[] { node.getTreePath() });
|
||||
performAction(copyAction);
|
||||
performTreeAction(copyAction);
|
||||
ProgramNode everythingNode = root.getChild("Everything");
|
||||
|
||||
setSelectionPath(everythingNode);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
waitForProgram(program);
|
||||
|
||||
// cut a fragment in the view and paste onto a collapsed folder
|
||||
@ -953,7 +952,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
ProgramNode dataNode = root.getChild(".data");
|
||||
setSelectionPath(dataNode);
|
||||
setViewPaths(new TreePath[] { dataNode.getTreePath() });
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
|
||||
// select DLLs in Everything
|
||||
ProgramNode evNode = root.getChild("Everything");
|
||||
@ -962,7 +961,7 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
visitNode(dllsNode);
|
||||
setSelectionPath(dllsNode);
|
||||
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
|
||||
// first occurrence of DLLs should have icon for descendant in view
|
||||
ProgramNode[] nodes = findNodes("DLLs");
|
||||
@ -991,13 +990,13 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
assertTrue(plugin.getView().hasSameAddresses(set));
|
||||
|
||||
setSelectionPath(debugNode);
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
|
||||
// paste to an expanded folder not in the view
|
||||
ProgramNode subrNode = root.getChild("Subroutines");
|
||||
expandNode(subrNode);
|
||||
setSelectionPath(subrNode);
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
|
||||
assertTrue(plugin.getView().hasSameAddresses(set));
|
||||
}
|
||||
@ -1012,14 +1011,14 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
setViewPaths(dataNode, debugNode);
|
||||
|
||||
setSelectionPath(debugNode);
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
// paste onto another fragment that is not in the view
|
||||
ProgramNode funcNode = root.getChild("Functions");
|
||||
visitNode(funcNode);
|
||||
ProgramNode sscanfNode = funcNode.getChild("sscanf");
|
||||
|
||||
setSelectionPath(sscanfNode);
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
|
||||
assertTrue(plugin.getView().hasSameAddresses(dataNode.getFragment()));
|
||||
}
|
||||
@ -1042,11 +1041,11 @@ public class ProgramTreePlugin2Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
// cut first fragment in Subroutines
|
||||
setSelectionPath(node);
|
||||
performAction(cutAction);
|
||||
performTreeAction(cutAction);
|
||||
|
||||
// paste at the debug node
|
||||
setSelectionPath(debugNode);
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
|
||||
assertTrue(plugin.getView().contains(set));
|
||||
}
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -428,8 +428,7 @@ public class ProgramTreePlugin3Test extends AbstractProgramTreePluginTest {
|
||||
waitForSwing();
|
||||
|
||||
Component comp = getCellRendererComponentForLeaf(n, row);
|
||||
assertEquals(new GIcon(DnDTreeCellRenderer.VIEWED_FRAGMENT),
|
||||
((JLabel) comp).getIcon());
|
||||
assertEquals(new GIcon(DnDTreeCellRenderer.VIEWED_FRAGMENT), ((JLabel) comp).getIcon());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1380,7 +1379,7 @@ public class ProgramTreePlugin3Test extends AbstractProgramTreePluginTest {
|
||||
AtomicReference<Exception> ref = new AtomicReference<>();
|
||||
runSwing(() -> {
|
||||
try {
|
||||
tree.processDropRequest(node, list, TreeTransferable.localTreeNodeFlavor,
|
||||
tree.processDropRequest(node, list, ProgramTreeTransferable.localTreeNodeFlavor,
|
||||
dropAction);
|
||||
}
|
||||
catch (NotFoundException | CircularDependencyException | DuplicateGroupException e) {
|
||||
@ -1443,12 +1442,12 @@ public class ProgramTreePlugin3Test extends AbstractProgramTreePluginTest {
|
||||
|
||||
setSelectionPath(node);
|
||||
setViewPaths(node);
|
||||
performAction(copyAction);
|
||||
performTreeAction(copyAction);
|
||||
ProgramNode everythingNode = root.getChild(dst);
|
||||
|
||||
setSelectionPath(everythingNode);
|
||||
assertTrue(pasteAction.isEnabled());
|
||||
performAction(pasteAction);
|
||||
performTreeAction(pasteAction);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -277,7 +277,7 @@ public class ProgramTreePluginShowInViewTest extends AbstractGhidraHeadedIntegra
|
||||
|
||||
ProgramNode textNode = root.getChild(".text");
|
||||
setSelectionPath(textNode.getTreePath());
|
||||
DockingActionIf replaceAction = getAction(plugin, "Replace View");
|
||||
DockingActionIf replaceAction = getAction(plugin, "Set View");
|
||||
|
||||
ActionContext context = getActionContext();
|
||||
performAction(replaceAction, context, true);
|
||||
@ -312,7 +312,7 @@ public class ProgramTreePluginShowInViewTest extends AbstractGhidraHeadedIntegra
|
||||
ProgramNode rsrcNode = root.getChild(".rsrc");
|
||||
|
||||
addSelectionPath(rsrcNode.getTreePath());
|
||||
DockingActionIf replaceAction = getAction(plugin, "Replace View");
|
||||
DockingActionIf replaceAction = getAction(plugin, "Set View");
|
||||
ActionContext context = getActionContext();
|
||||
performAction(replaceAction, context, true);
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -136,8 +136,7 @@ public class ViewManagerPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertEquals(treeNames.length, tabbedPane.getTabCount());
|
||||
assertEquals(DEFAULT_TREE_NAME + "(1)", vps.getViewName());
|
||||
assertEquals(tabbedPane.getSelectedComponent(), vps.getViewComponent());
|
||||
SwingUtilities
|
||||
.invokeAndWait(() -> createTreeAction.actionPerformed(new DefaultActionContext()));
|
||||
performAction(createTreeAction);
|
||||
program.flushEvents();
|
||||
vps = provider.getCurrentViewProvider();
|
||||
treeNames = program.getListing().getTreeNames();
|
||||
@ -152,8 +151,7 @@ public class ViewManagerPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
public void testUndoRedo() throws Exception {
|
||||
ProgramTreePlugin treePlugin = env.getPlugin(ProgramTreePlugin.class);
|
||||
final DockingActionIf createTreeAction = getAction(treePlugin, "Create Default Tree View");
|
||||
SwingUtilities
|
||||
.invokeAndWait(() -> createTreeAction.actionPerformed(new DefaultActionContext()));
|
||||
performAction(createTreeAction);
|
||||
program.flushEvents();
|
||||
env.showTool();
|
||||
ViewProviderService vps = provider.getCurrentViewProvider();
|
||||
@ -163,8 +161,7 @@ public class ViewManagerPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
assertEquals(treeNames.length, tabbedPane.getTabCount());
|
||||
assertEquals(DEFAULT_TREE_NAME + "(1)", vps.getViewName());
|
||||
assertEquals(tabbedPane.getSelectedComponent(), vps.getViewComponent());
|
||||
SwingUtilities
|
||||
.invokeAndWait(() -> createTreeAction.actionPerformed(new DefaultActionContext()));
|
||||
performAction(createTreeAction);
|
||||
program.flushEvents();
|
||||
vps = provider.getCurrentViewProvider();
|
||||
treeNames = program.getListing().getTreeNames();
|
||||
@ -237,7 +234,7 @@ public class ViewManagerPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
public void testCloseView() throws Exception {
|
||||
// close "Program Tree"
|
||||
final DockingActionIf closeAction = getAction(plugin, "Close Tree View");
|
||||
SwingUtilities.invokeAndWait(() -> closeAction.actionPerformed(new DefaultActionContext()));
|
||||
performAction(closeAction);
|
||||
|
||||
waitForBusyTool(tool);
|
||||
|
||||
@ -261,8 +258,7 @@ public class ViewManagerPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
setCurrentViewProvider("Tree Two");
|
||||
|
||||
final DockingActionIf deleteAction = getAction(plugin, "Delete Tree View");
|
||||
SwingUtilities
|
||||
.invokeAndWait(() -> deleteAction.actionPerformed(new DefaultActionContext()));
|
||||
performAction(deleteAction);
|
||||
|
||||
waitForBusyTool(tool);
|
||||
|
||||
@ -300,31 +296,26 @@ public class ViewManagerPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
setCurrentViewProvider("Main Tree");
|
||||
|
||||
SwingUtilities
|
||||
.invokeAndWait(() -> deleteAction.actionPerformed(new DefaultActionContext()));
|
||||
performAction(deleteAction);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
setCurrentViewProvider("Tree One");
|
||||
|
||||
SwingUtilities
|
||||
.invokeAndWait(() -> deleteAction.actionPerformed(new DefaultActionContext()));
|
||||
performAction(deleteAction);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
setCurrentViewProvider("Tree Two");
|
||||
|
||||
SwingUtilities
|
||||
.invokeAndWait(() -> deleteAction.actionPerformed(new DefaultActionContext()));
|
||||
performAction(deleteAction);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
setCurrentViewProvider("Tree Three");
|
||||
|
||||
SwingUtilities
|
||||
.invokeAndWait(() -> deleteAction.actionPerformed(new DefaultActionContext()));
|
||||
performAction(deleteAction);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
// attempt to delete the last view
|
||||
SwingUtilities
|
||||
.invokeAndWait(() -> deleteAction.actionPerformed(new DefaultActionContext()));
|
||||
performAction(deleteAction);
|
||||
waitForBusyTool(tool);
|
||||
|
||||
ViewProviderService vps = provider.getCurrentViewProvider();
|
||||
@ -341,10 +332,10 @@ public class ViewManagerPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
final DockingActionIf closeAction = getAction(plugin, "Close Tree View");
|
||||
|
||||
setCurrentViewProvider(DEFAULT_TREE_NAME);
|
||||
SwingUtilities.invokeAndWait(() -> closeAction.actionPerformed(new DefaultActionContext()));
|
||||
performAction(closeAction);
|
||||
|
||||
setCurrentViewProvider("Main Tree");
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
runSwing(() -> {
|
||||
closeAction.actionPerformed(new DefaultActionContext());
|
||||
provider.setCurrentViewProvider("Tree One");
|
||||
closeAction.actionPerformed(new DefaultActionContext());
|
||||
|
Loading…
Reference in New Issue
Block a user