From 8734960b1b57a034ee5c0de40f7e235835bfc1f4 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Thu, 23 Feb 2023 10:14:03 -0500 Subject: [PATCH] GP-3123 - Fixed broken tool button animation --- .../ghidra/framework/main/FrontEndPlugin.java | 33 ++-- .../ghidra/framework/main/ToolButton.java | 182 +++++++----------- .../ProjectDataOpenDefaultToolAction.java | 2 +- .../ghidra/framework/model/ToolServices.java | 42 ++-- .../framework/plugintool/PluginTool.java | 4 +- .../plugintool/ToolServicesAdapter.java | 6 + .../project/tool/ToolServicesImpl.java | 20 +- 7 files changed, 140 insertions(+), 149 deletions(-) diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java index 05f33daadc..386b3c53ca 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/FrontEndPlugin.java @@ -485,11 +485,11 @@ public class FrontEndPlugin extends Plugin * general project utility that brings up a file chooser for * the user to specify a directory and filename that are used * for the Project location and name - * + * * @param fileChooser the chooser used to pick the project * @param mode read-only or not * @param preferenceName the preference property name used to save the last opened project - * @return the project locator for the opened project + * @return the project locator for the opened project */ ProjectLocator chooseProject(GhidraFileChooser fileChooser, String mode, String preferenceName) { @@ -703,9 +703,9 @@ public class FrontEndPlugin extends Plugin connectionButton.setContentAreaFilled(false); connectionButton.setSelected(isConnected); - connectionButton.setBorder( - isConnected ? BorderFactory.createBevelBorder(BevelBorder.LOWERED) - : BorderFactory.createBevelBorder(BevelBorder.RAISED)); + connectionButton + .setBorder(isConnected ? BorderFactory.createBevelBorder(BevelBorder.LOWERED) + : BorderFactory.createBevelBorder(BevelBorder.RAISED)); connectionIconPanel.add(connectionButton); if (isConnected) { @@ -716,8 +716,8 @@ public class FrontEndPlugin extends Plugin Msg.debug(this, "Unexpected exception retrieving user from repository", e); } } - repositoryLabel.setText( - "Project Repository: " + repository.getName() + getAccessString(user)); + repositoryLabel + .setText("Project Repository: " + repository.getName() + getAccessString(user)); String serverName = repository.getServerInfo().getServerName(); connectionButton.setToolTipText( @@ -988,8 +988,8 @@ public class FrontEndPlugin extends Plugin } }; renameToolAction.setPopupMenuData(new MenuData(new String[] { "Rename..." }, "tool")); - renameToolAction.setHelpLocation( - new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Rename Tool")); + renameToolAction + .setHelpLocation(new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Rename Tool")); propertiesAction = new ToolButtonAction(PROPERTIES_ACTION_NAME) { @Override @@ -1012,8 +1012,8 @@ public class FrontEndPlugin extends Plugin propertiesAction.setPopupMenuData( new MenuData(new String[] { "Configure Plugins..." }, "zproperties")); - propertiesAction.setHelpLocation( - new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Configure_Tool")); + propertiesAction + .setHelpLocation(new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Configure_Tool")); tool.addLocalAction(frontEndProvider, exportToolAction); tool.addLocalAction(frontEndProvider, renameToolAction); @@ -1103,6 +1103,15 @@ public class FrontEndPlugin extends Plugin Project project = tool.getProject(); ToolServices toolServices = project.getToolServices(); + ToolTemplate defaultToolTemplate = toolServices.getDefaultToolTemplate(domainFile); + if (defaultToolTemplate != null) { + ToolButton button = toolBar.getToolButtonForToolConfig(defaultToolTemplate); + if (button != null) { + button.launchTool(domainFile); + return; + } + } + if (toolServices.launchDefaultTool(domainFile) != null) { return; } @@ -1132,7 +1141,7 @@ public class FrontEndPlugin extends Plugin DomainFolder domainFolder = linkedFolder.getLinkedFolder(); if (domainFolder != null) { - // delayed to ensure tree is displayd + // delayed to ensure tree is displayed Swing.runLater(() -> dtp.selectDomainFolder(domainFolder)); } } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ToolButton.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ToolButton.java index 5937995c0c..59ce420e01 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ToolButton.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/ToolButton.java @@ -41,6 +41,7 @@ import ghidra.util.bean.GGlassPane; import ghidra.util.exception.AssertException; import help.Help; import help.HelpService; +import util.CollectionUtils; import utility.function.Dummy; /** @@ -53,8 +54,6 @@ import utility.function.Dummy; */ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { - private static final Runnable DUMMY_RUNNABLE = Dummy.runnable(); - private DropTarget dropTarget; private DropTgtAdapter dropTargetAdapter; private DataFlavor[] acceptableFlavors; // data flavors that this component can support @@ -145,57 +144,24 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { } public void launchTool(DomainFile domainFile) { - doLaunchTool(new DomainFile[] { domainFile }); + openFilesAndOpenToolAsNecessary(List.of(domainFile), null); } //================================================================================================== // Droppable interface //================================================================================================== - /** - * Set drag feedback according to the OK parameter. - * @param ok true means the drop action is OK - * @param e event that has current state of drag and drop operation - */ @Override public void dragUnderFeedback(boolean ok, DropTargetDragEvent e) { // nothing to do } - /** - * Return true if is OK to drop the transferable at the location - * specified the event. - * @param e event that has current state of drag and drop operation - */ @Override - @SuppressWarnings("unchecked") - // our data; cast is OK public boolean isDropOk(DropTargetDragEvent e) { DataFlavor[] flavors = e.getCurrentDataFlavors(); + Transferable transferable = e.getTransferable(); try { - for (DataFlavor element : flavors) { - if (element.equals(DataTreeDragNDropHandler.localDomainFileFlavor)) { - Object draggedData = e.getTransferable() - .getTransferData(DataTreeDragNDropHandler.localDomainFileFlavor); - return containsSupportedDataTypes((List) draggedData); - } - else if (element.equals(ToolButtonTransferable.localToolButtonFlavor)) { - Object draggedData = e.getTransferable() - .getTransferData(ToolButtonTransferable.localToolButtonFlavor); - ToolButton draggedButton = (ToolButton) draggedData; - if (draggedButton != null) { - if (draggedButton.associatedRunningTool == associatedRunningTool) { - // tool chest -> tool chest is not allowed (both runningTools are null). - // runningTool -> same runningTool is not allowed. - return false; - } - return true; - } - } - else if (element.equals(VersionInfoTransferable.localVersionInfoFlavor)) { - return true; - } - } + return checkForDrop(flavors, transferable); } catch (UnsupportedFlavorException e1) { // don't care; return false @@ -206,6 +172,36 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { return false; } + @SuppressWarnings("unchecked") // our data; cast is OK + private boolean checkForDrop(DataFlavor[] flavors, Transferable transferable) + throws UnsupportedFlavorException, IOException { + + for (DataFlavor flavor : flavors) { + if (flavor.equals(DataTreeDragNDropHandler.localDomainFileFlavor)) { + Object draggedData = + transferable.getTransferData(DataTreeDragNDropHandler.localDomainFileFlavor); + return containsSupportedDataTypes((List) draggedData); + } + else if (flavor.equals(ToolButtonTransferable.localToolButtonFlavor)) { + Object draggedData = + transferable.getTransferData(ToolButtonTransferable.localToolButtonFlavor); + ToolButton draggedButton = (ToolButton) draggedData; + if (draggedButton != null) { + if (draggedButton.associatedRunningTool == associatedRunningTool) { + // tool chest -> tool chest is not allowed (both runningTools are null). + // runningTool -> same runningTool is not allowed. + return false; + } + return true; + } + } + else if (flavor.equals(VersionInfoTransferable.localVersionInfoFlavor)) { + return true; + } + } + return false; + } + /** * The given list must contain only valid domain files (i.e., no folders or null items) * @param fileList The list of file objects to validate @@ -223,23 +219,11 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { return fileList.size() > 0; } - /** - * Revert back to normal if any drag feedback was set. - */ @Override public void undoDragUnderFeedback() { // nothing to do } - /** - * Add the object to the droppable component. The DropTgtAdapter - * calls this method from its drop() method. - * - * @param obj Transferable object that is to be dropped. - * @param event has current state of drop operation - * @param f represents the opaque concept of a data format as - * would appear on a clipboard, during drag and drop. - */ @Override public void add(Object obj, DropTargetDropEvent event, DataFlavor f) { @@ -249,8 +233,7 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { @SuppressWarnings("unchecked") // we put the data in List list = (List) obj; - DomainFile[] domainFiles = list.toArray(new DomainFile[list.size()]); - openFilesAndOpenToolAsNecessary(domainFiles); + openFilesAndOpenToolAsNecessary(list, null); } else if (f.equals(VersionInfoTransferable.localVersionInfoFlavor)) { VersionInfo info = (VersionInfo) obj; @@ -264,7 +247,7 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { DomainFile domainFile = versionedObj.getDomainFile(); if (isSupportedDataType(domainFile)) { resetButtonAfterDrag(this); - openFilesAndOpenToolAsNecessary(new DomainFile[] { domainFile }, + openFilesAndOpenToolAsNecessary(List.of(domainFile), () -> versionedObj.release(ToolButton.this)); } else { @@ -280,23 +263,12 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { } } - private void showFilesNotAcceptedMessage(DomainFile[] domainFiles) { - StringBuffer buffer = new StringBuffer("Tool did not accept files: "); - for (int i = 0; i < domainFiles.length; i++) { - buffer.append(domainFiles[i].getName()); - if (i != domainFiles.length - 1) { - buffer.append(", "); - } - } - Msg.showError(this, null, "Error", buffer.toString()); - } - private void addFromToolButton(ToolButton toolButton) { plugin.setToolButtonTransferable(null); PluginTool tool = null; if (associatedRunningTool != null && toolButton.associatedRunningTool != null) { final PluginTool t2 = toolButton.associatedRunningTool; - SwingUtilities.invokeLater(() -> connectTools(associatedRunningTool, t2)); + Swing.runLater(() -> connectTools(associatedRunningTool, t2)); return; } @@ -305,14 +277,14 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { tool = plugin.getActiveWorkspace().runTool(toolButton.template); accepted = tool.acceptDomainFiles(associatedRunningTool.getDomainFiles()); final PluginTool t = tool; - SwingUtilities.invokeLater(() -> connectTools(t, associatedRunningTool)); + Swing.runLater(() -> connectTools(t, associatedRunningTool)); } else { tool = plugin.getActiveWorkspace().runTool(template); accepted = tool.acceptDomainFiles(toolButton.associatedRunningTool.getDomainFiles()); final PluginTool t = tool; final PluginTool t2 = toolButton.associatedRunningTool; - SwingUtilities.invokeLater(() -> connectTools(t, t2)); + Swing.runLater(() -> connectTools(t, t2)); } if (!accepted) { @@ -332,9 +304,6 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { connectAll(tc); } - /** - * Connect all events in the connection object. - */ private void connectAll(ToolConnection tc) { String[] events = tc.getEvents(); for (String element : events) { @@ -345,10 +314,6 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { tc.getConsumer().getName()); } - /** - * Return true if the domain file's object class is supported by - * this tool. - */ private boolean isSupportedDataType(DomainFile file) { if (file == null) { return false; @@ -436,19 +401,11 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { return true; } - /** - * Called by the DragGestureAdapter to start the drag. - */ @Override public DragSourceListener getDragSourceListener() { return dragSourceAdapter; } - /** - * Get the object to transfer. - * @param p location of object to transfer - * @return object to transfer - */ @Override public Transferable getTransferable(Point p) { return plugin.getToolButtonTransferable(); @@ -459,16 +416,6 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { resetButtonAfterDrag(this); } - /** - * Get the drag actions supported by this drag source: - *
    - *
  • DnDConstants.ACTION_MOVE - *
  • DnDConstants.ACTION_COPY - *
  • DnDConstants.ACTION_COPY_OR_MOVE - *
  • - * - * @return the drag actions - */ @Override public int getDragAction() { return dragAction; @@ -517,24 +464,18 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { private void activateTool() { if (associatedRunningTool == null) { // this is a button on the tool bar, so launch a new tool - doLaunchTool(null); + openFilesAndOpenToolAsNecessary(null, null); } else { associatedRunningTool.toFront(); } } - private void doLaunchTool(DomainFile[] domainFiles) { - openFilesAndOpenToolAsNecessary(domainFiles); - } - - private void openFilesAndOpenToolAsNecessary(final DomainFile[] domainFiles) { - openFilesAndOpenToolAsNecessary(domainFiles, DUMMY_RUNNABLE); - } - - private void openFilesAndOpenToolAsNecessary(final DomainFile[] domainFiles, + private void openFilesAndOpenToolAsNecessary(List domainFiles, Runnable finishedCallback) { + finishedCallback = Dummy.ifNull(finishedCallback); + if (associatedRunningTool != null) { // this button has a running tool, no need to open one openDomainFiles(associatedRunningTool, domainFiles); @@ -559,9 +500,8 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { finishedCallback); } - private void launchToolWithAnimationAndOpenFiles(final DomainFile[] domainFiles, - final JFrame toolFrame, final GGlassPane toolGlassPane, - final Runnable finishedCallback) { + private void launchToolWithAnimationAndOpenFiles(List domainFiles, JFrame toolFrame, + GGlassPane toolGlassPane, Runnable finishedCallback) { Icon icon = getIcon(); Point buttonLocation = getLocation(); @@ -591,8 +531,6 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { MoveImageRunner moveRunner = new MoveImageRunner(toolGlassPane, startBounds, endBounds, painter); - // a callback that lets us know when to open the given files and restore the state of - // the GhidraGlassPane TimingTarget finishedTarget = new TimingTargetAdapter() { @Override public void end() { @@ -600,8 +538,7 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { try { // cleanup any residual painting effects toolGlassPane.paintImmediately(toolGlassPane.getBounds()); - PluginTool newTool = plugin.getActiveWorkspace().runTool(template); - openDomainFiles(newTool, domainFiles); + openDomainFiles(domainFiles); } finally { // always restore the cursor @@ -619,19 +556,36 @@ class ToolButton extends EmptyBorderButton implements Draggable, Droppable { zoomRunner.run(); } - private void openDomainFiles(PluginTool tool, DomainFile[] domainFiles) { + private void openDomainFiles(List domainFiles) { + if (CollectionUtils.isBlank(domainFiles)) { + plugin.getActiveWorkspace().runTool(template); + } + else { + toolServices.launchDefaultTool(domainFiles); + } + } + + private void openDomainFiles(PluginTool tool, List domainFiles) { if (domainFiles == null) { return; } - boolean accepted = tool.acceptDomainFiles(domainFiles); + boolean accepted = tool.acceptDomainFiles(domainFiles.toArray(DomainFile[]::new)); if (!accepted) { showFilesNotAcceptedMessage(domainFiles); } } - /** - * Set up the objects so we can be a drag and drop site. - */ + private void showFilesNotAcceptedMessage(List domainFiles) { + StringBuilder buffy = new StringBuilder("Tool did not accept files: "); + for (int i = 0; i < domainFiles.size(); i++) { + buffy.append(domainFiles.get(0).getName()); + if (i != domainFiles.size() - 1) { + buffy.append(", "); + } + } + Msg.showError(this, null, "Error", buffy.toString()); + } + private void setUpDragDrop() { acceptableFlavors = new DataFlavor[] { DataTreeDragNDropHandler.localDomainFileFlavor, diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataOpenDefaultToolAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataOpenDefaultToolAction.java index 506e2bb06f..e1404cb494 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataOpenDefaultToolAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataOpenDefaultToolAction.java @@ -37,7 +37,7 @@ public class ProjectDataOpenDefaultToolAction extends FrontendProjectTreeAction @Override protected void actionPerformed(ProjectDataContext context) { List selectedFiles = context.getSelectedFiles(); - AppInfo.getActiveProject().getToolServices().launchDefaultTool(selectedFiles.get(0)); + AppInfo.getActiveProject().getToolServices().launchDefaultTool(selectedFiles); } @Override diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/ToolServices.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/ToolServices.java index 20150baa2c..c6b0fc750d 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/ToolServices.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/model/ToolServices.java @@ -17,6 +17,7 @@ package ghidra.framework.model; import java.io.*; import java.net.URL; +import java.util.Collection; import java.util.Set; import ghidra.framework.plugintool.PluginEvent; @@ -33,22 +34,22 @@ public interface ToolServices { /** * Notify the framework that the tool is closing. - * + * * @param tool tool that is closing */ public void closeTool(PluginTool tool); /** * Saves the tool's configuration in the standard - * tool location. - * + * tool location. + * * @param tool tool to save. */ public void saveTool(PluginTool tool); /** * Save the tool to the given location on the local file system. - * + * * @param tool the tool template to write * @return the file to which the tool was saved * @throws FileNotFoundException thrown if the file's directory doesn't exist. @@ -67,7 +68,7 @@ public interface ToolServices { * If it finds a matching tool, then it is brought to the front. * Otherwise, it creates one and runs it. * It then invokes the specified event on the running tool. - * + * * @param tool find/create a tool like this one. * @param domainFile open this file in the found/created tool. * @param event invoke this event on the found/created tool @@ -75,18 +76,18 @@ public interface ToolServices { public void displaySimilarTool(PluginTool tool, DomainFile domainFile, PluginEvent event); /** - * Returns the default/preferred tool template which should be used to open the specified + * Returns the default/preferred tool template which should be used to open the specified * domain file, whether defined by the user or the system default. - * + * * @param domainFile The file whose preferred tool should be found. * @return The preferred tool that should be used to open the given file or null if none found. */ public ToolTemplate getDefaultToolTemplate(DomainFile domainFile); /** - * Returns the default/preferred tool template which should be used to open the specified + * Returns the default/preferred tool template which should be used to open the specified * domain file content type, whether defined by the user or the system default. - * + * * @param contentType The content type whose preferred tool should be found. * @return The preferred tool that should be used to open the given file or null if none found. */ @@ -100,18 +101,18 @@ public interface ToolServices { public Set getCompatibleTools(Class domainClass); /** - * Returns the {@link ToolAssociationInfo associations}, which describe content + * Returns the {@link ToolAssociationInfo associations}, which describe content * types and the tools used to open them, for all content types known to the system. - * + * * @return the associations * @see #setContentTypeToolAssociations(Set) */ public Set getContentTypeToolAssociations(); /** - * Sets the {@link ToolAssociationInfo associations}, which describe content - * types and the tools used to open them, for the system. - * + * Sets the {@link ToolAssociationInfo associations}, which describe content + * types and the tools used to open them, for the system. + * * @param infos The associations to be applied * @see #getContentTypeToolAssociations() */ @@ -119,13 +120,22 @@ public interface ToolServices { /** * Launch the default tool and open the specified domainFile. - * NOTE: running tool re-use is implementation dependent + * NOTE: running tool reuse is implementation dependent * @param domainFile the file to open * @return the launched tool. Null returned if a suitable default tool * for the file content type was not found. */ public PluginTool launchDefaultTool(DomainFile domainFile); + /** + * Launch the default tool and open the specified domainFiles. + * NOTE: running tool reuse is implementation dependent + * @param domainFile the file to open + * @return the launched tool. Null returned if a suitable default tool + * for the file content type was not found. + */ + public PluginTool launchDefaultTool(Collection domainFile); + /** * Launch the tool with the given name. A domainFile may be specified and will be opened * if its content type is supported by the tool. @@ -137,7 +147,7 @@ public interface ToolServices { /** * Launch the default tool and open the specified Ghidra URL resource. - * The tool choosen will be based upon the content type of the specified resource. + * The tool chosen will be based upon the content type of the specified resource. * NOTE: running tool re-use is implementation dependent * @param ghidraUrl resource to be opened (see {@link GhidraURL}) * @return the launched tool. Null returned if a failure occurs while accessing the specified diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java index 0a677c99ea..95d4394e74 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/PluginTool.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/ToolServicesAdapter.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/ToolServicesAdapter.java index 4890313862..fcc6015aa8 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/ToolServicesAdapter.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/ToolServicesAdapter.java @@ -17,6 +17,7 @@ package ghidra.framework.plugintool; import java.io.*; import java.net.URL; +import java.util.Collection; import java.util.Set; import ghidra.framework.model.*; @@ -78,6 +79,11 @@ public class ToolServicesAdapter implements ToolServices { return null; } + @Override + public PluginTool launchDefaultTool(Collection domainFile) { + return null; + } + @Override public PluginTool launchTool(String toolName, DomainFile domainFile) { return null; diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/ToolServicesImpl.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/ToolServicesImpl.java index 04d1c1f036..4c56dd9da0 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/ToolServicesImpl.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/project/tool/ToolServicesImpl.java @@ -41,6 +41,7 @@ import ghidra.util.filechooser.GhidraFileChooserModel; import ghidra.util.filechooser.GhidraFileFilter; import ghidra.util.task.TaskLauncher; import ghidra.util.xml.GenericXMLOutputter; +import util.CollectionUtils; /** * Implementation of service used to manipulate tools. @@ -243,6 +244,17 @@ class ToolServicesImpl implements ToolServices { }); } + @Override + public PluginTool launchDefaultTool(Collection domainFiles) { + if (CollectionUtils.isBlank(domainFiles)) { + throw new IllegalArgumentException("Domain files cannot be empty"); + } + ToolTemplate template = getDefaultToolTemplate(CollectionUtils.any(domainFiles)); + return defaultLaunch(template, t -> { + return t.acceptDomainFiles(domainFiles.toArray(DomainFile[]::new)); + }); + } + @Override public PluginTool launchTool(String toolName, DomainFile domainFile) { ToolTemplate template = findToolChestToolTemplate(toolName); @@ -530,9 +542,9 @@ class ToolServicesImpl implements ToolServices { /** * Get all running tools that have the same tool chest tool name as this one. - * + * * @param tool the tool for comparison. - * + * * @return array of tools that are running and named the same as this one. */ private PluginTool[] getSameNamedRunningTools(PluginTool tool) { @@ -554,10 +566,10 @@ class ToolServicesImpl implements ToolServices { /** * Search the array of tools for one using the given domainFile. - * + * * @param tools array of tools to search * @param domainFile domain file to find user of - * + * * @return first tool found to be using the domainFile */ private PluginTool findToolUsingFile(PluginTool[] tools, DomainFile domainFile) {