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())