From 1fbc4fc373f443a6b09a487e114cfbb7ccdee8bd Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 7 Mar 2019 18:08:19 -0500 Subject: [PATCH] 4755 working multi-select context menu action for main window --- .../DataResultTopComponent.java | 3 +- .../datamodel/DataModelActionsFactory.java | 260 ++++++++++-------- .../autopsy/datamodel/DirectoryNode.java | 4 +- .../sleuthkit/autopsy/datamodel/FileNode.java | 19 +- .../autopsy/datamodel/LayoutFileNode.java | 16 +- .../autopsy/datamodel/LocalFileNode.java | 13 +- .../autopsy/datamodel/SlackFileNode.java | 16 +- .../datamodel/SpecialDirectoryNode.java | 7 +- .../directorytree/DataResultFilterNode.java | 14 +- .../ExplorerNodeActionVisitor.java | 66 ++--- .../ExternalViewerShortcutAction.java | 14 +- .../timeline/TimeLineTopComponent.java | 2 +- .../ImageGalleryTopComponent.java | 2 +- .../gui/drawableviews/DrawableTileBase.java | 2 +- 14 files changed, 251 insertions(+), 187 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java index 250b76cac7..35a3007ece 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultTopComponent.java @@ -250,8 +250,7 @@ public final class DataResultTopComponent extends TopComponent implements DataRe getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(AddBookmarkTagAction.BOOKMARK_SHORTCUT, "addBookmarkTag"); //NON-NLS getActionMap().put("addBookmarkTag", new AddBookmarkTagAction()); //NON-NLS getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ExternalViewerShortcutAction.EXTERNAL_VIEWER_SHORTCUT, "useExternalViewer"); //NON-NLS - - getActionMap().put("useExternalViewer", new ExternalViewerShortcutAction()); //NON-NLS + getActionMap().put("useExternalViewer", ExternalViewerShortcutAction.getInstance()); //NON-NLS putClientProperty(TopComponent.PROP_CLOSING_DISABLED, isMain); putClientProperty(TopComponent.PROP_MAXIMIZATION_DISABLED, true); putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, true); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java index 88e90f054d..7033fa6543 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java @@ -1,15 +1,15 @@ /* * Autopsy Forensic Browser - * + * * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org - * + * * 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. @@ -37,6 +37,7 @@ import org.sleuthkit.autopsy.actions.ReplaceContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.datamodel.Reports.ReportNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; +import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; @@ -82,7 +83,13 @@ public class DataModelActionsFactory { final FileNode fileNode = new FileNode(file); actionsList.add(null); // creates a menu separator actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, fileNode)); - actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { + actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode)); + } else { + actionsList.add(ExternalViewerShortcutAction.getInstance()); + } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator @@ -90,24 +97,22 @@ public class DataModelActionsFactory { if (isArtifactSource) { actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } - if(isArtifactSource) { - final Collection selectedArtifactsList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); - if(selectedArtifactsList.size() == 1) { + if (isArtifactSource) { + final Collection selectedArtifactsList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + if (selectedArtifactsList.size() == 1) { actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); } } - + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } - + public static List getActions(SlackFile slackFile, boolean isArtifactSource) { List actionsList = new ArrayList<>(); actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), slackFile)); @@ -121,20 +126,20 @@ public class DataModelActionsFactory { if (isArtifactSource) { actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); - } - if(isArtifactSource) { - final Collection selectedArtifactsList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); - if(selectedArtifactsList.size() == 1) { + } + if (isArtifactSource) { + final Collection selectedArtifactsList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + if (selectedArtifactsList.size() == 1) { actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); } } - + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } @@ -145,7 +150,13 @@ public class DataModelActionsFactory { LayoutFileNode layoutFileNode = new LayoutFileNode(file); actionsList.add(null); // creates a menu separator actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, layoutFileNode)); - actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, layoutFileNode)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { + actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, layoutFileNode)); + } else { + actionsList.add(ExternalViewerShortcutAction.getInstance()); + } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance());// actionsList.add(null); // creates a menu separator @@ -153,20 +164,18 @@ public class DataModelActionsFactory { if (isArtifactSource) { actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } - if(isArtifactSource) { - final Collection selectedArtifactsList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); - if(selectedArtifactsList.size() == 1) { + if (isArtifactSource) { + final Collection selectedArtifactsList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + if (selectedArtifactsList.size() == 1) { actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); } } - + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } @@ -177,7 +186,13 @@ public class DataModelActionsFactory { DirectoryNode directoryNode = new DirectoryNode(directory); actionsList.add(null); // creates a menu separator actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode)); - actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { + actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode)); + } else { + actionsList.add(ExternalViewerShortcutAction.getInstance()); + } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator @@ -185,20 +200,18 @@ public class DataModelActionsFactory { if (isArtifactSource) { actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } - if(isArtifactSource) { - final Collection selectedArtifactsList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); - if(selectedArtifactsList.size() == 1) { + if (isArtifactSource) { + final Collection selectedArtifactsList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + if (selectedArtifactsList.size() == 1) { actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); } } - + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } @@ -209,7 +222,13 @@ public class DataModelActionsFactory { VirtualDirectoryNode directoryNode = new VirtualDirectoryNode(directory); actionsList.add(null); // creates a menu separator actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode)); - actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { + actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode)); + } else { + actionsList.add(ExternalViewerShortcutAction.getInstance()); + } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator @@ -217,31 +236,35 @@ public class DataModelActionsFactory { if (isArtifactSource) { actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } - if(isArtifactSource) { - final Collection selectedArtifactsList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); - if(selectedArtifactsList.size() == 1) { + if (isArtifactSource) { + final Collection selectedArtifactsList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + if (selectedArtifactsList.size() == 1) { actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); } } - + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } - + public static List getActions(LocalDirectory directory, boolean isArtifactSource) { List actionsList = new ArrayList<>(); actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory)); LocalDirectoryNode directoryNode = new LocalDirectoryNode(directory); actionsList.add(null); // creates a menu separator actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode)); - actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { + actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode)); + } else { + actionsList.add(ExternalViewerShortcutAction.getInstance()); + } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator @@ -249,20 +272,18 @@ public class DataModelActionsFactory { if (isArtifactSource) { actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } - if(isArtifactSource) { - final Collection selectedArtifactsList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); - if(selectedArtifactsList.size() == 1) { + if (isArtifactSource) { + final Collection selectedArtifactsList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + if (selectedArtifactsList.size() == 1) { actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); } } - + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } @@ -273,7 +294,13 @@ public class DataModelActionsFactory { final LocalFileNode localFileNode = new LocalFileNode(file); actionsList.add(null); // creates a menu separator actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode)); - actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { + actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode)); + } else { + actionsList.add(ExternalViewerShortcutAction.getInstance()); + } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator @@ -281,20 +308,18 @@ public class DataModelActionsFactory { if (isArtifactSource) { actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } - if(isArtifactSource) { - final Collection selectedArtifactsList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); - if(selectedArtifactsList.size() == 1) { + if (isArtifactSource) { + final Collection selectedArtifactsList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + if (selectedArtifactsList.size() == 1) { actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); } } - + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } @@ -305,7 +330,13 @@ public class DataModelActionsFactory { final LocalFileNode localFileNode = new LocalFileNode(file); actionsList.add(null); // creates a menu separator actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode)); - actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { + actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode)); + } else { + actionsList.add(ExternalViewerShortcutAction.getInstance()); + } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator @@ -313,20 +344,18 @@ public class DataModelActionsFactory { if (isArtifactSource) { actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } - if(isArtifactSource) { - final Collection selectedArtifactsList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); - if(selectedArtifactsList.size() == 1) { + if (isArtifactSource) { + final Collection selectedArtifactsList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + if (selectedArtifactsList.size() == 1) { actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); } } - + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } @@ -354,13 +383,19 @@ public class DataModelActionsFactory { } public static List getActions(ContentTag contentTag, boolean isArtifactSource) { - + List actionsList = new ArrayList<>(); actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), contentTag.getContent())); final ContentTagNode tagNode = new ContentTagNode(contentTag); actionsList.add(null); // creates a menu separator actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, tagNode)); - actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { + actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode)); + } else { + actionsList.add(ExternalViewerShortcutAction.getInstance()); + } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator @@ -368,35 +403,38 @@ public class DataModelActionsFactory { if (isArtifactSource) { actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } - if(isArtifactSource) { - final Collection selectedArtifactsList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); - if(selectedArtifactsList.size() == 1) { + if (isArtifactSource) { + final Collection selectedArtifactsList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + if (selectedArtifactsList.size() == 1) { actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); } } - + actionsList.add(DeleteContentTagAction.getInstance()); actionsList.add(ReplaceContentTagAction.getInstance()); - + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } - - + public static List getActions(BlackboardArtifactTag artifactTag, boolean isArtifactSource) { List actionsList = new ArrayList<>(); actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), artifactTag.getContent())); final BlackboardArtifactTagNode tagNode = new BlackboardArtifactTagNode(artifactTag); actionsList.add(null); // creates a menu separator actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, tagNode)); - actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { + actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, tagNode)); + } else { + actionsList.add(ExternalViewerShortcutAction.getInstance()); + } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator @@ -404,27 +442,25 @@ public class DataModelActionsFactory { if (isArtifactSource) { actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } - if(isArtifactSource) { - final Collection selectedArtifactsList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); - if(selectedArtifactsList.size() == 1) { + if (isArtifactSource) { + final Collection selectedArtifactsList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + if (selectedArtifactsList.size() == 1) { actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); } } - + actionsList.add(DeleteBlackboardArtifactTagAction.getInstance()); actionsList.add(ReplaceBlackboardArtifactTagAction.getInstance()); - + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } - + public static List getActions(Content content, boolean isArtifactSource) { if (content instanceof File) { return getActions((File) content, isArtifactSource); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 97b0fd8216..73823e8574 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -28,6 +28,7 @@ import org.openide.util.Utilities; import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; @@ -97,8 +98,7 @@ public class DirectoryNode extends AbstractFsContentNode { final Collection selectedFilesList = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); - } - + } actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[actionsList.size()]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 81f69cfbbf..1695b253b0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2011-2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; +import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; @@ -49,9 +50,9 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; * children. */ public class FileNode extends AbstractFsContentNode { - + private static final Logger logger = Logger.getLogger(FileNode.class.getName()); - + /** * Gets the path to the icon file that should be used to visually represent * an AbstractFile, using the file name extension to select the icon. @@ -160,7 +161,14 @@ public class FileNode extends AbstractFsContentNode { } actionsList.add(new NewWindowViewAction(Bundle.FileNode_getActions_viewInNewWin_text(), this)); - actionsList.add(new ExternalViewerAction(Bundle.FileNode_getActions_openInExtViewer_text(), this)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { + actionsList.add(new ExternalViewerAction( + Bundle.FileNode_getActions_openInExtViewer_text(), this)); + } else { + actionsList.add(ExternalViewerShortcutAction.getInstance()); + } actionsList.add(ViewFileInTimelineAction.createViewFileAction(getContent())); actionsList.add(null); // Creates an item separator @@ -168,12 +176,11 @@ public class FileNode extends AbstractFsContentNode { actionsList.add(null); // Creates an item separator actionsList.add(AddContentTagAction.getInstance()); - final Collection selectedFilesList = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); if (1 == selectedFilesList.size()) { actionsList.add(DeleteFileContentTagAction.getInstance()); } actionsList.addAll(ContextMenuExtensionPoint.getActions()); - if (FileTypeExtensions.getArchiveExtensions().contains("." + this.content.getNameExtension().toLowerCase())) { + if (FileTypeExtensions.getArchiveExtensions().contains("." + this.content.getNameExtension().toLowerCase())) { try { if (this.content.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED).size() > 0) { actionsList.add(new ExtractArchiveWithPasswordAction(this.getContent())); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index 555d61d77d..04d256c118 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2011-2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; -import java.util.Map; import javax.swing.Action; import org.openide.util.NbBundle; import org.openide.util.Utilities; @@ -31,6 +30,7 @@ import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; +import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.datamodel.AbstractFile; @@ -89,15 +89,19 @@ public class LayoutFileNode extends AbstractAbstractFileNode { actionsList.addAll(Arrays.asList(super.getActions(true))); actionsList.add(new NewWindowViewAction( NbBundle.getMessage(this.getClass(), "LayoutFileNode.getActions.viewInNewWin.text"), this)); - actionsList.add(new ExternalViewerAction( - NbBundle.getMessage(this.getClass(), "LayoutFileNode.getActions.openInExtViewer.text"), this)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { + actionsList.add(new ExternalViewerAction( + NbBundle.getMessage(this.getClass(), "LayoutFileNode.getActions.openInExtViewer.text"), this)); + } else { + actionsList.add(ExternalViewerShortcutAction.getInstance()); + } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); - final Collection selectedFilesList - = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index 5c83708fec..94ac684855 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -32,6 +32,7 @@ import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; +import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; @@ -69,16 +70,20 @@ public class LocalFileNode extends AbstractAbstractFileNode { actionsList.add(null); // creates a menu separator actionsList.add(new NewWindowViewAction( NbBundle.getMessage(this.getClass(), "LocalFileNode.getActions.viewInNewWin.text"), this)); - actionsList.add(new ExternalViewerAction( - NbBundle.getMessage(this.getClass(), "LocalFileNode.getActions.openInExtViewer.text"), this)); + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { + actionsList.add(new ExternalViewerAction( + NbBundle.getMessage(this.getClass(), "LocalFileNode.getActions.openInExtViewer.text"), this)); + } else { + actionsList.add(ExternalViewerShortcutAction.getInstance()); + } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); - final Collection selectedFilesList - = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java index ba377b1e0e..65eeadaa4c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java @@ -28,6 +28,7 @@ import org.openide.util.Utilities; import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; @@ -87,13 +88,12 @@ public class SlackFileNode extends AbstractFsContentNode { actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); - } - + } actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[actionsList.size()]); } @@ -112,7 +112,7 @@ public class SlackFileNode extends AbstractFsContentNode { // file based off it's extension static String getIconForFileType(AbstractFile file) { - return "org/sleuthkit/autopsy/images/file-icon.png"; //NON-NLS + return "org/sleuthkit/autopsy/images/file-icon.png"; //NON-NLS } @Override @@ -122,7 +122,7 @@ public class SlackFileNode extends AbstractFsContentNode { // not will check if it has children using the Content API return true; } - + @Override public String getItemType() { return getClass().getName(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java index 47f616de12..5aa16b075c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java @@ -19,16 +19,21 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import javax.swing.Action; import org.openide.util.NbBundle; +import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.datasourcesummary.ViewSummaryInformationAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.FileSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SpecialDirectory; @@ -36,7 +41,7 @@ import org.sleuthkit.datamodel.SpecialDirectory; * Parent class for special directory types (Local and Virtual) */ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNode { - + public SpecialDirectoryNode(SpecialDirectory sd) { super(sd); } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index e097f75a92..2b4ac0f75c 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -432,19 +432,23 @@ public class DataResultFilterNode extends FilterNode { actionsList.addAll(DataModelActionsFactory.getActions(c, false)); } if (n != null) { + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); actionsList.add(null); // creates a menu separator actionsList.add(new NewWindowViewAction( NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewInNewWin.text"), n)); - actionsList.add(new ExternalViewerAction( - NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.openInExtViewer.text"), n)); + if (selectedFilesList.size() == 1) { + actionsList.add(new ExternalViewerAction( + NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.openInExtViewer.text"), n)); + } else { + actionsList.add(ExternalViewerShortcutAction.getInstance()); + } actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); actionsList.add(AddBlackboardArtifactTagAction.getInstance()); - - final Collection selectedFilesList - = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java index 99692ea633..bd80b8900f 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java @@ -61,8 +61,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final Volume vol) { List lst = new ArrayList<>(); lst.add(new ExtractUnallocAction( - NbBundle.getMessage(this.getClass(), "ExplorerNodeActionVisitor.action.extUnallocToSingleFile"), vol)); - + NbBundle.getMessage(this.getClass(), "ExplorerNodeActionVisitor.action.extUnallocToSingleFile"), vol)); + return lst; } @@ -101,13 +100,13 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final Directory d) { List actionsList = new ArrayList<>(); actionsList.add(AddContentTagAction.getInstance()); - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } - + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } @@ -117,10 +116,10 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actionsList = new ArrayList<>(); if (!d.isDataSource()) { actionsList.add(AddContentTagAction.getInstance()); - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } } @@ -128,16 +127,15 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final LocalDirectory d) { List actionsList = new ArrayList<>(); if (!d.isDataSource()) { actionsList.add(AddContentTagAction.getInstance()); - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } } @@ -151,13 +149,11 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actionsList = new ArrayList<>(); actionsList.add(ExtractAction.getInstance()); actionsList.add(AddContentTagAction.getInstance()); - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } - actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } @@ -167,13 +163,11 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actionsList = new ArrayList<>(); actionsList.add(ExtractAction.getInstance()); actionsList.add(AddContentTagAction.getInstance()); - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); - } - + } actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } @@ -183,13 +177,11 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actionsList = new ArrayList<>(); actionsList.add(ExtractAction.getInstance()); actionsList.add(AddContentTagAction.getInstance()); - - final Collection selectedFilesList = - new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + final Collection selectedFilesList + = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); - } - + } actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerShortcutAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerShortcutAction.java index e90dc3c8e3..3066db5679 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerShortcutAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExternalViewerShortcutAction.java @@ -39,10 +39,22 @@ public class ExternalViewerShortcutAction extends AbstractAction { public static final KeyStroke EXTERNAL_VIEWER_SHORTCUT = KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_MASK); - public ExternalViewerShortcutAction() { + private ExternalViewerShortcutAction() { super(Bundle.ExternalViewerShortcutAction_title_text()); } + // This class is a singleton to support multi-selection of nodes, since + // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every + // node in the array returns a reference to the same action object from Node.getActions(boolean). + private static ExternalViewerShortcutAction instance; + + public static synchronized ExternalViewerShortcutAction getInstance() { + if (null == instance) { + instance = new ExternalViewerShortcutAction(); + } + return instance; + } + @Override public void actionPerformed(ActionEvent e) { final Collection selectedFiles = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java index 747152ee59..8bc247878e 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineTopComponent.java @@ -263,7 +263,7 @@ public final class TimeLineTopComponent extends TopComponent implements Explorer getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(AddBookmarkTagAction.BOOKMARK_SHORTCUT, "addBookmarkTag"); //NON-NLS getActionMap().put("addBookmarkTag", new AddBookmarkTagAction()); //NON-NLS getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ExternalViewerShortcutAction.EXTERNAL_VIEWER_SHORTCUT, "useExternalViewer"); //NON-NLS - getActionMap().put("useExternalViewer", new ExternalViewerShortcutAction()); //NON-NLS + getActionMap().put("useExternalViewer", ExternalViewerShortcutAction.getInstance()); //NON-NLS this.controller = controller; //create linked result and content views diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java index 159936ba4a..f7e8b9ba92 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java @@ -241,7 +241,7 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl setName(Bundle.CTL_ImageGalleryTopComponent()); initComponents(); getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ExternalViewerShortcutAction.EXTERNAL_VIEWER_SHORTCUT, "useExternalViewer"); //NON-NLS - getActionMap().put("useExternalViewer", new ExternalViewerShortcutAction()); //NON-NLS + getActionMap().put("useExternalViewer", ExternalViewerShortcutAction.getInstance()); //NON-NLS } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index c8ffb85545..79cbff1a76 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -217,7 +217,7 @@ public abstract class DrawableTileBase extends DrawableUIBase { MenuItem externalViewer = new MenuItem("Open in External Viewer"); externalViewer.setOnAction(actionEvent -> SwingUtilities.invokeLater(() -> { - new ExternalViewerShortcutAction() + ExternalViewerShortcutAction.getInstance() .actionPerformed(null); })); externalViewer.setAccelerator(OpenExternalViewerAction.EXTERNAL_VIEWER_SHORTCUT);