From 25e091229e32d9dcd0382c026c8abe8a6221be1c Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 19 Apr 2017 12:31:05 -0400 Subject: [PATCH] Added 'Remove File Tag' and 'Remove Result Tag' options. --- .../AddBlackboardArtifactTagAction.java | 6 + .../autopsy/actions/AddContentTagAction.java | 14 +- .../autopsy/actions/Bundle.properties | 17 -- .../autopsy/actions/Bundle_ja.properties | 104 ++++--- .../DeleteBlackboardArtifactTagAction.java | 80 +++-- .../actions/DeleteContentTagAction.java | 64 +++- ...DeleteFileBlackboardArtifactTagAction.java | 205 +++++++++++++ .../actions/DeleteFileContentTagAction.java | 202 +++++++++++++ .../datamodel/DataModelActionsFactory.java | 275 ++++++++++++------ .../autopsy/datamodel/DirectoryNode.java | 39 ++- .../sleuthkit/autopsy/datamodel/FileNode.java | 15 +- .../autopsy/datamodel/LayoutFileNode.java | 14 +- .../autopsy/datamodel/LocalFileNode.java | 16 +- .../autopsy/datamodel/SlackFileNode.java | 13 +- .../directorytree/DataResultFilterNode.java | 59 ++-- .../ExplorerNodeActionVisitor.java | 89 ++++-- .../imagegallery/actions/DeleteTagAction.java | 164 +++++++++++ .../gui/drawableviews/DrawableTileBase.java | 11 +- .../KeywordSearchFilterNode.java | 32 +- 19 files changed, 1161 insertions(+), 258 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java create mode 100755 Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java create mode 100755 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java index 4ac2e31ab1..85d5b7b668 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java @@ -34,6 +34,12 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this Action allow users to apply tags to blackboard artifacts. */ +@NbBundle.Messages({ + "AddBlackboardArtifactTagAction.singularTagResult=Tag Result", + "AddBlackboardArtifactTagAction.pluralTagResult=Tag Results", + "AddBlackboardArtifactTagAction.unableToTag.msg=Unable to tag {0}.", + "AddBlackboardArtifactTagAction.taggingErr=Tagging Error" +}) public class AddBlackboardArtifactTagAction extends AddTagAction { // This class is a singleton to support multi-selection of nodes, since diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java index c386858aa4..d6442c9b0a 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,15 +29,21 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.FsContent; -import org.sleuthkit.datamodel.LayoutFile; -import org.sleuthkit.datamodel.LocalFile; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this Action allow users to apply tags to content. */ +@NbBundle.Messages({ + "AddContentTagAction.singularTagFile=Tag File", + "AddContentTagAction.pluralTagFile=Tag Files", + "AddContentTagAction.unableToTag.msg=Unable to tag {0}, not a regular file.", + "AddContentTagAction.cannotApplyTagErr=Cannot Apply Tag", + "AddContentTagAction.unableToTag.msg2=Unable to tag {0}.", + "AddContentTagAction.taggingErr=Tagging Error", + "AddContentTagAction.tagExists={0} has been tagged as {1}. Cannot reapply the same tag." +}) public class AddContentTagAction extends AddTagAction { // This class is a singleton to support multi-selection of nodes, since diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties index 6314dc6f40..28d4e4006a 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties @@ -14,29 +14,12 @@ GetTagNameAndCommentDialog.commentLabel.text=Comment: GetTagNameAndCommentDialog.cancelButton.text=Cancel GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use GetTagNameAndCommentDialog.tagLabel.text=Tag: -AddBlackboardArtifactTagAction.singularTagResult=Tag Result -AddBlackboardArtifactTagAction.pluralTagResult=Tag Results -AddBlackboardArtifactTagAction.unableToTag.msg=Unable to tag {0}. -AddBlackboardArtifactTagAction.taggingErr=Tagging Error -AddContentTagAction.singularTagFile=Tag File -AddContentTagAction.pluralTagFile=Tag Files -AddContentTagAction.unableToTag.msg=Unable to tag {0}, not a regular file. -AddContentTagAction.cannotApplyTagErr=Cannot Apply Tag -AddContentTagAction.unableToTag.msg2=Unable to tag {0}. -AddContentTagAction.taggingErr=Tagging Error -AddContentTagAction.tagExists={0} has been tagged as {1}. Cannot reapply the same tag. AddTagAction.bookmarkFile=Bookmark file AddTagAction.quickTag=Quick Tag AddTagAction.noTags=No tags AddTagAction.newTag=New Tag... AddTagAction.tagAndComment=Tag and Comment... AddBookmarkTagAction.bookmark.text=Bookmark -DeleteBlackboardArtifactTagAction.deleteTags=Delete Tag(s) -DeleteBlackboardArtifactTagAction.unableToDelTag.msg=Unable to delete tag {0}. -DeleteBlackboardArtifactTagAction.tagDelErr=Tag Deletion Error -DeleteContentTagAction.deleteTags=Delete Tag(s) -DeleteContentTagAction.unableToDelTag.msg=Unable to delete tag {0}. -DeleteContentTagAction.tagDelErr=Tag Deletion Error GetTagNameAndCommentDialog.noTags=No Tags GetTagNameAndCommentDialog.createTag=Create Tag GetTagNameAndCommentDialog.cancelName=cancel diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle_ja.properties index 28b9af065b..195d12c695 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle_ja.properties @@ -1,57 +1,51 @@ -GetTagNameDialog.cancelButton.text=\u30AD\u30E3\u30F3\u30BB\u30EB +GetTagNameDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb GetTagNameDialog.okButton.text=OK -GetTagNameDialog.preexistingLabel.text=\u65E2\u5B58\u30BF\u30B0\uFF1A -GetTagNameDialog.newTagPanel.border.title=\u65B0\u898F\u30BF\u30B0 -GetTagNameDialog.tagNameLabel.text=\u30BF\u30B0\u540D\uFF1A -GetTagNameAndCommentDialog.newTagButton.text=\u65B0\u898F\u30BF\u30B0 +GetTagNameDialog.preexistingLabel.text=\u65e2\u5b58\u30bf\u30b0\uff1a +GetTagNameDialog.newTagPanel.border.title=\u65b0\u898f\u30bf\u30b0 +GetTagNameDialog.tagNameLabel.text=\u30bf\u30b0\u540d\uff1a +GetTagNameAndCommentDialog.newTagButton.text=\u65b0\u898f\u30bf\u30b0 GetTagNameAndCommentDialog.okButton.text=OK -GetTagNameAndCommentDialog.commentText.toolTipText=\u30BF\u30B0\u306E\u30AA\u30D7\u30B7\u30E7\u30CA\u30EB\u306E\u30B3\u30E1\u30F3\u30C8\u3092\u5165\u529B\u307E\u305F\u306F\u7A7A\u6B04\u306B\u3057\u3066\u304F\u3060\u3055\u3044 -GetTagNameAndCommentDialog.commentLabel.text=\u30B3\u30E1\u30F3\u30C8\uFF1A -GetTagNameAndCommentDialog.cancelButton.text=\u30AD\u30E3\u30F3\u30BB\u30EB -GetTagNameAndCommentDialog.tagCombo.toolTipText=\u4F7F\u7528\u3059\u308B\u30BF\u30B0\u3092\u9078\u629E -GetTagNameAndCommentDialog.tagLabel.text=\u30BF\u30B0\uFF1A -AddBlackboardArtifactTagAction.singularTagResult=\u7D50\u679C\u306B\u30BF\u30B0\u3092\u8FFD\u52A0 -AddBlackboardArtifactTagAction.pluralTagResult=\u7D50\u679C\u306B\u30BF\u30B0\u3092\u8FFD\u52A0 -AddBlackboardArtifactTagAction.unableToTag.msg={0}\u306B\u30BF\u30B0\u3092\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3002 -AddBlackboardArtifactTagAction.taggingErr=\u30BF\u30B0\u4ED8\u3051\u30A8\u30E9\u30FC -AddContentTagAction.singularTagFile=\u30D5\u30A1\u30A4\u30EB\u306B\u30BF\u30B0\u3092\u8FFD\u52A0 -AddContentTagAction.pluralTagFile=\u30D5\u30A1\u30A4\u30EB\u306B\u30BF\u30B0\u3092\u8FFD\u52A0 -AddContentTagAction.unableToTag.msg={0}\u306B\u30BF\u30B0\u3092\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3002\u901A\u5E38\u30D5\u30A1\u30A4\u30EB\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002 -AddContentTagAction.unableToTag.msg2={0}\u306B\u30BF\u30B0\u3092\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3002 -AddContentTagAction.taggingErr=\u30BF\u30B0\u4ED8\u3051\u30A8\u30E9\u30FC -AddTagAction.quickTag=\u30AF\u30A4\u30C3\u30AF\u30BF\u30B0 -AddTagAction.noTags=\u30BF\u30B0\u7121\u3057 -AddTagAction.newTag=\u65B0\u898F\u30BF\u30B0\u2026 -AddTagAction.tagAndComment=\u30BF\u30B0\u3068\u30B3\u30E1\u30F3\u30C8\u3092\u8FFD\u52A0\u2026 -DeleteBlackboardArtifactTagAction.deleteTags=\u30BF\u30B0\u3092\u524A\u9664 -DeleteBlackboardArtifactTagAction.unableToDelTag.msg=\u30BF\u30B0{0}\u3092\u524A\u9664\u3067\u304D\u307E\u305B\u3093\u3002 -DeleteBlackboardArtifactTagAction.tagDelErr=\u30BF\u30B0\u524A\u9664\u30A8\u30E9\u30FC -DeleteContentTagAction.deleteTags=\u30BF\u30B0\u3092\u524A\u9664 -DeleteContentTagAction.unableToDelTag.msg=\u30BF\u30B0{0}\u3092\u524A\u9664\u3067\u304D\u307E\u305B\u3093\u3002 -DeleteContentTagAction.tagDelErr=\u30BF\u30B0\u306E\u524A\u9664\u30A8\u30E9\u30FC -GetTagNameAndCommentDialog.noTags=\u30BF\u30B0\u7121\u3057 -GetTagNameAndCommentDialog.createTag=\u30BF\u30B0\u3092\u4F5C\u6210 -GetTagNameAndCommentDialog.cancelName=\u30AD\u30E3\u30F3\u30BB\u30EB -GetTagNameDialog.createTag=\u30BF\u30B0\u3092\u4F5C\u6210 -GetTagNameDialog.cancelName=\u30AD\u30E3\u30F3\u30BB\u30EB -GetTagNameDialog.mustSupplyTtagName.msg=\u30BF\u30B0\u540D\u3092\u6307\u5B9A\u3057\u306A\u3051\u308C\u3070\u5148\u306B\u9032\u3081\u307E\u305B\u3093\u3002 -GetTagNameDialog.tagNameErr=\u30BF\u30B0\u540D -GetTagNameDialog.illegalCharsErr=\u4F7F\u7528\u3067\u304D\u306A\u3044\u6587\u5B57 -GetTagNameDialog.unableToAddTagNameToCase.msg=\u30BF\u30B0\u540D{0}\u3092\u30B1\u30FC\u30B9\u306B\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -GetTagNameDialog.taggingErr=\u30BF\u30B0\u4ED8\u3051\u30A8\u30E9\u30FC -GetTagNameDialog.tagNameAlreadyDef.msg=\u30BF\u30B0\u540D{0}\u306F\u65E2\u306B\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u307E\u3059\u3002 -GetTagNameDialog.dupTagErr=\u30BF\u30B0\u306E\u91CD\u8907\u30A8\u30E9\u30FC -AddContentTagAction.cannotApplyTagErr=\u30BF\u30B0\u3092\u9069\u7528\u3067\u304D\u307E\u305B\u3093 -OpenLogFolder.error1=\u30ED\u30B0\u30D5\u30A1\u30A4\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\uFF1A{0} -CTL_OpenLogFolder=\u30ED\u30B0\u30D5\u30A9\u30EB\u30C0\u3092\u958B\u304F -ShowIngestProgressSnapshotAction.actionName.text=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30D7\u30ED\u30B0\u30EC\u30B9\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u3092\u53D6\u5F97 -CTL_OpenPythonModulesFolderAction=Python\u30D7\u30E9\u30B0\u30A4\u30F3 -OpenPythonModulesFolderAction.actionName.text=Python\u30D7\u30E9\u30B0\u30A4\u30F3 -OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python\u30D7\u30E9\u30B0\u30A4\u30F3\u30D5\u30A9\u30EB\u30C0\u30FC\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\uFF1A{0} -AddContentTagAction.tagExists={0}\u306F\u65E2\u306B{1}\u3068\u30BF\u30B0\u3055\u308C\u3066\u3044\u307E\u3059\u3002\u540C\u3058\u30BF\u30B0\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002 -OpenLogFolder.CouldNotOpenLogFolder=\u30ED\u30B0\u30D5\u30A9\u30EB\u30C0\u30FC\u3092\u958B\u3051\u307E\u305B\u3093\u3067\u3057\u305F -CTL_OpenOutputFolder=\u30A2\u30A6\u30C8\u30D7\u30C3\u30C8\u30D5\u30A9\u30EB\u30C0\u3092\u3092\u958B\u304F -OpenOutputFolder.error1=\u6B21\u306E\u30A2\u30A6\u30C8\u30D7\u30C3\u30C8\u30D5\u30A9\u30EB\u30C0\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\uFF1A{0} -OpenOutputFolder.noCaseOpen=\u30AA\u30FC\u30D7\u30F3\u30B1\u30FC\u30B9\u304C\u306A\u3044\u306E\u3067\u3001\u4F5C\u696D\u4E2D\u306E\u30A2\u30A6\u30C8\u30D7\u30C3\u30C8\u30D5\u30A9\u30EB\u30C0\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -GetTagNameDialog.illegalChars.msg=\u4F7F\u7528\u3067\u304D\u306A\u3044\u6587\u5B57\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059\u3002\n\u6B21\u306E\u6587\u5B57\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\uFF1A\\ \: * ? " < > | -OpenOutputFolder.CouldNotOpenOutputFolder=\u30A2\u30A6\u30C8\u30D7\u30C3\u30C8\u30D5\u30A9\u30EB\u30C0\u304C\u304C\u958B\u3051\u307E\u305B\u3093\u3067\u3057\u305F \ No newline at end of file +GetTagNameAndCommentDialog.commentText.toolTipText=\u30bf\u30b0\u306e\u30aa\u30d7\u30b7\u30e7\u30ca\u30eb\u306e\u30b3\u30e1\u30f3\u30c8\u3092\u5165\u529b\u307e\u305f\u306f\u7a7a\u6b04\u306b\u3057\u3066\u304f\u3060\u3055\u3044 +GetTagNameAndCommentDialog.commentLabel.text=\u30b3\u30e1\u30f3\u30c8\uff1a +GetTagNameAndCommentDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb +GetTagNameAndCommentDialog.tagCombo.toolTipText=\u4f7f\u7528\u3059\u308b\u30bf\u30b0\u3092\u9078\u629e +GetTagNameAndCommentDialog.tagLabel.text=\u30bf\u30b0\uff1a +AddBlackboardArtifactTagAction.singularTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0 +AddBlackboardArtifactTagAction.pluralTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0 +AddBlackboardArtifactTagAction.unableToTag.msg={0}\u306b\u30bf\u30b0\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3002 +AddBlackboardArtifactTagAction.taggingErr=\u30bf\u30b0\u4ed8\u3051\u30a8\u30e9\u30fc +AddContentTagAction.singularTagFile=\u30d5\u30a1\u30a4\u30eb\u306b\u30bf\u30b0\u3092\u8ffd\u52a0 +AddContentTagAction.pluralTagFile=\u30d5\u30a1\u30a4\u30eb\u306b\u30bf\u30b0\u3092\u8ffd\u52a0 +AddContentTagAction.unableToTag.msg={0}\u306b\u30bf\u30b0\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3002\u901a\u5e38\u30d5\u30a1\u30a4\u30eb\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002 +AddContentTagAction.unableToTag.msg2={0}\u306b\u30bf\u30b0\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3002 +AddContentTagAction.taggingErr=\u30bf\u30b0\u4ed8\u3051\u30a8\u30e9\u30fc +AddTagAction.quickTag=\u30af\u30a4\u30c3\u30af\u30bf\u30b0 +AddTagAction.noTags=\u30bf\u30b0\u7121\u3057 +AddTagAction.newTag=\u65b0\u898f\u30bf\u30b0\u2026 +AddTagAction.tagAndComment=\u30bf\u30b0\u3068\u30b3\u30e1\u30f3\u30c8\u3092\u8ffd\u52a0\u2026 +GetTagNameAndCommentDialog.noTags=\u30bf\u30b0\u7121\u3057 +GetTagNameAndCommentDialog.createTag=\u30bf\u30b0\u3092\u4f5c\u6210 +GetTagNameAndCommentDialog.cancelName=\u30ad\u30e3\u30f3\u30bb\u30eb +GetTagNameDialog.createTag=\u30bf\u30b0\u3092\u4f5c\u6210 +GetTagNameDialog.cancelName=\u30ad\u30e3\u30f3\u30bb\u30eb +GetTagNameDialog.mustSupplyTtagName.msg=\u30bf\u30b0\u540d\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u5148\u306b\u9032\u3081\u307e\u305b\u3093\u3002 +GetTagNameDialog.tagNameErr=\u30bf\u30b0\u540d +GetTagNameDialog.illegalCharsErr=\u4f7f\u7528\u3067\u304d\u306a\u3044\u6587\u5b57 +GetTagNameDialog.unableToAddTagNameToCase.msg=\u30bf\u30b0\u540d{0}\u3092\u30b1\u30fc\u30b9\u306b\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 +GetTagNameDialog.taggingErr=\u30bf\u30b0\u4ed8\u3051\u30a8\u30e9\u30fc +GetTagNameDialog.tagNameAlreadyDef.msg=\u30bf\u30b0\u540d{0}\u306f\u65e2\u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u3059\u3002 +GetTagNameDialog.dupTagErr=\u30bf\u30b0\u306e\u91cd\u8907\u30a8\u30e9\u30fc +AddContentTagAction.cannotApplyTagErr=\u30bf\u30b0\u3092\u9069\u7528\u3067\u304d\u307e\u305b\u3093 +OpenLogFolder.error1=\u30ed\u30b0\u30d5\u30a1\u30a4\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\uff1a{0} +CTL_OpenLogFolder=\u30ed\u30b0\u30d5\u30a9\u30eb\u30c0\u3092\u958b\u304f +ShowIngestProgressSnapshotAction.actionName.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30d7\u30ed\u30b0\u30ec\u30b9\u306e\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u53d6\u5f97 +CTL_OpenPythonModulesFolderAction=Python\u30d7\u30e9\u30b0\u30a4\u30f3 +OpenPythonModulesFolderAction.actionName.text=Python\u30d7\u30e9\u30b0\u30a4\u30f3 +OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python\u30d7\u30e9\u30b0\u30a4\u30f3\u30d5\u30a9\u30eb\u30c0\u30fc\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\uff1a{0} +AddContentTagAction.tagExists={0}\u306f\u65e2\u306b{1}\u3068\u30bf\u30b0\u3055\u308c\u3066\u3044\u307e\u3059\u3002\u540c\u3058\u30bf\u30b0\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093\u3002 +OpenLogFolder.CouldNotOpenLogFolder=\u30ed\u30b0\u30d5\u30a9\u30eb\u30c0\u30fc\u3092\u958b\u3051\u307e\u305b\u3093\u3067\u3057\u305f +CTL_OpenOutputFolder=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u3092\u3092\u958b\u304f +OpenOutputFolder.error1=\u6b21\u306e\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\uff1a{0} +OpenOutputFolder.noCaseOpen=\u30aa\u30fc\u30d7\u30f3\u30b1\u30fc\u30b9\u304c\u306a\u3044\u306e\u3067\u3001\u4f5c\u696d\u4e2d\u306e\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u3042\u308a\u307e\u305b\u3093\u3002 +GetTagNameDialog.illegalChars.msg=\u4f7f\u7528\u3067\u304d\u306a\u3044\u6587\u5b57\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3059\u3002\n\u6b21\u306e\u6587\u5b57\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093\uff1a\\ \: * ? " < > | +OpenOutputFolder.CouldNotOpenOutputFolder=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u304c\u958b\u3051\u307e\u305b\u3093\u3067\u3057\u305f \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java index 2ce4ebd666..cda4eb39a8 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2016 Basis Technology Corp. + * Copyright 2013-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,26 +20,41 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import java.util.Collection; +import java.util.HashSet; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; +import javafx.application.Platform; +import javafx.scene.control.Alert; import javax.swing.AbstractAction; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this Action allow users to delete tags applied to blackboard * artifacts. */ +@NbBundle.Messages({ + "DeleteBlackboardArtifactTagAction.deleteTag=Delete Tag", + "DeleteBlackboardArtifactTagAction.unableToDelTag.msg=Unable to delete tag {0}.", + "DeleteBlackboardArtifactTagAction.tagDelErr=Tag Deletion Error" +}) public class DeleteBlackboardArtifactTagAction extends AbstractAction { + + private static final Logger LOGGER = Logger.getLogger(DeleteBlackboardArtifactTagAction.class.getName()); private static final long serialVersionUID = 1L; private static final String MENU_TEXT = NbBundle.getMessage(DeleteBlackboardArtifactTagAction.class, - "DeleteBlackboardArtifactTagAction.deleteTags"); + "DeleteBlackboardArtifactTagAction.deleteTag"); // 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 @@ -65,7 +80,7 @@ public class DeleteBlackboardArtifactTagAction extends AbstractAction { try { Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag); } catch (TskCoreException ex) { - Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS + Logger.getLogger(DeleteBlackboardArtifactTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), @@ -81,28 +96,47 @@ public class DeleteBlackboardArtifactTagAction extends AbstractAction { }).start(); } - /** - * Deprecated, use actionPerformed() instead. - * - * @param event The event associated with the action. - * - * @deprecated - */ - @Deprecated - protected void doAction(ActionEvent event) { - actionPerformed(event); + protected String getActionDisplayName() { + return MENU_TEXT; } - /** - * Deprecated, does nothing. The TagManager methods to create, update or - * delete tags now notify the case that there is a tag change. The case then - * publishes an event that triggers a refresh of the tags sub-tree in the - * tree view. - * - * @deprecated - */ - @Deprecated - protected void refreshDirectoryTree() { + @NbBundle.Messages({"# {0} - artifactID", + "DeleteBlackboardArtifactTagAction.deleteTag.alert=Unable to untag artifact {0}."}) + protected void deleteTag(TagName tagName, BlackboardArtifactTag artifactTag, long artifactId) { + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + + // Pull the from the global context to avoid unnecessary calls + // to the database. + final Collection selectedFilesList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + AbstractFile file = selectedFilesList.iterator().next(); + + try { + LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS + tagsManager.deleteBlackboardArtifactTag(artifactTag); + } catch (TskCoreException tskCoreException) { + LOGGER.log(Level.SEVERE, "Error untagging artifact", tskCoreException); //NON-NLS + Platform.runLater(() -> + new Alert(Alert.AlertType.ERROR, Bundle.DeleteBlackboardArtifactTagAction_deleteTag_alert(artifactId)).show() + ); + } + return null; + } + + @Override + protected void done() { + super.done(); + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while untagging artifact", ex); //NON-NLS + } + } + }.execute(); } } diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java index aabc483247..afa7e49506 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2015 Basis Technology Corp. + * Copyright 2013-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,25 +20,40 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import java.util.Collection; +import java.util.HashSet; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; +import javafx.application.Platform; +import javafx.scene.control.Alert; import javax.swing.AbstractAction; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this Action allow users to delete tags applied to content. */ +@NbBundle.Messages({ + "DeleteContentTagAction.deleteTag=Delete Tag", + "DeleteContentTagAction.unableToDelTag.msg=Unable to delete tag {0}.", + "DeleteContentTagAction.tagDelErr=Tag Deletion Error" +}) public class DeleteContentTagAction extends AbstractAction { + + private static final Logger LOGGER = Logger.getLogger(DeleteContentTagAction.class.getName()); private static final long serialVersionUID = 1L; private static final String MENU_TEXT = NbBundle.getMessage(DeleteContentTagAction.class, - "DeleteContentTagAction.deleteTags"); + "DeleteContentTagAction.deleteTag"); // 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 @@ -64,7 +79,7 @@ public class DeleteContentTagAction extends AbstractAction { try { Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag); } catch (TskCoreException ex) { - Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS + Logger.getLogger(DeleteContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS SwingUtilities.invokeLater(() -> { JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), @@ -103,4 +118,47 @@ public class DeleteContentTagAction extends AbstractAction { protected void refreshDirectoryTree() { } + protected String getActionDisplayName() { + return MENU_TEXT; + } + + @NbBundle.Messages({"# {0} - fileID", + "DeleteContentTagAction.deleteTag.alert=Unable to untag file {0}."}) + protected void deleteTag(TagName tagName, ContentTag contentTag, long fileId) { + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + + // Pull the from the global context to avoid unnecessary calls + // to the database. + final Collection selectedFilesList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + AbstractFile file = selectedFilesList.iterator().next(); + + try { + LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS + tagsManager.deleteContentTag(contentTag); + } catch (TskCoreException tskCoreException) { + LOGGER.log(Level.SEVERE, "Error untagging file", tskCoreException); //NON-NLS + Platform.runLater(() -> + new Alert(Alert.AlertType.ERROR, Bundle.DeleteContentTagAction_deleteTag_alert(fileId)).show() + ); + } + return null; + } + + @Override + protected void done() { + super.done(); + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while untagging file", ex); //NON-NLS + } + } + }.execute(); + } + } diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java new file mode 100755 index 0000000000..4c1e52d828 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java @@ -0,0 +1,205 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.actions; + +import java.awt.event.ActionEvent; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import javafx.application.Platform; +import javafx.scene.control.Alert; +import javax.swing.AbstractAction; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import org.openide.util.NbBundle; +import org.openide.util.Utilities; +import org.openide.util.actions.Presenter; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Instances of this Action allow users to delete tags applied to blackboard + * artifacts. + */ +@NbBundle.Messages({ + "DeleteFileBlackboardArtifactTagAction.deleteTag=Remove Result Tag" +}) +public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implements Presenter.Popup { + + private static final Logger LOGGER = Logger.getLogger(DeleteFileBlackboardArtifactTagAction.class.getName()); + + private static final long serialVersionUID = 1L; + private static final String MENU_TEXT = NbBundle.getMessage(DeleteFileBlackboardArtifactTagAction.class, + "DeleteFileBlackboardArtifactTagAction.deleteTag"); + + // 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 DeleteFileBlackboardArtifactTagAction instance; + + public static synchronized DeleteFileBlackboardArtifactTagAction getInstance() { + if (null == instance) { + instance = new DeleteFileBlackboardArtifactTagAction(); + } + return instance; + } + + private DeleteFileBlackboardArtifactTagAction() { + super(MENU_TEXT); + } + + @Override + public JMenuItem getPopupPresenter() { + return new TagMenu(); + } + + @Override + public void actionPerformed(ActionEvent event) { + } + + protected String getActionDisplayName() { + return MENU_TEXT; + } + + @NbBundle.Messages({"# {0} - artifactID", + "DeleteFileBlackboardArtifactTagAction.deleteTag.alert=Unable to untag artifact {0}."}) + protected void deleteTag(TagName tagName, BlackboardArtifactTag artifactTag, long artifactId) { + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + + // Pull the from the global context to avoid unnecessary calls + // to the database. + final Collection selectedFilesList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + AbstractFile file = selectedFilesList.iterator().next(); + + try { + LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS + tagsManager.deleteBlackboardArtifactTag(artifactTag); + } catch (TskCoreException tskCoreException) { + LOGGER.log(Level.SEVERE, "Error untagging artifact", tskCoreException); //NON-NLS + Platform.runLater(() -> + new Alert(Alert.AlertType.ERROR, Bundle.DeleteFileBlackboardArtifactTagAction_deleteTag_alert(artifactId)).show() + ); + } + return null; + } + + @Override + protected void done() { + super.done(); + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while untagging artifact", ex); //NON-NLS + } + } + }.execute(); + } + + /** + * Instances of this class implement a context menu user interface for + * creating or selecting a tag name for a tag and specifying an optional tag + * comment. + */ + // @@@ This user interface has some significant usability issues and needs + // to be reworked. + @NbBundle.Messages({"# {0} - artifactID", + "DeleteFileBlackboardArtifactTagAction.deleteTags.alert=Unable to untag artifact {0}."}) + private class TagMenu extends JMenu { + + private static final long serialVersionUID = 1L; + + TagMenu() { + super(getActionDisplayName()); + + final Collection selectedBlackboardArtifactsList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + + if(!selectedBlackboardArtifactsList.isEmpty()) { + BlackboardArtifact artifact = + selectedBlackboardArtifactsList.iterator().next(); + + // Get the current set of tag names. + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + + Map tagNamesMap = null; + try { + tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap()); + } catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS + } + + // Each tag name in the current set of tags gets its own menu item in + // the "Quick Tags" sub-menu. Selecting one of these menu items adds + // a tag with the associated tag name. + if (null != tagNamesMap && !tagNamesMap.isEmpty()) { + try { + List existingTagsList = + Case.getCurrentCase().getServices().getTagsManager() + .getBlackboardArtifactTagsByArtifact(artifact); + + for (Map.Entry entry : tagNamesMap.entrySet()) { + String tagDisplayName = entry.getKey(); + + TagName tagName = entry.getValue(); + for(BlackboardArtifactTag artifactTag : existingTagsList) { + if(tagDisplayName.equals(artifactTag.getName().getDisplayName())) { + JMenuItem tagNameItem = new JMenuItem(tagDisplayName); + // for the bookmark tag name only, added shortcut label + if (tagDisplayName.equals(NbBundle.getMessage(AddTagAction.class, "AddBookmarkTagAction.bookmark.text"))) { + tagNameItem.setAccelerator(AddBookmarkTagAction.BOOKMARK_SHORTCUT); + } + tagNameItem.addActionListener((ActionEvent e) -> { + deleteTag(tagName, artifactTag, artifact.getArtifactID()); + }); + add(tagNameItem); + } + } + } + } catch (TskCoreException ex) { + Logger.getLogger(TagMenu.class.getName()) + .log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS + } + } + + if(getItemCount() == 0) { + setEnabled(false); + } + } + } + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java new file mode 100755 index 0000000000..0da884c34e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java @@ -0,0 +1,202 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.actions; + +import java.awt.event.ActionEvent; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import javafx.application.Platform; +import javafx.scene.control.Alert; +import javax.swing.AbstractAction; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import org.openide.util.NbBundle; +import org.openide.util.Utilities; +import org.openide.util.actions.Presenter; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Instances of this Action allow users to delete tags applied to content. + */ +@NbBundle.Messages({ + "DeleteFileContentTagAction.deleteTag=Remove File Tag" +}) +public class DeleteFileContentTagAction extends AbstractAction implements Presenter.Popup { + + private static final Logger LOGGER = Logger.getLogger(DeleteFileContentTagAction.class.getName()); + + private static final long serialVersionUID = 1L; + private static final String MENU_TEXT = NbBundle.getMessage(DeleteFileContentTagAction.class, + "DeleteFileContentTagAction.deleteTag"); + + // 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 DeleteFileContentTagAction instance; + + public static synchronized DeleteFileContentTagAction getInstance() { + if (null == instance) { + instance = new DeleteFileContentTagAction(); + } + return instance; + } + + private DeleteFileContentTagAction() { + super(MENU_TEXT); + } + + @Override + public JMenuItem getPopupPresenter() { + return new TagMenu(); + } + + @Override + public void actionPerformed(ActionEvent e) { + } + + protected String getActionDisplayName() { + return MENU_TEXT; + } + + @NbBundle.Messages({"# {0} - fileID", + "DeleteFileContentTagAction.deleteTag.alert=Unable to untag file {0}."}) + protected void deleteTag(TagName tagName, ContentTag contentTag, long fileId) { + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + + // Pull the from the global context to avoid unnecessary calls + // to the database. + final Collection selectedFilesList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + AbstractFile file = selectedFilesList.iterator().next(); + + try { + LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS + tagsManager.deleteContentTag(contentTag); + } catch (TskCoreException tskCoreException) { + LOGGER.log(Level.SEVERE, "Error untagging file", tskCoreException); //NON-NLS + Platform.runLater(() -> + new Alert(Alert.AlertType.ERROR, Bundle.DeleteFileContentTagAction_deleteTag_alert(fileId)).show() + ); + } + return null; + } + + @Override + protected void done() { + super.done(); + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while untagging file", ex); //NON-NLS + } + } + }.execute(); + } + + /** + * Instances of this class implement a context menu user interface for + * creating or selecting a tag name for a tag and specifying an optional tag + * comment. + */ + // @@@ This user interface has some significant usability issues and needs + // to be reworked. + private class TagMenu extends JMenu { + + private static final long serialVersionUID = 1L; + + TagMenu() { + super(getActionDisplayName()); + + final Collection selectedAbstractFilesList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + + if(!selectedAbstractFilesList.isEmpty()) { + AbstractFile file = selectedAbstractFilesList.iterator().next(); + + // Get the current set of tag names. + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + + Map tagNamesMap = null; + try { + tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap()); + } catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS + } + + // Each tag name in the current set of tags gets its own menu item in + // the "Quick Tags" sub-menu. Selecting one of these menu items adds + // a tag with the associated tag name. + if (null != tagNamesMap && !tagNamesMap.isEmpty()) { + try { + /*List existingTagsList = + Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact);*/ + List existingTagsList = + Case.getCurrentCase().getServices().getTagsManager() + .getContentTagsByContent(file); + + for (Map.Entry entry : tagNamesMap.entrySet()) { + String tagDisplayName = entry.getKey(); + + TagName tagName = entry.getValue(); + for(ContentTag contentTag : existingTagsList) { + if(tagDisplayName.equals(contentTag.getName().getDisplayName())) { + JMenuItem tagNameItem = new JMenuItem(tagDisplayName); + // for the bookmark tag name only, added shortcut label + if (tagDisplayName.equals(NbBundle.getMessage(AddTagAction.class, "AddBookmarkTagAction.bookmark.text"))) { + tagNameItem.setAccelerator(AddBookmarkTagAction.BOOKMARK_SHORTCUT); + } + tagNameItem.addActionListener((ActionEvent e) -> { + deleteTag(tagName, contentTag, file.getId()); + }); + add(tagNameItem); + } + } + } + } catch (TskCoreException ex) { + Logger.getLogger(TagMenu.class.getName()) + .log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS + } + } + + if(getItemCount() == 0) { + setEnabled(false); + } + } + } + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java index 7ab744d712..dc1aa9a8bf 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,18 +19,25 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; +import java.util.Collection; +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.actions.AddBlackboardArtifactTagAction; import org.sleuthkit.autopsy.actions.AddContentTagAction; +import org.sleuthkit.autopsy.actions.DeleteFileBlackboardArtifactTagAction; +import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.Directory; @@ -64,129 +71,227 @@ public class DataModelActionsFactory { .getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.srfFileSameMD5.text"); public static List getActions(File file, boolean isArtifactSource) { - List actions = new ArrayList<>(); - actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file)); + List actionsList = new ArrayList<>(); + actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file)); final FileNode fileNode = new FileNode(file); - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, fileNode)); - actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode)); - actions.add(null); // creates a menu separator - actions.add(ExtractAction.getInstance()); - actions.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, fileNode)); - actions.add(null); // creates a menu separator - actions.add(AddContentTagAction.getInstance()); + 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)); + actionsList.add(null); // creates a menu separator + actionsList.add(ExtractAction.getInstance()); + actionsList.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, fileNode)); + actionsList.add(null); // creates a menu separator + actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { - actions.add(AddBlackboardArtifactTagAction.getInstance()); + actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + + 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) { + actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); + } + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; } public static List getActions(SlackFile slackFile, boolean isArtifactSource) { - List actions = new ArrayList<>(); - actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), slackFile)); + List actionsList = new ArrayList<>(); + actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), slackFile)); final SlackFileNode slackFileNode = new SlackFileNode(slackFile); - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, slackFileNode)); - actions.add(null); // creates a menu separator - actions.add(ExtractAction.getInstance()); - actions.add(null); // creates a menu separator - actions.add(AddContentTagAction.getInstance()); + actionsList.add(null); // creates a menu separator + actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, slackFileNode)); + actionsList.add(null); // creates a menu separator + actionsList.add(ExtractAction.getInstance()); + actionsList.add(null); // creates a menu separator + actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { - actions.add(AddBlackboardArtifactTagAction.getInstance()); + actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + + 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) { + actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); + } + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; } public static List getActions(LayoutFile file, boolean isArtifactSource) { - List actions = new ArrayList<>(); - actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file)); + List actionsList = new ArrayList<>(); + actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file)); LayoutFileNode layoutFileNode = new LayoutFileNode(file); - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, layoutFileNode)); - actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, layoutFileNode)); - actions.add(null); // creates a menu separator - actions.add(ExtractAction.getInstance());// - actions.add(null); // creates a menu separator - actions.add(AddContentTagAction.getInstance()); + 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)); + actionsList.add(null); // creates a menu separator + actionsList.add(ExtractAction.getInstance());// + actionsList.add(null); // creates a menu separator + actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { - actions.add(AddBlackboardArtifactTagAction.getInstance()); + actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + + 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) { + actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); + } + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; } public static List getActions(Directory directory, boolean isArtifactSource) { - List actions = new ArrayList<>(); - actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory)); + List actionsList = new ArrayList<>(); + actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory)); DirectoryNode directoryNode = new DirectoryNode(directory); - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode)); - actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode)); - actions.add(null); // creates a menu separator - actions.add(ExtractAction.getInstance()); - actions.add(null); // creates a menu separator - actions.add(AddContentTagAction.getInstance()); + 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)); + actionsList.add(null); // creates a menu separator + actionsList.add(ExtractAction.getInstance()); + actionsList.add(null); // creates a menu separator + actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { - actions.add(AddBlackboardArtifactTagAction.getInstance()); + actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + + 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) { + actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); + } + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; } public static List getActions(VirtualDirectory directory, boolean isArtifactSource) { - List actions = new ArrayList<>(); - actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory)); + List actionsList = new ArrayList<>(); + actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory)); VirtualDirectoryNode directoryNode = new VirtualDirectoryNode(directory); - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode)); - actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode)); - actions.add(null); // creates a menu separator - actions.add(ExtractAction.getInstance()); - actions.add(null); // creates a menu separator - actions.add(AddContentTagAction.getInstance()); + 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)); + actionsList.add(null); // creates a menu separator + actionsList.add(ExtractAction.getInstance()); + actionsList.add(null); // creates a menu separator + actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { - actions.add(AddBlackboardArtifactTagAction.getInstance()); + actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + + 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) { + actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); + } + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; } public static List getActions(LocalFile file, boolean isArtifactSource) { - List actions = new ArrayList<>(); - actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file)); + List actionsList = new ArrayList<>(); + actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file)); final LocalFileNode localFileNode = new LocalFileNode(file); - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode)); - actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode)); - actions.add(null); // creates a menu separator - actions.add(ExtractAction.getInstance()); - actions.add(null); // creates a menu separator - actions.add(AddContentTagAction.getInstance()); + 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)); + actionsList.add(null); // creates a menu separator + actionsList.add(ExtractAction.getInstance()); + actionsList.add(null); // creates a menu separator + actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { - actions.add(AddBlackboardArtifactTagAction.getInstance()); + actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + + 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) { + actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); + } + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; } public static List getActions(DerivedFile file, boolean isArtifactSource) { - List actions = new ArrayList<>(); - actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file)); + List actionsList = new ArrayList<>(); + actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file)); final LocalFileNode localFileNode = new LocalFileNode(file); - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode)); - actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode)); - actions.add(null); // creates a menu separator - actions.add(ExtractAction.getInstance()); - actions.add(null); // creates a menu separator - actions.add(AddContentTagAction.getInstance()); + 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)); + actionsList.add(null); // creates a menu separator + actionsList.add(ExtractAction.getInstance()); + actionsList.add(null); // creates a menu separator + actionsList.add(AddContentTagAction.getInstance()); if (isArtifactSource) { - actions.add(AddBlackboardArtifactTagAction.getInstance()); + actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + + 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) { + actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); + } + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; } public static List getActions(Content content, boolean isArtifactSource) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 59240d204a..68aeb01e8c 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 - 2013 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,11 +19,16 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; +import java.util.Collection; +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.actions.AddContentTagAction; +import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; @@ -37,6 +42,8 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; * are more directories. */ public class DirectoryNode extends AbstractFsContentNode { + + private static final Logger LOGGER = Logger.getLogger(DirectoryNode.class.getName()); public static final String DOTDOTDIR = NbBundle.getMessage(DirectoryNode.class, "DirectoryNode.parFolder.text"); public static final String DOTDIR = NbBundle.getMessage(DirectoryNode.class, "DirectoryNode.curFolder.text"); @@ -71,23 +78,29 @@ public class DirectoryNode extends AbstractFsContentNode { */ @Override public Action[] getActions(boolean popup) { - List actions = new ArrayList<>(); + List actionsList = new ArrayList<>(); for (Action a : super.getActions(true)) { - actions.add(a); + actionsList.add(a); } if (!getDirectoryBrowseMode()) { - actions.add(new ViewContextAction( + actionsList.add(new ViewContextAction( NbBundle.getMessage(this.getClass(), "DirectoryNode.getActions.viewFileInDir.text"), this)); - actions.add(null); // creates a menu separator + actionsList.add(null); // creates a menu separator } - actions.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "DirectoryNode.viewInNewWin.text"), this)); - actions.add(ViewFileInTimelineAction.createViewFileAction(getContent())); - actions.add(null); // creates a menu separator - actions.add(ExtractAction.getInstance()); - actions.add(null); // creates a menu separator - actions.add(AddContentTagAction.getInstance()); - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions.toArray(new Action[actions.size()]); + actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "DirectoryNode.viewInNewWin.text"), this)); + actionsList.add(ViewFileInTimelineAction.createViewFileAction(getContent())); + 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()); + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList.toArray(new Action[actionsList.size()]); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 7ee5acf08f..10ba139efd 100755 --- 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-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,13 +19,18 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import javax.swing.Action; import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle; +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.coreutils.ImageUtils; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -41,6 +46,8 @@ 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()); /** * Constructor @@ -96,6 +103,12 @@ public class FileNode extends AbstractFsContentNode { actionsList.add(new HashSearchAction(Bundle.FileNode_getActions_searchFilesSameMD5_text(), this)); 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()); + } + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[actionsList.size()]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index 495737488b..c759b425d7 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-2014 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,17 +19,22 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; +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.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.TskData; @@ -121,6 +126,13 @@ public class LayoutFileNode extends AbstractAbstractFileNode { 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()); + } + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index ecccb26272..5738356c46 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2016 Basis Technology Corp. + * Copyright 2013-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,14 +20,19 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; +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.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -39,6 +44,8 @@ import org.sleuthkit.datamodel.AbstractFile; * A Node for a LocalFile or DerivedFile content object. */ public class LocalFileNode extends AbstractAbstractFileNode { + + private static final Logger LOGGER = Logger.getLogger(LocalFileNode.class.getName()); public LocalFileNode(AbstractFile af) { super(af); @@ -98,6 +105,13 @@ public class LocalFileNode extends AbstractAbstractFileNode { NbBundle.getMessage(this.getClass(), "LocalFileNode.getActions.searchFilesSameMd5.text"), this)); 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()); + } + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java index 863de3d9d8..742b75ddcb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SlackFileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,10 +19,14 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; +import java.util.Collection; +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.actions.AddContentTagAction; +import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; @@ -84,6 +88,13 @@ 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) { + actionsList.add(DeleteFileContentTagAction.getInstance()); + } + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[actionsList.size()]); } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 81820218ec..58cba4102f 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.directorytree; import java.awt.event.ActionEvent; import java.beans.PropertyVetoException; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.logging.Level; import java.util.prefs.PreferenceChangeEvent; @@ -33,8 +35,11 @@ import org.openide.nodes.FilterNode; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; +import org.openide.util.Utilities; import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction; import org.sleuthkit.autopsy.actions.AddContentTagAction; +import org.sleuthkit.autopsy.actions.DeleteFileBlackboardArtifactTagAction; +import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.Logger; @@ -70,6 +75,8 @@ import org.sleuthkit.datamodel.VirtualDirectory; * defines the actions that the node should have. */ public class DataResultFilterNode extends FilterNode { + + private static final Logger LOGGER = Logger.getLogger(DataResultFilterNode.class.getName()); private static boolean filterKnownFromDataSources = UserPreferences.hideKnownFilesInDataSourcesTree(); private static boolean filterKnownFromViews = UserPreferences.hideKnownFilesInViewsTree(); @@ -260,29 +267,29 @@ public class DataResultFilterNode extends FilterNode { //they should be set in individual Node subclass and using a utility to get Actions per Content sub-type // TODO UPDATE: There is now a DataModelActionsFactory utility; - List actions = new ArrayList<>(); + List actionsList = new ArrayList<>(); //merge predefined specific node actions if bban subclasses have their own for (Action a : ban.getActions(true)) { - actions.add(a); + actionsList.add(a); } BlackboardArtifact ba = ban.getLookup().lookup(BlackboardArtifact.class); final int artifactTypeID = ba.getArtifactTypeID(); if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID() || artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) { - actions.add(new ViewContextAction( + actionsList.add(new ViewContextAction( NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), ban)); } else { // if the artifact links to another file, add an action to go to // that file Content c = findLinked(ban); if (c != null) { - actions.add(new ViewContextAction( + actionsList.add(new ViewContextAction( NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), c)); } // action to go to the source file of the artifact - actions.add(new ViewContextAction( + actionsList.add(new ViewContextAction( NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewSrcFileInDir.text"), ban)); } Content c = ban.getLookup().lookup(File.class); @@ -304,28 +311,44 @@ public class DataResultFilterNode extends FilterNode { n = new SlackFileNode((SlackFile) c); } if (n != null) { - actions.add(null); // creates a menu separator - actions.add(new NewWindowViewAction( + actionsList.add(null); // creates a menu separator + actionsList.add(new NewWindowViewAction( NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewInNewWin.text"), n)); - actions.add(new ExternalViewerAction( + actionsList.add(new ExternalViewerAction( NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.openInExtViewer.text"), n)); - actions.add(null); // creates a menu separator - actions.add(ExtractAction.getInstance()); + actionsList.add(null); // creates a menu separator + actionsList.add(ExtractAction.getInstance()); if (md5Action) { - actions.add(new HashSearchAction( + actionsList.add(new HashSearchAction( NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.searchFilesSameMd5.text"), n)); } - actions.add(null); // creates a menu separator - actions.add(AddContentTagAction.getInstance()); - actions.add(AddBlackboardArtifactTagAction.getInstance()); - actions.addAll(ContextMenuExtensionPoint.getActions()); + 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()); + } } else { // There's no specific file associated with the artifact, but // we can still tag the artifact itself - actions.add(null); - actions.add(AddBlackboardArtifactTagAction.getInstance()); + actionsList.add(null); + actionsList.add(AddBlackboardArtifactTagAction.getInstance()); } - return actions; + + final Collection selectedArtifactsList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); + if(selectedArtifactsList.size() == 1) { + actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance()); + } + + if(n != null) { + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + } + + return actionsList; } @Override diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java index 27cc6dbcca..86c3df1fe3 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2014 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,13 +19,18 @@ package org.sleuthkit.autopsy.directorytree; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import org.openide.util.NbBundle; +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.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.DerivedFile; @@ -85,48 +90,82 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final Directory d) { - List actions = new ArrayList<>(); - actions.add(AddContentTagAction.getInstance()); - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + List actionsList = new ArrayList<>(); + actionsList.add(AddContentTagAction.getInstance()); + + final Collection selectedFilesList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if(selectedFilesList.size() == 1) { + actionsList.add(DeleteFileContentTagAction.getInstance()); + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; } @Override public List visit(final VirtualDirectory d) { - List actions = new ArrayList<>(); + List actionsList = new ArrayList<>(); if (!d.isDataSource()) { - actions.add(AddContentTagAction.getInstance()); + actionsList.add(AddContentTagAction.getInstance()); + + final Collection selectedFilesList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if(selectedFilesList.size() == 1) { + actionsList.add(DeleteFileContentTagAction.getInstance()); + } } - actions.add(ExtractAction.getInstance()); - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + actionsList.add(ExtractAction.getInstance()); + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; } @Override public List visit(final DerivedFile d) { - List actions = new ArrayList<>(); - actions.add(ExtractAction.getInstance()); - actions.add(AddContentTagAction.getInstance()); - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + List 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) { + actionsList.add(DeleteFileContentTagAction.getInstance()); + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; } @Override public List visit(final LocalFile d) { - List actions = new ArrayList<>(); - actions.add(ExtractAction.getInstance()); - actions.add(AddContentTagAction.getInstance()); - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + List 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) { + actionsList.add(DeleteFileContentTagAction.getInstance()); + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; } @Override public List visit(final org.sleuthkit.datamodel.File d) { - List actions = new ArrayList<>(); - actions.add(ExtractAction.getInstance()); - actions.add(AddContentTagAction.getInstance()); - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + List 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) { + actionsList.add(DeleteFileContentTagAction.getInstance()); + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java new file mode 100755 index 0000000000..5fc73fc656 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java @@ -0,0 +1,164 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery.actions; + +import java.awt.Window; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import javafx.application.Platform; +import javafx.scene.control.Alert; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; +import javafx.scene.image.ImageView; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import org.controlsfx.control.action.Action; +import org.controlsfx.control.action.ActionUtils; +import org.openide.util.NbBundle; +import org.openide.util.Utilities; +import org.openide.windows.TopComponent; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Instances of this Action allow users to remove tags from content. + */ +public class DeleteTagAction extends Action { + + private static final Logger LOGGER = Logger.getLogger(DeleteTagAction.class.getName()); + + private final ImageGalleryController controller; + private final long fileId; + private final TagName tagName; + private final ContentTag contentTag; + + public DeleteTagAction(ImageGalleryController controller, TagName tagName, ContentTag contentTag, long fileId) { + super(tagName.getDisplayName()); + this.controller = controller; + this.fileId = fileId; + this.tagName = tagName; + this.contentTag = contentTag; + setGraphic(controller.getTagsManager().getGraphic(tagName)); + setText(tagName.getDisplayName()); + setEventHandler(actionEvent -> deleteTag()); + } + + static public Menu getTagMenu(ImageGalleryController controller) { + return new TagMenu(controller); + } + + @NbBundle.Messages({"# {0} - fileID", + "DeleteDrawableTagAction.deleteTag.alert=Unable to untag file {0}."}) + private void deleteTag() { + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + DrawableTagsManager tagsManager = controller.getTagsManager(); + + // Pull the from the global context to avoid unnecessary calls + // to the database. + final Collection selectedFilesList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + AbstractFile file = selectedFilesList.iterator().next(); + + try { + LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS + tagsManager.deleteContentTag(contentTag); + } catch (TskCoreException tskCoreException) { + LOGGER.log(Level.SEVERE, "Error untagging file", tskCoreException); //NON-NLS + Platform.runLater(() -> + new Alert(Alert.AlertType.ERROR, Bundle.DeleteDrawableTagAction_deleteTag_alert(fileId)).show() + ); + } + return null; + } + + @Override + protected void done() { + super.done(); + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while untagging file", ex); //NON-NLS + } + } + }.execute(); + } + + @NbBundle.Messages({"DeleteDrawableTagAction.displayName=Remove File Tag"}) + private static class TagMenu extends Menu { + + TagMenu(ImageGalleryController controller) { + setGraphic(new ImageView(DrawableAttribute.TAGS.getIcon())); + setText(Bundle.DeleteDrawableTagAction_displayName()); + + // For this menu, we shouldn't have more than one file selected. + // Therefore, we will simply grab the first file and work with that. + final Collection selectedFilesList = + new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + AbstractFile file = selectedFilesList.iterator().next(); + + try { + List existingTagsList = + Case.getCurrentCase().getServices().getTagsManager() + .getContentTagsByContent(file); + + Collection tagNamesList = + controller.getTagsManager().getNonCategoryTagNames(); + Iterator tagNameIterator = tagNamesList.iterator(); + for(int i=0; tagNameIterator.hasNext(); i++) { + TagName tagName = tagNameIterator.next(); + for(ContentTag contentTag : existingTagsList) { + if(contentTag.getName().getId() == tagName.getId()) { + DeleteTagAction deleteDrawableTagAction = new DeleteTagAction(controller, tagName, contentTag, file.getId()); + MenuItem tagNameItem = ActionUtils.createMenuItem(deleteDrawableTagAction); + getItems().add(tagNameItem); + } + } + } + } catch (TskCoreException ex) { + Logger.getLogger(TagMenu.class.getName()) + .log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS + } + + if(getItems().isEmpty()) { + setDisable(true); + } + } + } + + static private Window getIGWindow() { + TopComponent etc = WindowManager.getDefault().findTopComponent(ImageGalleryTopComponent.PREFERRED_ID); + return SwingUtilities.getWindowAncestor(etc); + } +} 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 d9f93fe03c..243045d789 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-16 Basis Technology Corp. + * Copyright 2013-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.eventbus.Subscribe; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; @@ -49,6 +50,7 @@ import javax.swing.SwingUtilities; import org.controlsfx.control.action.ActionUtils; import org.openide.util.Lookup; import org.openide.util.NbBundle; +import org.openide.util.Utilities; import org.openide.util.actions.Presenter; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; @@ -66,10 +68,12 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.actions.AddTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; +import org.sleuthkit.autopsy.imagegallery.actions.DeleteTagAction; import org.sleuthkit.autopsy.imagegallery.actions.OpenExternalViewerAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -184,6 +188,11 @@ public abstract class DrawableTileBase extends DrawableUIBase { menuItems.add(CategorizeAction.getCategoriesMenu(getController())); menuItems.add(AddTagAction.getTagMenu(getController())); + + final Collection selectedFilesList = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); + if(selectedFilesList.size() == 1) { + menuItems.add(DeleteTagAction.getTagMenu(getController())); + } final MenuItem extractMenuItem = new MenuItem(Bundle.DrawableTileBase_menuItem_extractFiles()); extractMenuItem.setOnAction(actionEvent -> { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index 7e147c1ba6..47b36de0be 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -19,6 +19,8 @@ package org.sleuthkit.autopsy.keywordsearch; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import javax.swing.Action; import org.openide.nodes.FilterNode; @@ -26,14 +28,17 @@ import org.openide.nodes.Node; import org.openide.nodes.Node.Property; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; +import org.openide.util.Utilities; import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.actions.AddContentTagAction; +import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.DerivedFile; @@ -107,16 +112,23 @@ class KeywordSearchFilterNode extends FilterNode { } private List getFileActions() { - List actions = new ArrayList<>(); - actions.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl"), KeywordSearchFilterNode.this)); - actions.add(new ExternalViewerAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.openExternViewActLbl"), getOriginal())); - actions.add(null); - actions.add(ExtractAction.getInstance()); - actions.add(new HashSearchAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.searchSameMd5"), getOriginal())); - actions.add(null); // creates a menu separator - actions.add(AddContentTagAction.getInstance()); - actions.addAll(ContextMenuExtensionPoint.getActions()); - return actions; + List actionsList = new ArrayList<>(); + actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl"), KeywordSearchFilterNode.this)); + actionsList.add(new ExternalViewerAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.openExternViewActLbl"), getOriginal())); + actionsList.add(null); + actionsList.add(ExtractAction.getInstance()); + actionsList.add(new HashSearchAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.searchSameMd5"), getOriginal())); + 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()); + } + + actionsList.addAll(ContextMenuExtensionPoint.getActions()); + return actionsList; } @Override