Merge remote-tracking branch 'origin/dragonmacher-GT-2705-9.0' into Ghidra_9.0.2

This commit is contained in:
ghidravore 2019-04-03 12:00:05 -04:00
commit b82a0115a1
37 changed files with 441 additions and 694 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,21 +15,29 @@
*/
package foundation;
import ghidra.app.factory.*;
import ghidra.app.util.*;
import ghidra.framework.*;
import ghidra.framework.data.*;
import ghidra.framework.main.datatree.*;
import ghidra.app.factory.GhidraToolStateFactory;
import ghidra.app.util.GhidraFileOpenDataFlavorHandlerService;
import ghidra.framework.ModuleInitializer;
import ghidra.framework.PluggableServiceRegistry;
import ghidra.framework.data.ToolStateFactory;
import ghidra.framework.main.datatree.GhidraDataFlavorHandlerService;
import ghidra.program.database.*;
public class FoundationInitializer implements ModuleInitializer {
public void run() {
PluggableServiceRegistry.registerPluggableService( ToolStateFactory.class, new GhidraToolStateFactory() );
PluggableServiceRegistry.registerPluggableService( DataFlavorHandlerService.class, new GhidraDataFlavorHandlerService() );
PluggableServiceRegistry.registerPluggableService( FileOpenDataFlavorHandlerService.class, new GhidraFileOpenDataFlavorHandlerService() );
PluggableServiceRegistry.registerPluggableService( DataTypeArchiveMergeManagerFactory.class, new GhidraDataTypeArchiveMergeManagerFactory() );
PluggableServiceRegistry.registerPluggableService( ProgramMultiUserMergeManagerFactory.class, new GhidraProgramMultiUserMergeManagerFactory() );
}
@Override
public void run() {
PluggableServiceRegistry.registerPluggableService(ToolStateFactory.class,
new GhidraToolStateFactory());
PluggableServiceRegistry.registerPluggableService(GhidraDataFlavorHandlerService.class,
new GhidraDataFlavorHandlerService());
PluggableServiceRegistry.registerPluggableService(
GhidraFileOpenDataFlavorHandlerService.class,
new GhidraFileOpenDataFlavorHandlerService());
PluggableServiceRegistry.registerPluggableService(DataTypeArchiveMergeManagerFactory.class,
new GhidraDataTypeArchiveMergeManagerFactory());
PluggableServiceRegistry.registerPluggableService(ProgramMultiUserMergeManagerFactory.class,
new GhidraProgramMultiUserMergeManagerFactory());
}
@Override
public String getName() {

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,6 +15,12 @@
*/
package ghidra.app.plugin.core.datamgr;
import java.util.ArrayList;
import java.util.List;
import javax.swing.tree.TreePath;
import docking.widgets.tree.GTreeNode;
import ghidra.app.context.ProgramActionContext;
import ghidra.app.plugin.core.datamgr.archive.ProjectArchive;
import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
@ -24,13 +29,6 @@ import ghidra.framework.main.datatable.DomainFileProvider;
import ghidra.framework.model.DomainFile;
import ghidra.program.model.listing.Program;
import java.util.ArrayList;
import java.util.List;
import javax.swing.tree.TreePath;
import docking.widgets.tree.GTreeNode;
public class DataTypesActionContext extends ProgramActionContext implements DomainFileProvider {
private final GTreeNode clickedNode;
private final boolean isToolbarAction;

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,14 +15,13 @@
*/
package ghidra.app.util;
import ghidra.framework.main.datatree.*;
import java.awt.datatransfer.DataFlavor;
public class GhidraFileOpenDataFlavorHandlerService extends FileOpenDataFlavorHandlerService {
import ghidra.framework.main.datatree.*;
@Override
protected void doRegisterDataFlavorHandlers() {
public class GhidraFileOpenDataFlavorHandlerService {
public GhidraFileOpenDataFlavorHandlerService() {
try {
DataFlavor linuxFileUrlFlavor =
@ -34,15 +32,15 @@ public class GhidraFileOpenDataFlavorHandlerService extends FileOpenDataFlavorHa
// should never happen as it is using java.lang.String
}
LocalTreeNodeFlavorHandler localHandler = new LocalTreeNodeFlavorHandler();
LocalTreeNodeHandler localHandler = new LocalTreeNodeHandler();
FileOpenDropHandler.addDataFlavorHandler(DataTreeDragNDropHandler.localDomainFileFlavor,
localHandler);
FileOpenDropHandler.addDataFlavorHandler(VersionInfoTransferable.localVersionInfoFlavor,
FileOpenDropHandler.addDataFlavorHandler(DataTreeDragNDropHandler.localDomainFileTreeFlavor,
localHandler);
FileOpenDropHandler.addDataFlavorHandler(DataFlavor.javaFileListFlavor,
new JavaFileListFlavorHandler());
FileOpenDropHandler.addDataFlavorHandler(
DataTreeDragNDropHandler.localDomainFileTreeFlavor, localHandler);
FileOpenDropHandler.addDataFlavorHandler(VersionInfoTransferable.localVersionInfoFlavor,
new LocalVersionInfoHandler());
FileOpenDropHandler.addDataFlavorHandler(DataFlavor.javaFileListFlavor,
new JavaFileListHandler());
}
}

View File

@ -1,48 +0,0 @@
/* ###
* 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.util;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DropTargetDropEvent;
import java.io.File;
import java.util.List;
import ghidra.app.services.FileImporterService;
import ghidra.framework.model.DomainFolder;
import ghidra.framework.plugintool.PluginTool;
import util.CollectionUtils;
final class JavaFileListFlavorHandler implements FileOpenDataFlavorHandler {
@Override
public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f) {
List<File> files = CollectionUtils.asList((List<?>) obj, File.class);
FileImporterService im = tool.getService(FileImporterService.class);
if (im == null) {
tool.setStatusInfo("ERROR: Could not get importer service.");
return;
}
DomainFolder rootFolder = tool.getProject().getProjectData().getRootFolder();
if (files.size() == 1 && files.get(0).isFile()) {
im.importFile(rootFolder, files.get(0));
}
else {
im.importFiles(rootFolder, files);
}
}
}

View File

@ -26,6 +26,7 @@ import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import docking.*;
import docking.event.mouse.GMouseListenerAdapter;
import docking.widgets.tree.support.GTreeSelectionEvent;
import docking.widgets.tree.support.GTreeSelectionListener;
import ghidra.framework.main.datatree.ClearCutAction;
@ -40,7 +41,7 @@ import ghidra.util.layout.PairLayout;
* Dialog to open or save domain data items to a new location or name.
*/
public class DataTreeDialog extends DialogComponentProvider
implements GTreeSelectionListener, ActionListener {
implements GTreeSelectionListener, ActionListener {
/**
* Dialog type for opening domain data files.
@ -540,10 +541,11 @@ implements GTreeSelectionListener, ActionListener {
protected void addTreeListeners() {
if (type == OPEN) {
treePanel.addTreeMouseListener(new MouseAdapter() {
treePanel.addTreeMouseListener(new GMouseListenerAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (e.getClickCount() == 2 && okButton.isEnabled()) {
public void doubleClickTriggered(MouseEvent e) {
if (okButton.isEnabled()) {
okCallback();
}
}
@ -671,7 +673,7 @@ implements GTreeSelectionListener, ActionListener {
// populate the combo box
DefaultComboBoxModel<String> model =
(DefaultComboBoxModel<String>) projectComboBox.getModel();
(DefaultComboBoxModel<String>) projectComboBox.getModel();
model.removeAllElements();
Set<String> map = new HashSet<>();

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.
@ -18,9 +17,10 @@ package ghidra.framework.main.datatree;
import java.awt.datatransfer.DataFlavor;
public class GhidraDataFlavorHandlerService extends DataFlavorHandlerService {
@Override
protected void doRegisterDataFlavorHandlers() {
public class GhidraDataFlavorHandlerService {
public GhidraDataFlavorHandlerService() {
try {
DataFlavor linuxFileUrlFlavor =
new DataFlavor("application/x-java-serialized-object;class=java.lang.String");
@ -31,15 +31,12 @@ public class GhidraDataFlavorHandlerService extends DataFlavorHandlerService {
// should never happen as it is using java.lang.String
}
final LocalTreeNodeHandler localTreeNodeHandler = new LocalTreeNodeHandler();
LocalTreeNodeHandler localNodeHandler = new LocalTreeNodeHandler();
DataTreeDragNDropHandler.addActiveDataFlavorHandler(
DataTreeDragNDropHandler.localDomainFileTreeFlavor, localTreeNodeHandler);
DataTreeDragNDropHandler.localDomainFileTreeFlavor, localNodeHandler);
DataTreeDragNDropHandler.addActiveDataFlavorHandler(DataFlavor.javaFileListFlavor,
new JavaFileListHandler());
DataTreeDragNDropHandler.addActiveDataFlavorHandler(
VersionInfoTransferable.localVersionInfoFlavor, new LocalVersionInfoHandler());
DataTreeDragNDropHandler.addInactiveDataFlavorHandler(
DataTreeDragNDropHandler.localDomainFileTreeFlavor, localTreeNodeHandler);
}
}

View File

@ -19,13 +19,15 @@
package ghidra.framework.main.datatree;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DropTargetDropEvent;
import java.io.File;
import java.util.List;
import docking.widgets.tree.GTreeNode;
import ghidra.app.services.FileImporterService;
import ghidra.framework.main.FrontEndTool;
import ghidra.app.util.FileOpenDataFlavorHandler;
import ghidra.framework.model.DomainFolder;
import ghidra.framework.plugintool.PluginTool;
import ghidra.util.Msg;
import util.CollectionUtils;
@ -33,24 +35,43 @@ import util.CollectionUtils;
* A drag-and-drop handler for trees that is specific to List&ltFile&gt. (see
* {@link DataFlavor#javaFileListFlavor}).
*/
final class JavaFileListHandler implements DataFlavorHandler {
@Override
public void handle(FrontEndTool tool, DataTree dataTree, GTreeNode destinationNode,
Object transferData, int dropAction) {
DomainFolder folder = getDomainFolder(destinationNode);
public final class JavaFileListHandler implements DataTreeFlavorHandler, FileOpenDataFlavorHandler {
FileImporterService im = tool.getService(FileImporterService.class);
if (im == null) {
Msg.showError(this, dataTree, "Could Not Import", "Could not find importer service");
@Override
public void handle(PluginTool tool, Object transferData, DropTargetDropEvent e, DataFlavor f) {
FileImporterService importer = tool.getService(FileImporterService.class);
if (importer == null) {
Msg.showError(this, null, "Could Not Import", "Could not find Importer Service");
return;
}
List<File> fileList = CollectionUtils.asList((List<?>) transferData, File.class);
DomainFolder folder = tool.getProject().getProjectData().getRootFolder();
doImport(importer, folder, transferData);
}
@Override
public void handle(PluginTool tool, DataTree dataTree, GTreeNode destinationNode,
Object transferData, int dropAction) {
FileImporterService importer = tool.getService(FileImporterService.class);
if (importer == null) {
Msg.showError(this, dataTree, "Could Not Import", "Could not find Importer Service");
return;
}
DomainFolder folder = getDomainFolder(destinationNode);
doImport(importer, folder, transferData);
}
private void doImport(FileImporterService importer, DomainFolder folder, Object files) {
List<File> fileList = CollectionUtils.asList((List<?>) files, File.class);
if (fileList.size() == 1 && fileList.get(0).isFile()) {
im.importFile(folder, fileList.get(0));
importer.importFile(folder, fileList.get(0));
}
else {
im.importFiles(folder, fileList);
importer.importFiles(folder, fileList);
}
}

View File

@ -27,7 +27,6 @@ import java.util.function.Function;
import docking.widgets.tree.GTreeNode;
import ghidra.app.services.FileImporterService;
import ghidra.app.util.FileOpenDataFlavorHandler;
import ghidra.framework.main.FrontEndTool;
import ghidra.framework.model.DomainFolder;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.ServiceProvider;
@ -38,11 +37,11 @@ import ghidra.util.Msg;
* duty in that it opens files for DataTrees and for Tools (signaled via the interfaces it
* implements).
*/
public final class LinuxFileUrlHandler implements DataFlavorHandler, FileOpenDataFlavorHandler {
public final class LinuxFileUrlHandler implements DataTreeFlavorHandler, FileOpenDataFlavorHandler {
@Override
// This is for the DataFlavorHandler interface for handling node drops in DataTrees
public void handle(FrontEndTool tool, DataTree dataTree, GTreeNode destinationNode,
public void handle(PluginTool tool, DataTree dataTree, GTreeNode destinationNode,
Object transferData, int dropAction) {
DomainFolder folder = getDomainFolder(destinationNode);

View File

@ -47,7 +47,12 @@ public class ActionContext {
}
/**
* For Testing
* Constructor
*
* @param provider the ComponentProvider that generated this context.
* @param contextObject an optional contextObject that the ComponentProvider can provide
* @param sourceObject an optional source object; this can be anything that actions wish to
* later retrieve
*/
public ActionContext(ComponentProvider provider, Object contextObject, Object sourceObject) {
this(provider, contextObject);
@ -55,8 +60,8 @@ public class ActionContext {
}
/**
* Returns the {@link #ComponentProvider} that generated this ActionContext
* @return
* Returns the {@link ComponentProvider} that generated this ActionContext
* @return the provider
*/
public ComponentProvider getComponentProvider() {
return provider;

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.
@ -19,69 +18,75 @@ package docking.widgets.tree.support;
import java.awt.datatransfer.*;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import docking.widgets.tree.GTreeNode;
/**
* A transferable for sharing data via drag/drop and clipboard operations for GTrees.
* A transferable for sharing data via drag/drop and clipboard operations for GTrees
*/
public class GTreeNodeTransferable implements Transferable {
private final List<GTreeNode> selectedData;
private final GTreeTransferHandler transferHandler;
private final List<GTreeNode> selectedData;
private final GTreeTransferHandler transferHandler;
/**
* Creates this transferable based upon the selected data and uses the given transfer
* handler to perform {@link Transferable} operations.
* @param handler the handler used to perform transfer operations.
* @param selectedData The
*/
public GTreeNodeTransferable( GTreeTransferHandler handler, List<GTreeNode> selectedData) {
this.selectedData = selectedData;
this.transferHandler = handler;
}
/**
* Returns all of the original selected data contained by this transferable.
* @return all of the original selected data contained by this transferable
*/
public List<GTreeNode> getAllData() {
return selectedData;
}
/**
* Gets the transfer data from the selection based upon the given flavor.
* @param transferNodes The nodes from which to get the data.
* @param flavor The flavor of data to retreive from the given selection.
* @return the transfer data from the selection based upon the given flavor.
* @throws UnsupportedFlavorException if the given flavor is not one of the supported flavors
* returned by {@link #getSupportedDataFlavors(List)}.
*/
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return transferHandler.getTransferData(selectedData, flavor);
}
/**
* Returns the DataFlavors for the types of data that this transferable supports, based upon
* the given selection.
* @param transferNodes The nodes to base the DataFlavor selection upon.
* @return the DataFlavors for the types of data that this transferable supports, based upon
* the given selection.
/**
* Creates this transferable based upon the selected data and uses the given transfer
* handler to perform {@link Transferable} operations
*
* @param handler the handler used to perform transfer operations
* @param selectedData The selected tree nodes
*/
public DataFlavor[] getTransferDataFlavors() {
return transferHandler.getSupportedDataFlavors(selectedData);
}
public GTreeNodeTransferable(GTreeTransferHandler handler, List<GTreeNode> selectedData) {
this.transferHandler = Objects.requireNonNull(handler);
this.selectedData = Objects.requireNonNull(selectedData);
}
/**
* A convenience method to determine if this transferable supports the given flavor.
* @return true if this transferable supports the given flavor.
*/
public boolean isDataFlavorSupported(DataFlavor flavor) {
DataFlavor[] flavors = transferHandler.getSupportedDataFlavors(selectedData);
for(int i=0;i<flavors.length;i++) {
if (flavors[i].equals(flavor)) {
return true;
}
}
return false;
}
/**
* Returns all of the original selected data contained by this transferable.
* @return all of the original selected data contained by this transferable
*/
public List<GTreeNode> getAllData() {
return selectedData;
}
/**
* Gets the transfer data from the selection based upon the given flavor
* @param flavor The flavor of data to retrieve from the given selection.
* @return the transfer data from the selection based upon the given flavor.
* @throws UnsupportedFlavorException if the given flavor is not one of the supported flavors
* returned by {@link #getTransferDataFlavors()}
*/
@Override
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException, IOException {
return transferHandler.getTransferData(selectedData, flavor);
}
/**
* Returns the DataFlavors for the types of data that this transferable supports, based upon
* the given selection
*
* @return the DataFlavors for the types of data that this transferable supports, based upon
* the given selection
*/
@Override
public DataFlavor[] getTransferDataFlavors() {
return transferHandler.getSupportedDataFlavors(selectedData);
}
/**
* A convenience method to determine if this transferable supports the given flavor
* @return true if this transferable supports the given flavor
*/
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
DataFlavor[] flavors = transferHandler.getSupportedDataFlavors(selectedData);
for (DataFlavor f : flavors) {
if (f.equals(flavor)) {
return true;
}
}
return false;
}
}

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

@ -30,6 +30,7 @@ public class ProjectDataActionContext extends ActionContext implements DomainFil
private Component comp;
private boolean isActiveProject;
private ProjectData projectData;
private boolean isTransient;
public ProjectDataActionContext(ComponentProvider provider, ProjectData projectData,
Object contextObject, List<DomainFolder> selectedFolders,
@ -112,4 +113,20 @@ public class ProjectDataActionContext extends ActionContext implements DomainFil
}
return false;
}
/**
* Transient data is that which will appear in a temporary project dialog
* @param isTransient true if transient
*/
public void setTransient(boolean isTransient) {
this.isTransient = isTransient;
}
/**
* Transient data is that which will appear in a temporary project dialog
* @return true if transient
*/
public boolean isTransient() {
return isTransient;
}
}

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.
@ -26,20 +25,42 @@ public abstract class ProjectDataContextAction extends DockingAction {
}
@Override
public final boolean isEnabledForContext(ActionContext actionContext) {
public boolean isEnabledForContext(ActionContext actionContext) {
if (!(actionContext instanceof ProjectDataActionContext)) {
return false;
}
ProjectDataActionContext context = (ProjectDataActionContext) actionContext;
if (ignoreTransientProject(context)) {
return false;
}
return isEnabledForContext(context);
}
protected boolean ignoreTransientProject(ProjectDataActionContext context) {
if (supportsTransientProjectData()) {
return false;
}
return context.isTransient();
}
/**
* Signals that this action can work on normal project data, as well as transient data.
* Transient data is that which will appear in a temporary project dialog.
*
* @return true if this action works on transient project data
*/
protected boolean supportsTransientProjectData() {
return false;
}
protected boolean isEnabledForContext(ProjectDataActionContext context) {
return context.hasOneOrMoreFilesAndFolders();
}
@Override
public final void actionPerformed(ActionContext context) {
public void actionPerformed(ActionContext context) {
actionPerformed((ProjectDataActionContext) context);
}
@ -59,7 +80,7 @@ public abstract class ProjectDataContextAction extends DockingAction {
@Override
public boolean isAddToPopup(ActionContext context) {
if (!(context instanceof ProjectDataActionContext)) {
if (!isEnabledForContext(context)) {
return false;
}
return isAddToPopup((ProjectDataActionContext) context);

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.
@ -30,10 +29,32 @@ public abstract class ProjectDataContextToggleAction extends ToggleDockingAction
if (!(actionContext instanceof ProjectDataActionContext)) {
return false;
}
ProjectDataActionContext context = (ProjectDataActionContext) actionContext;
if (ignoreTransientProject(context)) {
return false;
}
return isEnabledForContext(context);
}
protected boolean ignoreTransientProject(ProjectDataActionContext context) {
if (supportsTransientProjectData()) {
return false;
}
return context.isTransient();
}
/**
* Signals that this action can work on normal project data, as well as transient data.
* Transient data is that which will appear in a temporary project dialog.
*
* @return true if this action works on transient project data
*/
protected boolean supportsTransientProjectData() {
return false;
}
protected boolean isEnabledForContext(ProjectDataActionContext context) {
return context.hasOneOrMoreFilesAndFolders();
}

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,9 @@
*/
package ghidra.framework.main.datatable;
import ghidra.framework.main.datatree.ProjectDataTreeActionContext;
import docking.ActionContext;
import docking.action.DockingAction;
import ghidra.framework.main.datatree.ProjectDataTreeActionContext;
public abstract class ProjectDataTreeContextAction extends DockingAction {
@ -31,10 +30,32 @@ public abstract class ProjectDataTreeContextAction extends DockingAction {
if (!(actionContext instanceof ProjectDataTreeActionContext)) {
return false;
}
ProjectDataTreeActionContext context = (ProjectDataTreeActionContext) actionContext;
if (ignoreTransientProject(context)) {
return false;
}
return isEnabledForContext(context);
}
protected boolean ignoreTransientProject(ProjectDataActionContext context) {
if (supportsTransientProjectData()) {
return false;
}
return context.isTransient();
}
/**
* Signals that this action can work on normal project data, as well as transient data.
* Transient data is that which will appear in a temporary project dialog.
*
* @return true if this action works on transient project data
*/
protected boolean supportsTransientProjectData() {
return false;
}
protected boolean isEnabledForContext(ProjectDataTreeActionContext context) {
return context.hasOneOrMoreFilesAndFolders();
}
@ -60,7 +81,7 @@ public abstract class ProjectDataTreeContextAction extends DockingAction {
@Override
public boolean isAddToPopup(ActionContext context) {
if (!(context instanceof ProjectDataTreeActionContext)) {
if (!isEnabledForContext(context)) {
return false;
}
return isAddToPopup((ProjectDataTreeActionContext) context);

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

@ -23,6 +23,7 @@ import javax.swing.tree.TreePath;
import docking.dnd.GClipboard;
import docking.widgets.tree.GTreeNode;
import docking.widgets.tree.support.GTreeNodeTransferable;
import ghidra.util.Msg;
/**
@ -35,14 +36,8 @@ public class DataTreeClipboardUtils {
* Static instance of a callback handler that is notified when the clipboard is changed
* and our data is discarded.
*/
private static final ClipboardOwner DATATREE_CLIPBOARD_OWNER = new ClipboardOwner() {
@Override
public void lostOwnership(Clipboard clipboard, Transferable contents) {
// This is called when something other than this class modifies the clipboard
// and our data is discarded.
clearCuttables(contents);
}
};
private static final ClipboardOwner DATATREE_CLIPBOARD_OWNER =
(clipboard, contents) -> clearCuttables(contents);
/**
* Pushes the GTreeNodes in the specified TreePath array to the clipboard.
@ -59,8 +54,9 @@ public class DataTreeClipboardUtils {
GTreeNode node = (GTreeNode) element.getLastPathComponent();
list.add(node);
}
DataTreeNodeTransferable contents =
new DataTreeNodeTransferable(tree.getDragNDropHandler(), list);
GTreeNodeTransferable contents =
new GTreeNodeTransferable(tree.getDragNDropHandler(), list);
try {
clipboard.setContents(contents, DATATREE_CLIPBOARD_OWNER);

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

@ -1,30 +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 java.util.List;
import docking.widgets.tree.GTreeNode;
import docking.widgets.tree.support.GTreeNodeTransferable;
import docking.widgets.tree.support.GTreeTransferHandler;
public class DataTreeNodeTransferable extends GTreeNodeTransferable {
public DataTreeNodeTransferable(GTreeTransferHandler handler, List<GTreeNode> selectedData) {
super(handler, selectedData);
}
}

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);
public final class LocalVersionInfoHandler
implements DataTreeFlavorHandler, FileOpenDataFlavorHandler {
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());
}
}
@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

@ -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,14 +15,13 @@
*/
package ghidra.framework.main.datatree;
import ghidra.framework.main.datatable.ProjectDataActionContext;
import ghidra.framework.model.*;
import java.util.List;
import javax.swing.tree.TreePath;
import docking.ComponentProvider;
import ghidra.framework.main.datatable.ProjectDataActionContext;
import ghidra.framework.model.*;
public class ProjectDataTreeActionContext extends ProjectDataActionContext {
@ -52,7 +50,7 @@ public class ProjectDataTreeActionContext extends ProjectDataActionContext {
return selectionPaths;
}
public DataTree getDataTree() {
public DataTree getTree() {
return tree;
}
}

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) {
@ -360,13 +337,13 @@ public class ProjectDataTreePanel extends JPanel {
}
}
return new ProjectDataTreeActionContext(provider, projectData, selectionPaths,
domainFolderList, domainFileList, tree, isActiveProject);
ProjectDataTreeActionContext context = new ProjectDataTreeActionContext(provider,
projectData, selectionPaths, domainFolderList, domainFileList, tree, isActiveProject);
boolean isTransient = tool == null; // null for stand-alone dialog, not the project's tree
context.setTransient(isTransient);
return context;
}
/**
* get the data tree for this data tree panel.
*/
public DataTree getDataTree() {
return tree;
}
@ -380,17 +357,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;
}

View File

@ -33,7 +33,7 @@ public class ProjectDataCollapseAction extends ProjectDataTreeContextAction {
@Override
protected void actionPerformed(ProjectDataTreeActionContext context) {
DataTree tree = context.getDataTree();
DataTree tree = context.getTree();
TreePath[] paths = context.getSelectionPaths();
collapse(tree, paths[0]);
}

View File

@ -40,7 +40,7 @@ public class ProjectDataCopyAction extends ProjectDataCopyCutBaseAction {
protected void actionPerformed(ProjectDataTreeActionContext context) {
TreePath[] paths = adjustSelectionPaths(context.getSelectionPaths());
DataTreeClipboardUtils.setClipboardContents(context.getDataTree(), paths);
DataTreeClipboardUtils.setClipboardContents(context.getTree(), paths);
}

View File

@ -40,7 +40,7 @@ public class ProjectDataCutAction extends ProjectDataCopyCutBaseAction {
protected void actionPerformed(ProjectDataTreeActionContext context) {
TreePath[] paths = adjustSelectionPaths(context.getSelectionPaths());
DataTreeClipboardUtils.setClipboardContents(context.getDataTree(), paths);
DataTreeClipboardUtils.setClipboardContents(context.getTree(), paths);
markNodesCut(paths);
}

View File

@ -33,7 +33,7 @@ public class ProjectDataExpandAction extends ProjectDataTreeContextAction {
@Override
protected void actionPerformed(ProjectDataTreeActionContext context) {
DataTree tree = context.getDataTree();
DataTree tree = context.getTree();
TreePath[] paths = context.getSelectionPaths();
expand(tree, paths[0]);
}

View File

@ -41,6 +41,12 @@ public class ProjectDataNewFolderAction extends ProjectDataContextAction {
markHelpUnnecessary();
}
@Override
protected boolean supportsTransientProjectData() {
// we allow the user to create new folders even in transient projects
return true;
}
@Override
protected void actionPerformed(ProjectDataActionContext context) {
createNewFolder(context);

View File

@ -44,7 +44,7 @@ public class ProjectDataPasteAction extends ProjectDataCopyCutBaseAction {
GTreeNode node = (GTreeNode) context.getContextObject();
DomainFolderNode destNode = getFolderForNode(node);
paste(context.getDataTree(), destNode);
paste(context.getTree(), destNode);
}
@Override

View File

@ -50,6 +50,10 @@ public class ProjectDataReadOnlyAction extends ProjectDataContextToggleAction {
if (context.getFolderCount() != 0 || context.getFileCount() != 1) {
return false;
}
if (ignoreTransientProject(context)) {
return false;
}
DomainFile domainFile = context.getSelectedFiles().get(0);
setSelected(domainFile.isReadOnly());
return true;

View File

@ -36,7 +36,7 @@ public class ProjectDataSelectAction extends ProjectDataTreeContextAction {
@Override
protected void actionPerformed(ProjectDataTreeActionContext context) {
DataTree tree = context.getDataTree();
DataTree tree = context.getTree();
TreePath[] paths = context.getSelectionPaths();
GTreeNode node = (GTreeNode) paths[0].getLastPathComponent();
selectAllChildren(tree, node);