GT-2705 - File Import - fixed drag-n-drop onto Project Tree dialogs

This commit is contained in:
dragonmacher 2019-03-28 18:24:34 -04:00
parent 097cf2e758
commit 84c16c2b27
18 changed files with 240 additions and 560 deletions

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,11 +15,14 @@
*/
package ghidra.app.util;
import ghidra.framework.plugintool.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import ghidra.framework.plugintool.PluginTool;
/**
* Interface for classes that will handle drop actions for files dropped onto the tool
*/
public interface FileOpenDataFlavorHandler {
public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f);
public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f);
}

View file

@ -1,37 +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.util;
import ghidra.framework.PluggableServiceRegistry;
import ghidra.framework.main.datatree.DataTreeDragNDropHandler;
import ghidra.framework.main.datatree.VersionInfoTransferable;
public class FileOpenDataFlavorHandlerService {
static {
PluggableServiceRegistry.registerPluggableService(FileOpenDataFlavorHandlerService.class, new FileOpenDataFlavorHandlerService());
}
public static void registerDataFlavorHandlers() {
FileOpenDataFlavorHandlerService factory = PluggableServiceRegistry.getPluggableService(FileOpenDataFlavorHandlerService.class);
factory.doRegisterDataFlavorHandlers();
}
protected void doRegisterDataFlavorHandlers() {
FileOpenDropHandler.addDataFlavorHandler(DataTreeDragNDropHandler.localDomainFileFlavor, new LocalTreeNodeFlavorHandler());
FileOpenDropHandler.addDataFlavorHandler(VersionInfoTransferable.localVersionInfoFlavor, new LocalTreeNodeFlavorHandler());
}
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,9 +15,6 @@
*/
package ghidra.app.util;
import ghidra.framework.plugintool.PluginTool;
import ghidra.util.CascadedDropTarget;
import java.awt.Component;
import java.awt.Container;
import java.awt.datatransfer.DataFlavor;
@ -33,6 +29,8 @@ import javax.swing.CellRendererPane;
import docking.DropTargetHandler;
import docking.dnd.DropTgtAdapter;
import docking.dnd.Droppable;
import ghidra.framework.plugintool.PluginTool;
import ghidra.util.CascadedDropTarget;
/**
* Handles drag/drop events on a given component such that a file
@ -44,9 +42,6 @@ import docking.dnd.Droppable;
public class FileOpenDropHandler implements DropTargetHandler, Droppable, ContainerListener {
private static HashMap<DataFlavor, FileOpenDataFlavorHandler> handlers =
new HashMap<DataFlavor, FileOpenDataFlavorHandler>();
static {
FileOpenDataFlavorHandlerService.registerDataFlavorHandlers();
}
private DropTgtAdapter dropTargetAdapter;
private DropTarget globalDropTarget;
@ -75,11 +70,13 @@ public class FileOpenDropHandler implements DropTargetHandler, Droppable, Contai
/**
* Dispose this drop handler.
*/
@Override
public void dispose() {
deinitializeComponents(component);
globalDropTarget.removeDropTargetListener(dropTargetAdapter);
}
@Override
public boolean isDropOk(DropTargetDragEvent e) {
Set<DataFlavor> flavors = handlers.keySet();
for (DataFlavor dataFlavor : flavors) {
@ -90,6 +87,7 @@ public class FileOpenDropHandler implements DropTargetHandler, Droppable, Contai
return false;
}
@Override
public void add(Object obj, DropTargetDropEvent e, DataFlavor f) {
FileOpenDataFlavorHandler handler = handlers.get(f);
if (handler != null) {
@ -97,24 +95,28 @@ public class FileOpenDropHandler implements DropTargetHandler, Droppable, Contai
}
}
@Override
public void dragUnderFeedback(boolean ok, DropTargetDragEvent e) {
// nothing to display or do
}
@Override
public void undoDragUnderFeedback() {
// nothing to display or do
}
private void initializeComponents(Component comp) {
if (comp instanceof CellRendererPane)
if (comp instanceof CellRendererPane) {
return;
}
if (comp instanceof Container) {
Container c = (Container) comp;
c.addContainerListener(this);
Component comps[] = c.getComponents();
for (Component element : comps)
for (Component element : comps) {
initializeComponents(element);
}
}
DropTarget primaryDropTarget = comp.getDropTarget();
if (primaryDropTarget != null) {
@ -123,15 +125,17 @@ public class FileOpenDropHandler implements DropTargetHandler, Droppable, Contai
}
private void deinitializeComponents(Component comp) {
if (comp instanceof CellRendererPane)
if (comp instanceof CellRendererPane) {
return;
}
if (comp instanceof Container) {
Container c = (Container) comp;
c.removeContainerListener(this);
Component comps[] = c.getComponents();
for (Component element : comps)
for (Component element : comps) {
deinitializeComponents(element);
}
}
DropTarget dt = comp.getDropTarget();
if (dt instanceof CascadedDropTarget) {
@ -141,15 +145,18 @@ public class FileOpenDropHandler implements DropTargetHandler, Droppable, Contai
}
}
@Override
public void componentAdded(ContainerEvent e) {
initializeComponents(e.getChild());
}
@Override
public void componentRemoved(ContainerEvent e) {
deinitializeComponents(e.getChild());
}
public static void addDataFlavorHandler(DataFlavor dataFlavor, FileOpenDataFlavorHandler handler) {
public static void addDataFlavorHandler(DataFlavor dataFlavor,
FileOpenDataFlavorHandler handler) {
handlers.put(dataFlavor, handler);
}

View file

@ -1,72 +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.util;
import ghidra.framework.main.GetVersionedObjectTask;
import ghidra.framework.main.datatree.*;
import ghidra.framework.model.*;
import ghidra.framework.plugintool.PluginTool;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DropTargetDropEvent;
import java.util.List;
final class LocalTreeNodeFlavorHandler implements FileOpenDataFlavorHandler {
public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f) {
if (f.equals(DataTreeDragNDropHandler.localDomainFileFlavor)) {
List<?> files = (List<?>) obj;
DomainFile[] domainFiles = new DomainFile[files.size()];
for (int i = 0; i < files.size(); i++) {
domainFiles[i] = (DomainFile) files.get(i);
}
tool.acceptDomainFiles(domainFiles);
}
else if (f.equals(DataTreeDragNDropHandler.localDomainFileTreeFlavor)) {
List<?> files = (List<?>) obj;
DomainFile[] domainFiles = new DomainFile[files.size()];
for (int i = 0; i < files.size(); i++) {
DomainFileNode node = (DomainFileNode) files.get(i);
domainFiles[i] = node.getDomainFile();
}
tool.acceptDomainFiles(domainFiles);
}
else if (f.equals(VersionInfoTransferable.localVersionInfoFlavor)) {
VersionInfo info = (VersionInfo) obj;
Project project = tool.getProject();
ProjectData projectData = project.getProjectData();
DomainFile file = projectData.getFile(info.getDomainFilePath());
DomainObject versionedObj = getVersionedObject(tool, file, info.getVersionNumber());
if (versionedObj != null) {
DomainFile domainFile = versionedObj.getDomainFile();
if (domainFile != null) {
tool.acceptDomainFiles(new DomainFile[] { domainFile });
}
versionedObj.release(this);
}
}
}
private DomainObject getVersionedObject(PluginTool tool, DomainFile file, int versionNumber) {
GetVersionedObjectTask task = new GetVersionedObjectTask(this, file, versionNumber);
tool.execute(task, 250);
return task.getVersionedObject();
}
}

View file

@ -1,47 +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.util;
import ghidra.framework.main.*;
import ghidra.framework.main.datatree.*;
import ghidra.framework.model.*;
import ghidra.framework.plugintool.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
final class LocalVersionInfoFlavorHandler implements
FileOpenDataFlavorHandler {
public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f) {
VersionInfo info = (VersionInfo) obj;
DomainFile file = tool.getProject().getProjectData().getFile(info.getDomainFilePath());
GetVersionedObjectTask task = new GetVersionedObjectTask(this, file,
info.getVersionNumber());
tool.execute(task, 250);
DomainObject versionedObj = task.getVersionedObject();
if (versionedObj != null) {
DomainFile vfile = versionedObj.getDomainFile();
tool.acceptDomainFiles(new DomainFile[] {vfile});
versionedObj.release(this);
}
}
}

View file

@ -1,38 +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.framework.main.datatree;
import ghidra.framework.PluggableServiceRegistry;
public class DataFlavorHandlerService {
static {
PluggableServiceRegistry.registerPluggableService(DataFlavorHandlerService.class, new DataFlavorHandlerService());
}
public static void registerDataFlavorHandlers() {
DataFlavorHandlerService factory = PluggableServiceRegistry.getPluggableService(DataFlavorHandlerService.class);
factory.doRegisterDataFlavorHandlers();
}
protected void doRegisterDataFlavorHandlers() {
final LocalTreeNodeHandler localTreeNodeHandler = new LocalTreeNodeHandler();
DataTreeDragNDropHandler.addActiveDataFlavorHandler(DataTreeDragNDropHandler.localDomainFileTreeFlavor, localTreeNodeHandler);
DataTreeDragNDropHandler.addActiveDataFlavorHandler(VersionInfoTransferable.localVersionInfoFlavor, new LocalVersionInfoHandler());
DataTreeDragNDropHandler.addInactiveDataFlavorHandler(DataTreeDragNDropHandler.localDomainFileTreeFlavor, localTreeNodeHandler);
}
}

View file

@ -16,8 +16,7 @@
package ghidra.framework.main.datatree;
import java.awt.Component;
import java.awt.event.*;
import java.util.List;
import java.awt.event.KeyEvent;
import javax.swing.JTree;
import javax.swing.KeyStroke;
@ -30,20 +29,13 @@ import docking.widgets.tree.support.GTreeRenderer;
import ghidra.framework.main.FrontEndTool;
/**
* Tree that shows the folders and domain files in a Project.
* Tree that shows the folders and domain files in a Project
*/
public class DataTree extends GTree {
static {
DataFlavorHandlerService.registerDataFlavorHandlers();
}
private boolean isActive;
private DataTreeDragNDropHandler dragNDropHandler;
/**
* Constructor
* @param folder root domain folder for the project.
*/
DataTree(FrontEndTool tool, GTreeRootNode root) {
super(root);
@ -53,30 +45,11 @@ public class DataTree extends GTree {
docking.ToolTipManager.sharedInstance().registerComponent(this);
//When the user right clicks, change selection to what the mouse was under
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent evt) {
if (evt.getButton() == MouseEvent.BUTTON3) {
//Find the would-be newly selected path
TreePath newPath = getPathForLocation(evt.getX(), evt.getY());
if (newPath == null) {
return;
}
//Determine if the path is already selected--If so, do not change the selection
TreePath[] paths = getSelectionPaths();
if (paths != null) {
for (TreePath element : paths) {
if (element.equals(newPath)) {
return;
}
}
}
}
}
});
dragNDropHandler = new DataTreeDragNDropHandler(tool, this, isActive);
setDragNDropHandler(dragNDropHandler);
if (tool != null) {
dragNDropHandler = new DataTreeDragNDropHandler(tool, this, isActive);
setDragNDropHandler(dragNDropHandler);
}
initializeKeyEvents();
}
@ -92,74 +65,10 @@ public class DataTree extends GTree {
KeyStroke.getKeyStroke(KeyEvent.VK_X, DockingUtils.CONTROL_KEY_MODIFIER_MASK));
}
void setProjectActive(boolean b) {
dragNDropHandler.setProjectActive(b);
}
/**
* Return true if this path has all of its subpaths expanded.
*/
public boolean allPathsExpanded(TreePath path) {
GTreeNode node = (GTreeNode) path.getLastPathComponent();
if (node.isLeaf()) {
return true;
void setProjectActive(boolean isActive) {
if (dragNDropHandler != null) {
dragNDropHandler.setProjectActive(isActive);
}
if (isCollapsed(path)) {
return false;
}
boolean allLeaves = true;
List<GTreeNode> children = node.getChildren();
for (GTreeNode child : children) {
if (child.isLeaf()) {
continue;
}
allLeaves = false;
if (!isExpanded(child.getTreePath())) {
return false;
}
if (!allPathsExpanded(child.getTreePath())) {
return false;
}
}
if (allLeaves) {
return isExpanded(path);
}
return true;
}
/**
* Return true if this path has all of its subpaths collapsed.
*/
public boolean allPathsCollapsed(TreePath path) {
GTreeNode node = (GTreeNode) path.getLastPathComponent();
if (isExpanded(path)) {
return false;
}
boolean allLeaves = true; // variable for knowing whether all children are leaves
node.getChildren();
for (GTreeNode child : node) {
if (child.isLeaf()) {
continue;
}
allLeaves = false;
if (!isCollapsed(child.getTreePath())) {
return false;
}
if (!allPathsCollapsed(child.getTreePath())) {
return false;
}
}
if (allLeaves) {
return isCollapsed(path);
}
return true;
}
public void clearSelection() {
@ -183,20 +92,7 @@ public class DataTree extends GTree {
getJTree().stopEditing();
}
//////////////////////////////////////////////////////////////////////
// *** private methods
//////////////////////////////////////////////////////////////////////
/**
* Tree cell renderer to use the appropriate icons for the
* DataTreeNodes.
*/
private class DataTreeCellRenderer extends GTreeRenderer {
/**
* Configures the renderer based on the passed in components.
* The icon is set according to value, expanded, and leaf
* parameters.
*/
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel,
boolean expanded, boolean leaf, int row, boolean doesHaveFocus) {
@ -209,7 +105,5 @@ public class DataTree extends GTree {
}
return this;
}
}
}

View file

@ -30,9 +30,7 @@ import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
public class DataTreeDragNDropHandler implements GTreeDragNDropHandler {
private static Map<DataFlavor, DataFlavorHandler> activeProjectDropFlavorHandlerMap =
new HashMap<>();
private static Map<DataFlavor, DataFlavorHandler> inactiveProjectDropFlavorHandlerMap =
private static Map<DataFlavor, DataTreeFlavorHandler> activeProjectDropFlavorHandlerMap =
new HashMap<>();
public static DataFlavor localDomainFileTreeFlavor = createLocalTreeNodeFlavor();
public static DataFlavor localDomainFileFlavor = createLocalTreeFlavor();
@ -79,29 +77,31 @@ public class DataTreeDragNDropHandler implements GTreeDragNDropHandler {
public void drop(GTreeNode destination, Transferable transferable, int dropAction) {
DataFlavor[] transferDataFlavors = transferable.getTransferDataFlavors();
for (DataFlavor dataFlavor : transferDataFlavors) {
DataFlavorHandler flavorHandler = getFlavorHandler(dataFlavor);
DataTreeFlavorHandler flavorHandler = getFlavorHandler(dataFlavor);
if (flavorHandler != null) {
try {
Object transferData = transferable.getTransferData(dataFlavor);
flavorHandler.handle(tool, tree, destination, transferData, dropAction);
}
catch (UnsupportedFlavorException e) {
throw new AssertException(
"Got unsupported flavor from using a supported flavor");
}
catch (IOException e) {
Msg.showError(this, null, "IO Error", "Error during drop", e);
}
handleDrop(destination, transferable, dropAction, dataFlavor, flavorHandler);
return;
}
}
}
private DataFlavorHandler getFlavorHandler(DataFlavor flavor) {
if (isActiveProject) {
return activeProjectDropFlavorHandlerMap.get(flavor);
private void handleDrop(GTreeNode destination, Transferable transferable, int dropAction,
DataFlavor dataFlavor, DataTreeFlavorHandler flavorHandler) {
try {
Object transferData = transferable.getTransferData(dataFlavor);
flavorHandler.handle(tool, tree, destination, transferData, dropAction);
}
return inactiveProjectDropFlavorHandlerMap.get(flavor);
catch (UnsupportedFlavorException e) {
throw new AssertException("Got unsupported flavor from using a supported flavor");
}
catch (IOException e) {
Msg.showError(this, null, "IO Error", "Error during drop", e);
}
}
private DataTreeFlavorHandler getFlavorHandler(DataFlavor flavor) {
return activeProjectDropFlavorHandlerMap.get(flavor);
}
@Override
@ -134,13 +134,6 @@ public class DataTreeDragNDropHandler implements GTreeDragNDropHandler {
@Override
public DataFlavor[] getSupportedDataFlavors(List<GTreeNode> transferNodes) {
return allSupportedFlavors;
// Set<DataFlavor> keySet = null;
// if (isActiveProject) {
// keySet = activeProjectDropFlavorHandlerMap.keySet();
// } else {
// keySet = inactiveProjectDropFlavorHandlerMap.keySet();
// }
// return keySet.toArray(new DataFlavor[keySet.size()]);
}
@Override
@ -196,24 +189,15 @@ public class DataTreeDragNDropHandler implements GTreeDragNDropHandler {
return false;
}
public static void addActiveDataFlavorHandler(DataFlavor flavor, DataFlavorHandler handler) {
public static void addActiveDataFlavorHandler(DataFlavor flavor, DataTreeFlavorHandler handler) {
activeProjectDropFlavorHandlerMap.put(flavor, handler);
}
public static void addInactiveDataFlavorHandler(DataFlavor flavor, DataFlavorHandler handler) {
inactiveProjectDropFlavorHandlerMap.put(flavor, handler);
}
public static DataFlavorHandler removeActiveDataFlavorHandler(DataFlavor flavor) {
public static DataTreeFlavorHandler removeActiveDataFlavorHandler(DataFlavor flavor) {
return activeProjectDropFlavorHandlerMap.remove(flavor);
}
public static DataFlavorHandler removeInctiveDataFlavorHandler(DataFlavor flavor) {
return inactiveProjectDropFlavorHandlerMap.remove(flavor);
}
public void setProjectActive(boolean b) {
isActiveProject = b;
}
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,10 +15,13 @@
*/
package ghidra.framework.main.datatree;
import ghidra.framework.main.FrontEndTool;
import docking.widgets.tree.GTreeNode;
import ghidra.framework.plugintool.PluginTool;
public interface DataFlavorHandler {
public void handle(FrontEndTool tool, DataTree dataTree, GTreeNode destinationNode,
Object transferData, int dropAction);
/**
* Interface for classes that will handle drop actions for {@link DataTree}s.
*/
public interface DataTreeFlavorHandler {
public void handle(PluginTool tool, DataTree dataTree, GTreeNode destinationNode,
Object transferData, int dropAction);
}

View file

@ -15,29 +15,55 @@
*/
package ghidra.framework.main.datatree;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTargetDropEvent;
import java.io.IOException;
import java.util.List;
import javax.swing.SwingUtilities;
import docking.widgets.tree.GTreeNode;
import docking.widgets.tree.GTreeState;
import ghidra.framework.main.FrontEndTool;
import ghidra.app.util.FileOpenDataFlavorHandler;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainFolder;
import ghidra.framework.plugintool.PluginTool;
import ghidra.util.Msg;
import ghidra.util.SystemUtilities;
import ghidra.util.exception.DuplicateFileException;
import ghidra.util.exception.FileInUseException;
import ghidra.util.task.*;
final class LocalTreeNodeHandler implements DataFlavorHandler {
public final class LocalTreeNodeHandler
implements DataTreeFlavorHandler, FileOpenDataFlavorHandler {
private DataTree dataTree;
private GTreeState treeState;
@Override
public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f) {
if (f.equals(DataTreeDragNDropHandler.localDomainFileFlavor)) {
List<?> files = (List<?>) obj;
DomainFile[] domainFiles = new DomainFile[files.size()];
for (int i = 0; i < files.size(); i++) {
domainFiles[i] = (DomainFile) files.get(i);
}
tool.acceptDomainFiles(domainFiles);
}
else if (f.equals(DataTreeDragNDropHandler.localDomainFileTreeFlavor)) {
List<?> files = (List<?>) obj;
DomainFile[] domainFiles = new DomainFile[files.size()];
for (int i = 0; i < files.size(); i++) {
DomainFileNode node = (DomainFileNode) files.get(i);
domainFiles[i] = node.getDomainFile();
}
tool.acceptDomainFiles(domainFiles);
}
}
@Override
@SuppressWarnings("unchecked")
public void handle(FrontEndTool tool, DataTree tree, GTreeNode destinationNode,
public void handle(PluginTool tool, DataTree tree, GTreeNode destinationNode,
Object transferData, int dropAction) {
this.dataTree = tree;
@ -52,12 +78,9 @@ final class LocalTreeNodeHandler implements DataFlavorHandler {
new TaskLauncher(task, dataTree, 1000);
if (treeState != null) { // is set to null if drag results in a task
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
treeState.updateStateForMovedNodes();
dataTree.restoreTreeState(treeState);
}
SystemUtilities.runSwingLater(() -> {
treeState.updateStateForMovedNodes();
dataTree.restoreTreeState(treeState);
});
}
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,42 +13,64 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
*/
package ghidra.framework.main.datatree;
import ghidra.framework.client.*;
import ghidra.framework.main.FrontEndTool;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainFolder;
import ghidra.util.task.TaskLauncher;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DropTargetDropEvent;
import java.io.IOException;
import docking.widgets.tree.GTreeNode;
import ghidra.app.util.FileOpenDataFlavorHandler;
import ghidra.framework.client.*;
import ghidra.framework.main.GetVersionedObjectTask;
import ghidra.framework.model.*;
import ghidra.framework.plugintool.PluginTool;
import ghidra.util.task.TaskLauncher;
final class LocalVersionInfoHandler implements DataFlavorHandler {
public void handle(FrontEndTool tool, DataTree dataTree, GTreeNode destinationNode,
Object transferData, int dropAction) {
DomainFolder folder = getDomainFolder(destinationNode);
VersionInfo info = (VersionInfo) transferData;
RepositoryAdapter rep = tool.getProject().getProjectData().getRepository();
try {
if (rep != null) {
rep.connect();
}
DomainFile file = tool.getProject().getProjectData().getFile(info.getDomainFilePath());
if (file != null) {
new TaskLauncher(new CopyFileVersionTask(file, info.getVersionNumber(), folder), dataTree, 500);
}
}
catch (NotConnectedException exc) {}
catch (IOException exc) {
ClientUtil.handleException(rep, exc, "Repository Connection", tool.getToolFrame());
}
}
public final class LocalVersionInfoHandler
implements DataTreeFlavorHandler, FileOpenDataFlavorHandler {
@Override
public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f) {
VersionInfo info = (VersionInfo) obj;
DomainFile file = tool.getProject().getProjectData().getFile(info.getDomainFilePath());
GetVersionedObjectTask task =
new GetVersionedObjectTask(this, file, info.getVersionNumber());
tool.execute(task, 250);
DomainObject versionedObj = task.getVersionedObject();
if (versionedObj != null) {
DomainFile vfile = versionedObj.getDomainFile();
tool.acceptDomainFiles(new DomainFile[] { vfile });
versionedObj.release(this);
}
}
@Override
public void handle(PluginTool tool, DataTree dataTree, GTreeNode destinationNode,
Object transferData, int dropAction) {
DomainFolder folder = getDomainFolder(destinationNode);
VersionInfo info = (VersionInfo) transferData;
RepositoryAdapter rep = tool.getProject().getProjectData().getRepository();
try {
if (rep != null) {
rep.connect();
}
DomainFile file = tool.getProject().getProjectData().getFile(info.getDomainFilePath());
if (file != null) {
new TaskLauncher(new CopyFileVersionTask(file, info.getVersionNumber(), folder),
dataTree, 500);
}
}
catch (NotConnectedException exc) {
// not sure why we squash this?
}
catch (IOException exc) {
ClientUtil.handleException(rep, exc, "Repository Connection", tool.getToolFrame());
}
}
private DomainFolder getDomainFolder(GTreeNode destinationNode) {
if (destinationNode instanceof DomainFolderNode) {

View file

@ -55,33 +55,26 @@ public class ProjectDataTreePanel extends JPanel {
private ChangeManager changeMgr;
private boolean isActiveProject;
private FrontEndTool tool; // may be null if the panel is inside of the
// these may be null if the panel is inside of a dialog
private FrontEndTool tool;
private FrontEndPlugin plugin;
// data tree dialog
/**
* Construct an empty panel that is going to be used as the active
* panel.
* @param tool front end tool
* Construct an empty panel that is going to be used as the active panel
* @param plugin front end plugin
*/
public ProjectDataTreePanel(FrontEndPlugin plugin) {
this(null, true, plugin, null);
}
/**
* Construct a new DataTreePanel.
* Constructor
*
* @param projectName name of project
* @param projectData object that provides access to all the user data
* folders in a project
* @param isActiveProject true if the project is active, and the
* data tree may be modified
* @param tool front end tool; will be null if the panel is used in a dialog
* @param actionMgr class to handle enablement of actions; an ActionManager
* is passed in when several data tree panels all need to use the
* same ActionManager, e.g., the viewed projects in the front end tool;
* actionMgr will be null if the panel is used in a dialog
* @param plugin front end plugin; will be null if the panel is used in a dialog
* @param filter optional filter that is used to hide programs from view
*/
public ProjectDataTreePanel(String projectName, boolean isActiveProject, FrontEndPlugin plugin,
DomainFileFilter filter) {
@ -211,9 +204,6 @@ public class ProjectDataTreePanel extends JPanel {
}
}
/**
* Set the help location for the data tree.
*/
public void setHelpLocation(HelpLocation helpLocation) {
HelpService help = Help.getHelpService();
help.registerHelp(tree, helpLocation);
@ -228,8 +218,9 @@ public class ProjectDataTreePanel extends JPanel {
}
/**
* Get the number of selected items in the tree.
* These could be either DomainFile's or DomainFolder's.
* Get the number of selected items in the tree. These could be either files or folders.
*
* @return the number of selected items in the tree.
*/
public int getSelectedItemCount() {
return tree.getSelectionCount();
@ -279,47 +270,31 @@ public class ProjectDataTreePanel extends JPanel {
tree.removeGTreeSelectionListener(l);
}
/**
* Add a mouse listener to the data tree.
*/
public void addTreeMouseListener(MouseListener l) {
tree.addMouseListener(l);
}
/**
* Remove the mouse listener from the data tree.
*/
public void removeTreeMouseListener(MouseListener l) {
tree.removeMouseListener(l);
}
/**
* Set the preferred size of the scroll pane that contains the
* data tree.
*/
public void setPreferredTreePanelSize(Dimension d) {
tree.setPreferredSize(d);
}
/**
* Get the project data that this data tree panel is operating on.
*/
public ProjectData getProjectData() {
return projectData;
}
/**
* Notification that the project was renamed; update the root node name
* and reload the node.
* and reload the node
* @param newName the new project name
*/
public void projectRenamed(String newName) {
updateProjectName(newName);
}
/**
* Notification that panel is being disposed.
*
*/
public void dispose() {
if (projectData != null) {
projectData.removeDomainFolderChangeListener(changeMgr);
@ -328,10 +303,12 @@ public class ProjectDataTreePanel extends JPanel {
}
/**
* Get the data tree node that is selected.
* @param e mouse event for the popup; may be null if this is being
* called as a result of the key binding pressed
* @return null if there is no selection
* Get the data tree node that is selected
*
* @param provider the provider with which to construct the new context
* @param e mouse event for the popup; may be null if this is being called as a result of
* the key binding pressed
* @return the new context; null if there is no selection
*/
public ActionContext getActionContext(ComponentProvider provider, MouseEvent e) {
if (root instanceof NoProjectNode) {
@ -364,9 +341,6 @@ public class ProjectDataTreePanel extends JPanel {
domainFolderList, domainFileList, tree, isActiveProject);
}
/**
* get the data tree for this data tree panel.
*/
public DataTree getDataTree() {
return tree;
}
@ -380,17 +354,10 @@ public class ProjectDataTreePanel extends JPanel {
tree.setFilterVisible(enabled);
}
/**
* Return true if this data tree panel is listening to domain folder
* changes.
*/
boolean domainFolderListenerAdded() {
return changeMgr != null;
}
/**
* Get the folder change listener.
*/
DomainFolderChangeListener getFolderChangeListener() {
return changeMgr;
}