From adbbc255420fefb2c5efe7daaf4614f4754fddb7 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Fri, 3 Jan 2020 15:42:21 -0500 Subject: [PATCH] GT-3432 - Fixed recently broken drag-n-drop from the Front End to a running Tool --- ...hidraFileOpenDataFlavorHandlerService.java | 22 +- .../main/datatree/LinuxFileUrlHandler.java | 11 +- .../main/java/docking/dnd/DropTgtAdapter.java | 362 ++++++++---------- .../datatree/DataTreeDragNDropHandler.java | 4 +- 4 files changed, 184 insertions(+), 215 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/GhidraFileOpenDataFlavorHandlerService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/GhidraFileOpenDataFlavorHandlerService.java index 5302137db7..e2f120e910 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/GhidraFileOpenDataFlavorHandlerService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/GhidraFileOpenDataFlavorHandlerService.java @@ -19,18 +19,18 @@ import java.awt.datatransfer.DataFlavor; import ghidra.framework.main.datatree.*; +/** + * A class used to initialize the handling of files that are dropped onto the tool + */ public class GhidraFileOpenDataFlavorHandlerService { public GhidraFileOpenDataFlavorHandlerService() { - try { - DataFlavor linuxFileUrlFlavor = - new DataFlavor("application/x-java-serialized-object;class=java.lang.String"); - FileOpenDropHandler.addDataFlavorHandler(linuxFileUrlFlavor, new LinuxFileUrlHandler()); - } - catch (ClassNotFoundException cnfe) { - // should never happen as it is using java.lang.String - } + // + // Note: the order of the file drop flavors/handlers is intentional. We wish to process + // objects first which we know to be transfered from within the current JVM. After + // that, then process objects given to us from the OS or another JVM. + // LocalTreeNodeHandler localHandler = new LocalTreeNodeHandler(); FileOpenDropHandler.addDataFlavorHandler(DataTreeDragNDropHandler.localDomainFileFlavor, @@ -40,7 +40,13 @@ public class GhidraFileOpenDataFlavorHandlerService { FileOpenDropHandler.addDataFlavorHandler(VersionInfoTransferable.localVersionInfoFlavor, new LocalVersionInfoHandler()); + FileOpenDropHandler.addDataFlavorHandler(DataFlavor.javaFileListFlavor, new JavaFileListHandler()); + + DataFlavor linuxFileUrlFlavor = + new DataFlavor("application/x-java-serialized-object;class=java.lang.String", + "String file URL"); + FileOpenDropHandler.addDataFlavorHandler(linuxFileUrlFlavor, new LinuxFileUrlHandler()); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/LinuxFileUrlHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/LinuxFileUrlHandler.java index 16a7e690ef..336e2219a1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/LinuxFileUrlHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/LinuxFileUrlHandler.java @@ -19,6 +19,7 @@ import java.awt.Component; import java.awt.datatransfer.DataFlavor; import java.awt.dnd.DropTargetDropEvent; import java.io.File; +import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; @@ -84,8 +85,14 @@ public final class LinuxFileUrlHandler implements DataTreeFlavorHandler, FileOpe try { return new File(new URL(s).toURI()); } - catch (Exception ex) { - Msg.error(this, "Unable to open dropped URL: '" + s + "'", ex); + catch (MalformedURLException e) { + // this could be the case that this handler is attempting to process an arbitrary + // String that is not actually a URL + Msg.trace(this, "Not a URL: '" + s + "'", e); + return null; + } + catch (Exception e) { + Msg.error(this, "Unable to open dropped URL: '" + s + "'", e); return null; } }); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/dnd/DropTgtAdapter.java b/Ghidra/Framework/Docking/src/main/java/docking/dnd/DropTgtAdapter.java index 449b4006d0..2a2584f22e 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/dnd/DropTgtAdapter.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/dnd/DropTgtAdapter.java @@ -15,246 +15,202 @@ */ package docking.dnd; -import ghidra.util.Msg; - import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.*; -import java.util.ArrayList; + +import ghidra.util.Msg; /** - * Class to handle notifications of drag and drop operations that occur - * on the DropTarget object. The DropTarget is the component that accepts - * drops during a drag and drop operation. The drop - * method actually transfers the data. + * Class to handle notifications of drag and drop operations that occur on the DropTarget + * object. The DropTarget is the component that accepts drops during a drag and drop operation. + * The drop method actually transfers the data. */ public class DropTgtAdapter implements DropTargetListener { - private Droppable dropComponent; - private int dropActions; // actions that the drop target - // can accept - private DataFlavor []dropFlavors; //drop flavors that the - // drop target can accept + private Droppable dropComponent; + private int dropActions; // actions that the drop target can accept + private DataFlavor[] dropFlavors; //drop flavors that the drop target can accept - /** - * Constructor - * @param dropComponent the drop target - * @param acceptableDropActions a DnDConstants variable that defines - * dnd actions - * @param acceptableDropFlavors acceptable data formats that the drop - * target can handle - */ - public DropTgtAdapter(Droppable dropComponent, - int acceptableDropActions, DataFlavor []acceptableDropFlavors) { + /** + * Constructor + * + * @param dropComponent the drop target + * @param acceptableDropActions a DnDConstants variable that defines dnd actions + * @param acceptableDropFlavors acceptable data formats that the drop target can handle + */ + public DropTgtAdapter(Droppable dropComponent, + int acceptableDropActions, DataFlavor[] acceptableDropFlavors) { - this.dropComponent = dropComponent; - dropActions = acceptableDropActions; - dropFlavors = acceptableDropFlavors; - } - /** - * Set the data flavors acceptable to the associated drop target. - * @param dropFlavors - */ - public void setAcceptableDropFlavors(DataFlavor []dropFlavors) { - this.dropFlavors = dropFlavors; - } - /** - * DropTargetListener method called when the drag operation encounters - * the drop target. - * @param e event that has current state of drag and drop operation - */ - public void dragEnter(DropTargetDragEvent e) { + this.dropComponent = dropComponent; + dropActions = acceptableDropActions; + dropFlavors = acceptableDropFlavors; + } - if (isDropOk(e)) { - e.acceptDrag(e.getDropAction()); - } - else { - dropComponent.dragUnderFeedback(false,e); - e.rejectDrag(); - } - } - /** - * DropTargetListener method called when the drag operation is over - * the drop target. - * @param e event that has current state of drag and drop operation - */ - public void dragOver(DropTargetDragEvent e) { + /** + * Set the data flavors acceptable to the associated drop target + * @param dropFlavors the flavors + */ + public void setAcceptableDropFlavors(DataFlavor[] dropFlavors) { + this.dropFlavors = dropFlavors; + } - if (isDropOk(e)) { - dropComponent.dragUnderFeedback(true, e); - e.acceptDrag(e.getDropAction()); - } - else { - dropComponent.dragUnderFeedback(false,e); - e.rejectDrag(); - } - } - /** - * DropTargetListener method called when the - * drag operation exits the drop target without dropping. However, - * this method is also called even when the drop completes. - * @param e event that has current state of drag and drop operation - */ - public void dragExit(DropTargetEvent e) { - dropComponent.undoDragUnderFeedback(); - // Note: at this point, there is no way to tell whether the - // drop actually occurred; so, there is no notification - // for a "drop canceled" + @Override + public void dragEnter(DropTargetDragEvent e) { - } - /** - * DropTargetListener method called when the user modifies the - * drag action. - * @param e event that has current state of drag and drop operation - */ - public void dropActionChanged(DropTargetDragEvent e){ - dragOver(e); - } - /** - * DropTargetListener method called when the drag operation terminates and - * drops onto the drop target. - * @param e event that has current state of drag and drop operation - */ - public void drop(DropTargetDropEvent e) { + if (isDropOk(e)) { + e.acceptDrag(e.getDropAction()); + } + else { + dropComponent.dragUnderFeedback(false, e); + e.rejectDrag(); + } + } - // only handle local transfers (within same JVM) for now... -// if (!e.isLocalTransfer()) { -// e.rejectDrop(); -// dropComponent.undoDragUnderFeedback(); -// return; -// } + @Override + public void dragOver(DropTargetDragEvent e) { - Transferable t = e.getTransferable(); - int flavorIndex=-1; - for (int i=0; i + *
  • the drop target accepts one of the data flavors that the event's transferable provides + *
  • + *
  • the drop action (i.e. COPY, MOVE, etc.) is accepted by the target + *
  • + *
  • the drop is accepted by the Droppable component + *
  • + * + * + * @param e event that has current state of drag and drop operation + * @return true if the drop operation is OK + */ + protected boolean isDropOk(DropTargetDragEvent e) { - /** - * Returns true if the drop operation is OK. A drop is deemed to be okay if - *
    1. the drop target accepts one of the data flavors that the event's transferrable provides. - *
    2. the drop action (i.e. COPY, MOVE, etc.) is accepted by the target. - *
    3. the drop is accepted by the Droppable component. - * @param e event that has current state of drag and drop operation - */ - protected boolean isDropOk(DropTargetDragEvent e) { // Does this target accept the drop action type being dropped on it? - int da = e.getDropAction(); - if ((da & dropActions) == 0) { - return false; - } - // Does the event's transferable have a flavor that this drop target accepts? + int da = e.getDropAction(); + if ((da & dropActions) == 0) { + return false; + } + // Does the event's transferable have a flavor that this drop target accepts? if (!isDragFlavorSupported(e)) { - return false; - } + return false; + } // Does the target component allow the drop. - if (!dropComponent.isDropOk(e)) { - return false; - } - return true; - } - /** - * Returns true if the drop target can accept the data - * flavor that is to be dropped. - */ - protected boolean isDragFlavorSupported(DropTargetDragEvent e) { - if (dropFlavors == null) { - return false; // This drop target doesn't accept any flavors. - } - // Check each flavor to see that this accepts at least one flavor the event can drop. - for (int i=0; i list = new ArrayList(); - DataFlavor[] transferFlavors = e.getCurrentDataFlavors(); - for (DataFlavor acceptableFlavor : acceptableFlavors) { - for (DataFlavor transferFlavor : transferFlavors) { - if (acceptableFlavor.equals(transferFlavor)) { - list.add(transferFlavor); - break; - } } } - return list.toArray(new DataFlavor[list.size()]); + return null; } - } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeDragNDropHandler.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeDragNDropHandler.java index 97cb1ee644..62d110be35 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeDragNDropHandler.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeDragNDropHandler.java @@ -33,8 +33,8 @@ public class DataTreeDragNDropHandler implements GTreeDragNDropHandler { private static Map activeProjectDropFlavorHandlerMap = new HashMap<>(); public static DataFlavor localDomainFileTreeFlavor = createLocalTreeNodeFlavor(); - public static DataFlavor localDomainFileFlavor = createLocalTreeFlavor(); + public static DataFlavor localDomainFileFlavor = createLocalTreeFlavor(); public static DataFlavor[] allSupportedFlavors = { localDomainFileTreeFlavor, localDomainFileFlavor, DataFlavor.stringFlavor }; @@ -152,7 +152,7 @@ public class DataTreeDragNDropHandler implements GTreeDragNDropHandler { .map(node -> ((DomainFileNode) node).getDomainFile()) .collect(Collectors.toList()); } - else if (flavor == DataFlavor.stringFlavor) { + else if (flavor.equals(DataFlavor.stringFlavor)) { // allow users to copy the names of nodes return transferNodes.stream() .map(node -> node.getName())