From b65a9e6d5a61b2bbd5c46bed886d42d9f6d9807f Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 16 Oct 2013 18:26:32 -0400 Subject: [PATCH] Added delete tag capability to new tags api --- .../AddBlackboardArtifactTagAction.java | 2 +- .../autopsy/actions/AddContentTagAction.java | 2 +- .../autopsy/actions/AddTagAction.java | 24 +- .../DeleteBlackboardArtifactTagAction.java | 67 +++ .../actions/DeleteContentTagAction.java | 66 +++ .../sleuthkit/autopsy/actions/TagAction.java | 62 +++ .../casemodule/services/TagsManager.java | 336 +++++++------- .../datamodel/AbstractContentChildren.java | 5 - .../autopsy/datamodel/AutopsyItemVisitor.java | 7 - .../datamodel/BlackboardArtifactTagNode.java | 11 + .../autopsy/datamodel/ContentTagNode.java | 11 + .../autopsy/datamodel/ContentTagTypeNode.java | 2 +- .../datamodel/DisplayableItemNodeVisitor.java | 24 - .../autopsy/datamodel/ResultsNode.java | 1 - .../datamodel/RootContentChildren.java | 17 +- .../org/sleuthkit/autopsy/datamodel/Tags.java | 411 +----------------- .../sleuthkit/autopsy/datamodel/TagsNode.java | 6 +- .../BlackboardArtifactTagTypeNode.java | 2 +- .../directorytree/DataResultFilterNode.java | 12 - 19 files changed, 432 insertions(+), 636 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java create mode 100755 Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java create mode 100755 Core/src/org/sleuthkit/autopsy/actions/TagAction.java diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java index 303a773e17..d81e978bc1 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java @@ -46,6 +46,7 @@ public class AddBlackboardArtifactTagAction extends AddTagAction { } private AddBlackboardArtifactTagAction() { + super(""); } @Override @@ -57,7 +58,6 @@ public class AddBlackboardArtifactTagAction extends AddTagAction { protected void addTag(TagName tagName, String comment) { Collection selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); for (BlackboardArtifact artifact : selectedArtifacts) { - Tags.createTag(artifact, tagName.getDisplayName(), comment); //RJCTODO: Jettision this try { Case.getCurrentCase().getServices().getTagsManager().addBlackboardArtifactTag(artifact, tagName, comment); } diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java index 813fde02af..1483ce36c9 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java @@ -46,6 +46,7 @@ public class AddContentTagAction extends AddTagAction { } private AddContentTagAction() { + super(""); } @Override @@ -57,7 +58,6 @@ public class AddContentTagAction extends AddTagAction { protected void addTag(TagName tagName, String comment) { Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); for (AbstractFile file : selectedFiles) { - Tags.createTag(file, tagName.getDisplayName(), comment); //RJCTODO: Jettision this try { Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment); } diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index a98b94b0c4..1532a573d2 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -35,16 +35,20 @@ import org.sleuthkit.datamodel.TagName; * An abstract base class for Actions that allow users to tag SleuthKit data * model objects. */ -abstract class AddTagAction extends AbstractAction implements Presenter.Popup { +abstract class AddTagAction extends TagAction implements Presenter.Popup { private static final String NO_COMMENT = ""; + AddTagAction(String menuText) { + super(menuText); + } + @Override public JMenuItem getPopupPresenter() { return new TagMenu(); } @Override - public void actionPerformed(ActionEvent e) { + protected void doAction(ActionEvent event) { } /** @@ -59,14 +63,6 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { */ abstract protected void addTag(TagName tagName, String comment); - private void refreshDirectoryTree() { - //TODO instead should send event to node children, which will call its refresh() / refreshKeys() - // RJCTODO: Explain what is going on here and pare to one refreshTree() call. - DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance(); - viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); - viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); - } - /** * 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 @@ -90,7 +86,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { // 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 (tagNames.isEmpty()) { + if (!tagNames.isEmpty()) { for (final TagName tagName : tagNames) { JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName()); tagNameItem.addActionListener(new ActionListener() { @@ -114,7 +110,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { // The "Quick Tag" menu also gets an "Choose Tag..." menu item. // Selecting this item initiates a dialog that can be used to create // or select a tag name and adds a tag with the resulting name. - JMenuItem newTagMenuItem = new JMenuItem("Choose Tag..."); + JMenuItem newTagMenuItem = new JMenuItem("New Tag..."); newTagMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -127,10 +123,10 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { }); quickTagMenu.add(newTagMenuItem); - // Create a "Choose Tag and Comment..." menu item. Selecting this itme initiates + // Create a "Choose Tag and Comment..." menu item. Selecting this item initiates // a dialog that can be used to create or select a tag name with an // optional comment and adds a tag with the resulting name. - JMenuItem tagAndCommentItem = new JMenuItem("Choose Tag and Comment..."); + JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment..."); tagAndCommentItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java new file mode 100755 index 0000000000..67891305da --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java @@ -0,0 +1,67 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.logging.Level; +import java.util.logging.Logger; +import javax.swing.JOptionPane; +import org.openide.util.Utilities; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Instances of this Action allow users to delete tags applied to blackboard artifacts. + */ +public class DeleteBlackboardArtifactTagAction extends TagAction { + private static final String MENU_TEXT = "Delete Tag(s)"; + + // 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 DeleteBlackboardArtifactTagAction instance; + + public static synchronized DeleteBlackboardArtifactTagAction getInstance() { + if (null == instance) { + instance = new DeleteBlackboardArtifactTagAction(); + } + return instance; + } + + private DeleteBlackboardArtifactTagAction() { + super(MENU_TEXT); + } + + @Override + protected void doAction(ActionEvent event) { + Collection selectedTags = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactTag.class); + for (BlackboardArtifactTag tag : selectedTags) { + try { + Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag); + } + catch (TskCoreException ex) { + Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); + JOptionPane.showMessageDialog(null, "Unable to delete tag " + tag.getName() + ".", "Tag Deletion Error", JOptionPane.ERROR_MESSAGE); + } + } + } +} + diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java new file mode 100755 index 0000000000..fd0f6a41dc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java @@ -0,0 +1,66 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.logging.Level; +import java.util.logging.Logger; +import javax.swing.JOptionPane; +import org.openide.util.Utilities; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Instances of this Action allow users to delete tags applied to content. + */ +public class DeleteContentTagAction extends TagAction { + private static final String MENU_TEXT = "Delete Tag(s)"; + + // 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 DeleteContentTagAction instance; + + public static synchronized DeleteContentTagAction getInstance() { + if (null == instance) { + instance = new DeleteContentTagAction(); + } + return instance; + } + + private DeleteContentTagAction() { + super(MENU_TEXT); + } + + @Override + protected void doAction(ActionEvent e) { + Collection selectedTags = Utilities.actionsGlobalContext().lookupAll(ContentTag.class); + for (ContentTag tag : selectedTags) { + try { + Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag); + } + catch (TskCoreException ex) { + Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); + JOptionPane.showMessageDialog(null, "Unable to delete tag " + tag.getName() + ".", "Tag Deletion Error", JOptionPane.ERROR_MESSAGE); + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagAction.java b/Core/src/org/sleuthkit/autopsy/actions/TagAction.java new file mode 100755 index 0000000000..d5d78550f1 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/TagAction.java @@ -0,0 +1,62 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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 javax.swing.AbstractAction; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; +import org.sleuthkit.datamodel.BlackboardArtifact; + +/** + * Abstract base class for Actions involving tags. + */ +public abstract class TagAction extends AbstractAction { + public TagAction(String menuText) { + super(menuText); + } + + @Override + public void actionPerformed(ActionEvent event) { + doAction(event); + refreshDirectoryTree(); + } + + /** + * Derived classes must implement this Template Method for actionPerformed(). + * @param event ActionEvent object passed to actionPerformed() + */ + abstract protected void doAction(ActionEvent event); + + /** + * Derived classes should call this method any time a tag is created, updated + * or deleted outside of an actionPerformed() call. + */ + protected void refreshDirectoryTree() { + // The way the "directory tree" currently works, a new tags sub-tree + // needs to be made to reflect the results of invoking tag Actions. The + // way to do this is to call DirectoryTreeTopComponent.refreshTree(), + // which calls RootContentChildren.refreshKeys(BlackboardArtifact.ARTIFACT_TYPE... types) + // for the RootContentChildren object that is the child factory for the + // ResultsNode that is the root of the tags sub-tree. There is a switch + // statement in RootContentChildren.refreshKeys() that maps both + // BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE and BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT + // to making a call to refreshKey(TagsNodeKey). + DirectoryTreeTopComponent.findInstance().refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 2f113dec83..afab0a237b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -37,20 +37,105 @@ import org.sleuthkit.datamodel.TskCoreException; /** * A singleton instance of this class functions as an Autopsy service that - * manages the creation, updating, and deletion of tags applied to Content and - * BlackboardArtifacts objects by users. + * manages the creation, updating, and deletion of tags applied to content and + * blackboard artifacts by users. */ public class TagsManager implements Closeable { - private static final String TAGS_SETTINGS_FILE_NAME = "tags"; - private static final String TAG_NAMES_SETTING_KEY = "tagNames"; + private static final String TAGS_SETTINGS_NAME = "Tags"; + private static final String TAG_NAMES_SETTING_KEY = "TagNames"; + private static final TagName[] predefinedTagNames = new TagName[]{new TagName("Bookmark", "", TagName.HTML_COLOR.NONE)}; private final SleuthkitCase tskCase; private final HashMap tagNames = new HashMap<>(); + private final Object lock = new Object(); + // Use this exception and the member hash map to manage uniqueness of hash + // names. This is deemed more proactive and informative than leaving this to + // the UNIQUE constraint on the display_name field of the tag_names table in + // the case database. + public class TagNameAlreadyExistsException extends Exception { + } + + /** + * Package-scope constructor for use of Services class. An instance of + * TagsManager should be created for each case that is opened. + * @param [in] tskCase The SleuthkitCase object for the current case. + */ TagsManager(SleuthkitCase tskCase) { this.tskCase = tskCase; - loadTagNamesFromTagSettings(); + getExistingTagNames(); + saveTagNamesToTagsSettings(); } - + + private void getExistingTagNames() { + getTagNamesFromCurrentCase(); + getTagNamesFromTagsSettings(); + getPredefinedTagNames(); + } + + private void getTagNamesFromCurrentCase() { + try { + ArrayList currentTagNames = new ArrayList<>(); + tskCase.getAllTagNames(currentTagNames); + for (TagName tagName : currentTagNames) { + tagNames.put(tagName.getDisplayName(), tagName); + } + } + catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); + } + } + + private void getTagNamesFromTagsSettings() { + String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); + if (null != setting && !setting.isEmpty()) { + // Read the tag name setting and break it into tag name tuples. + List tagNameTuples = Arrays.asList(setting.split(";")); + + // Parse each tuple and add the tag names to the current case, one + // at a time to gracefully discard any duplicates or corrupt tuples. + for (String tagNameTuple : tagNameTuples) { + String[] tagNameAttributes = tagNameTuple.split(","); + if (!tagNames.containsKey(tagNameAttributes[0])) { + TagName tagName = new TagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2])); + addTagName(tagName, "Failed to add " + tagName.getDisplayName() + " tag name from tag settings to the current case"); + } + } + } + } + + private void getPredefinedTagNames() { + for (TagName tagName : predefinedTagNames) { + if (!tagNames.containsKey(tagName.getDisplayName())) { + addTagName(tagName, "Failed to add predefined " + tagName.getDisplayName() + " tag name to the current case"); + } + } + } + + private void addTagName(TagName tagName, String errorMessage) { + try { + tskCase.addTagName(tagName); + tagNames.put(tagName.getDisplayName(), tagName); + } + catch(TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, errorMessage, ex); + } + } + + private void saveTagNamesToTagsSettings() { + if (!tagNames.isEmpty()) { + StringBuilder setting = new StringBuilder(); + for (TagName tagName : tagNames.values()) { + if (setting.length() != 0) { + setting.append(";"); + } + setting.append(tagName.getDisplayName()).append(","); + setting.append(tagName.getDescription()).append(","); + setting.append(tagName.getColor().name()); + } + ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); + } + } + /** * Gets a list of all tag names currently available for tagging content or * blackboard artifacts. @@ -67,27 +152,35 @@ public class TagsManager implements Closeable { } /** - * RJCTODO: Discard or properly comment + * Gets a list of all tag names currently used for tagging content or + * blackboard artifacts. + * @return [out] A list, possibly empty, of TagName data transfer objects (DTOs). + */ + public void getTagNamesInUse(List tagNames) { + try { + tagNames.clear(); + tskCase.getTagNamesInUse(tagNames); + } + catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names from the current case", ex); + } + } + + /** + * Checks whether a tag name with a given display name exists. + * @param [in] tagDisplayName The display name for which to check. + * @return True if the tag name exists, false otherwise. */ public boolean tagNameExists(String tagDisplayName) { - return tagNames.containsKey(tagDisplayName); + synchronized(lock) { + return tagNames.containsKey(tagDisplayName); + } } - /** - * RJCTODO: Discard or properly comment - */ - public TagName getTagName(String tagDisplayName) { - if (!tagNames.containsKey(tagDisplayName)) { - // RJCTODO: Throw exception - } - - return tagNames.get(tagDisplayName); - } - /** * Adds a new tag name to the current case and to the tags settings file. - * @param displayName The display name for the new tag name. - * @return A TagName object representing the new tag name on success, null on failure. + * @param [in] displayName The display name for the new tag name. + * @return A TagName data transfer object (DTO) representing the new tag name. * @throws TskCoreException */ public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException { @@ -96,9 +189,9 @@ public class TagsManager implements Closeable { /** * Adds a new tag name to the current case and to the tags settings file. - * @param displayName The display name for the new tag name. - * @param description The description for the new tag name. - * @return A TagName object representing the new tag name on success, null on failure. + * @param [in] displayName The display name for the new tag name. + * @param [in] description The description for the new tag name. + * @return A TagName data transfer object (DTO) representing the new tag name. * @throws TskCoreException */ public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException { @@ -107,31 +200,34 @@ public class TagsManager implements Closeable { /** * Adds a new tag name to the current case and to the tags settings file. - * @param displayName The display name for the new tag name. - * @param description The description for the new tag name. - * @param color The HTML color to associate with the new tag name. - * @return A TagName object representing the new tag name. + * @param [in] displayName The display name for the new tag name. + * @param [in] description The description for the new tag name. + * @param [in] color The HTML color to associate with the new tag name. + * @return A TagName data transfer object (DTO) representing the new tag name. * @throws TskCoreException */ public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { - if (tagNames.containsKey(displayName)) { - throw new TagNameAlreadyExistsException(); - } + synchronized(lock) { + if (tagNames.containsKey(displayName)) { + throw new TagNameAlreadyExistsException(); + } + + // Add the tag name to the case. + TagName newTagName = new TagName(displayName, description, color); + tskCase.addTagName(newTagName); + + // Add the tag name to the tags settings. + tagNames.put(newTagName.getDisplayName(), newTagName); + saveTagNamesToTagsSettings(); + + return newTagName; + } + } - TagName newTagName = new TagName(displayName, description, color); - tskCase.addTagName(newTagName); - tagNames.put(newTagName.getDisplayName(), newTagName); - saveTagNamesToTagsSettings(); - return newTagName; - } - - public class TagNameAlreadyExistsException extends Exception { - } - /** - * Tags a Content object. - * @param content The Content to tag. - * @param tagName The type of tag to add. + * Tags a content object. + * @param [in] content The content to tag. + * @param [in] tagName The name to use for the tag. * @throws TskCoreException */ public void addContentTag(Content content, TagName tagName) throws TskCoreException { @@ -139,10 +235,10 @@ public class TagsManager implements Closeable { } /** - * Tags a Content object. - * @param content The Content to tag. - * @param tagName The name to use for the tag. - * @param comment A comment to store with the tag. + * Tags a content object. + * @param [in] content The content to tag. + * @param [in] tagName The name to use for the tag. + * @param [in] comment A comment to store with the tag. * @throws TskCoreException */ public void addContentTag(Content content, TagName tagName, String comment) throws TskCoreException { @@ -150,12 +246,12 @@ public class TagsManager implements Closeable { } /** - * Tags a Content object or a portion of a content object. - * @param content The Content to tag. - * @param tagName The name to use for the tag. - * @param comment A comment to store with the tag. - * @param beginByteOffset Designates the beginning of a tagged extent. - * @param endByteOffset Designates the end of a tagged extent. + * Tags a content object or a portion of a content object. + * @param [in] content The content to tag. + * @param [in] tagName The name to use for the tag. + * @param [in] comment A comment to store with the tag. + * @param [in] beginByteOffset Designates the beginning of a tagged extent. + * @param [in] endByteOffset Designates the end of a tagged extent. * @throws TskCoreException */ public void addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { @@ -176,7 +272,7 @@ public class TagsManager implements Closeable { /** * Deletes a content tag. - * @param tag The tag to delete. + * @param [in] tag The tag to delete. * @throws TskCoreException */ public void deleteContentTag(ContentTag tag) throws TskCoreException { @@ -184,36 +280,11 @@ public class TagsManager implements Closeable { } /** - * Tags a BlackboardArtifact object. - * @param artifact The BlackboardArtifact to tag. - * @param tagName The name to use for the tag. - * @throws TskCoreException + * Gets content tags by tag name. + * @param [in] tagName The tag name of interest. + * @return A list, possibly empty, of the content tags with the specified tag name. */ - public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException { - addBlackboardArtifactTag(artifact, tagName, ""); - } - - /** - * Tags a BlackboardArtifact object. - * @param artifact The BlackboardArtifact to tag. - * @param tagName The name to use for the tag. - * @param comment A comment to store with the tag. - * @throws TskCoreException - */ - public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { - tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tskCase.getContentById(artifact.getObjectID()), tagName, comment)); - } - - void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { - tskCase.deleteBlackboardArtifactTag(tag); - } - - /** - * RJCTODO - * @param tagName - * @return - */ - public void getContentTags(TagName tagName, List tags) { + public void getContentTagsByTagName(TagName tagName, List tags) { try { tskCase.getContentTagsByTagName(tagName, tags); } @@ -221,13 +292,43 @@ public class TagsManager implements Closeable { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get content tags from the current case", ex); } } - + /** - * RJCTODO - * @param tagName - * @return + * Tags a blackboard artifact object. + * @param [in] artifact The blackboard artifact to tag. + * @param [in] tagName The name to use for the tag. + * @throws TskCoreException */ - public void getBlackboardArtifactTags(TagName tagName, List tags) { + public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException { + addBlackboardArtifactTag(artifact, tagName, ""); + } + + /** + * Tags a blackboard artifact object. + * @param [in] artifact The blackboard artifact to tag. + * @param [in] tagName The name to use for the tag. + * @param [in] comment A comment to store with the tag. + * @throws TskCoreException + */ + public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { + tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tskCase.getContentById(artifact.getObjectID()), tagName, comment)); + } + + /** + * Deletes a blackboard artifact tag. + * @param [in] tag The tag to delete. + * @throws TskCoreException + */ + public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { + tskCase.deleteBlackboardArtifactTag(tag); + } + + /** + * Gets blackboard artifact tags by tag name. + * @param [in] tagName The tag name of interest. + * @return A list, possibly empty, of the content tags with the specified tag name. + */ + public void getBlackboardArtifactTagsByTagName(TagName tagName, List tags) { try { tskCase.getBlackboardArtifactTagsByTagName(tagName, tags); } @@ -239,62 +340,5 @@ public class TagsManager implements Closeable { @Override public void close() throws IOException { saveTagNamesToTagsSettings(); - } - - private void loadTagNamesFromTagSettings() { - // Get any tag names already defined for the current case. - try { - ArrayList currentTagNames = new ArrayList<>(); - tskCase.getAllTagNames(currentTagNames); - for (TagName tagName : currentTagNames) { - tagNames.put(tagName.getDisplayName(), tagName); - } - } - catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); - } - - // Read the saved tag names, if any, from the tags settings file and - // add them to the current case if they haven't already been added, e.g, - // when the case was last opened. - String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY); - if (null != setting && !setting.isEmpty()) { - // Read the tag types setting and break in into tag type tuples. - List tagNameTuples = Arrays.asList(setting.split(";")); - - // Parse each tuple and add the tag types to the current case, one - // at a time to gracefully discard any duplicates or corrupt tuples. - for (String tagNameTuple : tagNameTuples) { - String[] tagNameAttributes = tagNameTuple.split(","); - if (!tagNames.containsKey(tagNameAttributes[0])) { - TagName tagName = new TagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2])); - try { - tskCase.addTagName(tagName); - tagNames.put(tagName.getDisplayName(),tagName); - } - catch(TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, "Failed to add saved " + tagName.getDisplayName() + " tag name to the current case", ex); - } - } - } - - saveTagNamesToTagsSettings(); - } - } - - private void saveTagNamesToTagsSettings() { - if (!tagNames.isEmpty()) { - StringBuilder setting = new StringBuilder(); - for (TagName tagName : tagNames.values()) { - if (setting.length() != 0) { - setting.append(";"); - } - setting.append(tagName.getDisplayName()).append(","); - setting.append(tagName.getDescription()).append(","); - setting.append(tagName.getColor().name()); - } - - ModuleSettings.setConfigSetting(TAGS_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); - } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index 5df4ad782e..eaccbc35e2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -155,11 +155,6 @@ abstract class AbstractContentChildren extends Keys { return ee.new EmailExtractedRootNode(); } - @Override - public AbstractNode visit(Tags t) { - return t.new TagsRootNode(); - } - @Override public AbstractNode visit(TagsNodeKey tagsNodeKey) { return new TagsNode(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java index 0a3133a018..f57388ae65 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java @@ -52,8 +52,6 @@ public interface AutopsyItemVisitor { T visit(EmailExtracted ee); - T visit(Tags t); - T visit(TagsNodeKey tagsNodeKey); T visit(DataSources i); @@ -136,11 +134,6 @@ public interface AutopsyItemVisitor { return defaultVisit(ee); } - @Override - public T visit(Tags t) { - return defaultVisit(t); - } - @Override public T visit(TagsNodeKey tagsNodeKey) { return defaultVisit(tagsNodeKey); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java index 5a603bbcf5..e4e61680b3 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java @@ -18,11 +18,15 @@ */ package org.sleuthkit.autopsy.datamodel; +import java.util.ArrayList; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.Action; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.actions.DeleteBlackboardArtifactTagAction; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.TskCoreException; @@ -69,6 +73,13 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode { return propertySheet; } + @Override + public Action[] getActions(boolean context) { + List actions = new ArrayList<>(); + actions.add(DeleteBlackboardArtifactTagAction.getInstance()); + return actions.toArray(new Action[0]); + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java index 2c893b3fb5..b2e5c1d08e 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java @@ -19,11 +19,15 @@ package org.sleuthkit.autopsy.datamodel; +import java.util.ArrayList; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.Action; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.actions.DeleteContentTagAction; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TskCoreException; @@ -68,6 +72,13 @@ public class ContentTagNode extends DisplayableItemNode { return propertySheet; } + @Override + public Action[] getActions(boolean context) { + List actions = new ArrayList<>(); + actions.add(DeleteContentTagAction.getInstance()); + return actions.toArray(new Action[0]); + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java index 123d21944b..956ac6d69d 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java @@ -77,7 +77,7 @@ public class ContentTagTypeNode extends DisplayableItemNode { @Override protected boolean createKeys(List keys) { // Use the content tags bearing the specified tag name as the keys. - Case.getCurrentCase().getServices().getTagsManager().getContentTags(tagName, keys); + Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName, keys); return true; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index b4d820bec2..e2cef3846e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -30,9 +30,6 @@ import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode; -import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot; -import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot; -import org.sleuthkit.autopsy.datamodel.Tags.TagsRootNode; import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode; /** @@ -86,12 +83,6 @@ public interface DisplayableItemNodeVisitor { T visit(EmailExtractedFolderNode eefn); - T visit(TagsRootNode bksrn); - - T visit(TagsNodeRoot bksrn); - - T visit(TagNodeRoot tnr); - T visit(TagsNode node); T visit(TagNameNode node); @@ -277,21 +268,6 @@ public interface DisplayableItemNodeVisitor { return defaultVisit(ldn); } - @Override - public T visit(TagsRootNode bksrn) { - return defaultVisit(bksrn); - } - - @Override - public T visit(TagsNodeRoot bksnr) { - return defaultVisit(bksnr); - } - - @Override - public T visit(TagNodeRoot tnr) { - return defaultVisit(tnr); - } - @Override public T visit(TagsNode node) { return defaultVisit(node); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java index ab5159440b..d87f1f2670 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java @@ -35,7 +35,6 @@ public class ResultsNode extends DisplayableItemNode { new KeywordHits(sleuthkitCase), new HashsetHits(sleuthkitCase), new EmailExtracted(sleuthkitCase), - new Tags(sleuthkitCase), //TODO move to the top of the tree new TagsNodeKey() )), Lookups.singleton(NAME)); setName(NAME); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 27b1a5ac84..ff91e44112 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -79,23 +79,12 @@ public class RootContentChildren extends AbstractContentChildren { case TSK_EMAIL_MSG: if (o instanceof EmailExtracted) this.refreshKey(o); - break; - - //TODO check + break; case TSK_TAG_FILE: - if (o instanceof Tags) - this.refreshKey(o); + case TSK_TAG_ARTIFACT: if (o instanceof TagsNodeKey) this.refreshKey(o); - break; - - //TODO check - case TSK_TAG_ARTIFACT: - if (o instanceof Tags) - this.refreshKey(o); - if (o instanceof TagsNodeKey) - this.refreshKey(o); - break; + break; default: if (o instanceof ExtractedContent) this.refreshKey(o); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 74f6fca42b..dce6ecb3ad 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -18,30 +18,15 @@ */ package org.sleuthkit.autopsy.datamodel; -import java.awt.event.ActionEvent; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumMap; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.TreeSet; import java.util.logging.Level; -import javax.swing.AbstractAction; -import javax.swing.Action; -import org.openide.nodes.ChildFactory; -import org.openide.nodes.Children; -import org.openide.nodes.Node; -import org.openide.nodes.Sheet; -import org.openide.util.Lookup; -import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; @@ -50,382 +35,12 @@ import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; -/** - * - * Support for tags in the directory tree. Tag nodes representing file and - * result tags, encapsulate TSK_TAG_FILE and TSK_TAG_ARTIFACT typed artifacts. - * - * The class implements querying of data model and populating node hierarchy - * using child factories. - * - */ -public class Tags implements AutopsyVisitableItem { +public class Tags { private static final Logger logger = Logger.getLogger(Tags.class.getName()); - private static final String FILE_TAG_LABEL_NAME = "File Tags"; - private static final String RESULT_TAG_LABEL_NAME = "Result Tags"; - private SleuthkitCase skCase; - public static final String NAME = "Tags"; - private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; - //bookmarks are specializations of tags public static final String BOOKMARK_TAG_NAME = "Bookmark"; - private static final String BOOKMARK_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png"; - private Map>> tags; private static final String EMPTY_COMMENT = ""; - private static final String APP_SETTINGS_FILE_NAME = "app"; // @@@ TODO: Need a general app settings or user preferences file, this will do for now. - private static final String TAG_NAMES_SETTING_KEY = "tag_names"; - private static final HashSet appSettingTagNames = new HashSet<>(); - private static final StringBuilder tagNamesAppSetting = new StringBuilder(); - - // When this class is loaded, either create an new app settings file or - // get the tag names setting from the existing app settings file. - static { - String setting = ModuleSettings.getConfigSetting(APP_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY); - if (null != setting && !setting.isEmpty()) { - // Make a speedy lookup for the tag names in the setting to aid in the - // detection of new tag names. - List tagNamesFromAppSettings = Arrays.asList(setting.split(",")); - for (String tagName : tagNamesFromAppSettings) { - appSettingTagNames.add(tagName); - } - - // Load the raw comma separated values list from the setting into a - // string builder to facilitate adding new tag names to the list and writing - // it back to the app settings file. - tagNamesAppSetting.append(setting); - } - } - Tags(SleuthkitCase skCase) { - this.skCase = skCase; - } - - @Override - public T accept(AutopsyItemVisitor v) { - return v.visit(this); - } - - /** - * Root of all Tag nodes. This node is shown directly under Results in the - * directory tree. - */ - public class TagsRootNode extends DisplayableItemNode { - - public TagsRootNode() { - super(Children.create(new Tags.TagsRootChildren(), true), Lookups.singleton(NAME)); - super.setName(NAME); - super.setDisplayName(NAME); - this.setIconBaseWithExtension(TAG_ICON_PATH); - initData(); - } - - private void initData() { - try { - // Get all file and artifact tags - - //init data - tags = new EnumMap<>(BlackboardArtifact.ARTIFACT_TYPE.class); - tags.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, new HashMap>()); - tags.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, new HashMap>()); - - //populate - for (BlackboardArtifact.ARTIFACT_TYPE artType : tags.keySet()) { - final Map> artTags = tags.get(artType); - for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(artType)) { - for (BlackboardAttribute attribute : artifact.getAttributes()) { - if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) { - String tagName = attribute.getValueString(); - if (artTags.containsKey(tagName)) { - List artifacts = artTags.get(tagName); - artifacts.add(artifact); - } else { - List artifacts = new ArrayList<>(); - artifacts.add(artifact); - artTags.put(tagName, artifacts); - } - break; - } - } - } - } - - - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Count not initialize tag nodes", ex); - } - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return v.visit(this); - } - - @Override - protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set ss = s.get(Sheet.PROPERTIES); - if (ss == null) { - ss = Sheet.createPropertiesSet(); - s.put(ss); - } - - ss.put(new NodeProperty("Name", - "Name", - "no description", - getName())); - - return s; - } - } - - /** - * bookmarks root child node creating types of bookmarks nodes - */ - private class TagsRootChildren extends ChildFactory { - - @Override - protected boolean createKeys(List list) { - for (BlackboardArtifact.ARTIFACT_TYPE artType : tags.keySet()) { - list.add(artType); - } - - return true; - } - - @Override - protected Node createNodeForKey(BlackboardArtifact.ARTIFACT_TYPE key) { - return new TagsNodeRoot(key, tags.get(key)); - } - } - - /** - * Tag node representation (file or result) - */ - public class TagsNodeRoot extends DisplayableItemNode { - - TagsNodeRoot(BlackboardArtifact.ARTIFACT_TYPE tagType, Map> subTags) { - super(Children.create(new TagRootChildren(tagType, subTags), true), Lookups.singleton(tagType.getDisplayName())); - - String name = null; - if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)) { - name = FILE_TAG_LABEL_NAME; - } else if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) { - name = RESULT_TAG_LABEL_NAME; - } - - super.setName(name); - super.setDisplayName(name + " (" + subTags.values().size() + ")"); - - this.setIconBaseWithExtension(TAG_ICON_PATH); - } - - @Override - protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set ss = s.get(Sheet.PROPERTIES); - if (ss == null) { - ss = Sheet.createPropertiesSet(); - s.put(ss); - } - - ss.put(new NodeProperty("Name", - "Name", - "no description", - getName())); - - return s; - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return v.visit(this); - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - } - - /** - * Child factory to add all the Tag artifacts to a TagsRootNode with the tag - * name. - */ - private class TagRootChildren extends ChildFactory { - - private Map> subTags; - private BlackboardArtifact.ARTIFACT_TYPE tagType; - - TagRootChildren(BlackboardArtifact.ARTIFACT_TYPE tagType, Map> subTags) { - super(); - this.tagType = tagType; - this.subTags = subTags; - } - - @Override - protected boolean createKeys(List list) { - list.addAll(subTags.keySet()); - - return true; - } - - @Override - protected Node createNodeForKey(String key) { - return new Tags.TagNodeRoot(tagType, key, subTags.get(key)); - } - } - - /** - * Node for each unique tag name. Shown directly under Results > Tags. - */ - public class TagNodeRoot extends DisplayableItemNode { - - TagNodeRoot(BlackboardArtifact.ARTIFACT_TYPE tagType, String tagName, List artifacts) { - super(Children.create(new Tags.TagsChildrenNode(tagType, tagName, artifacts), true), Lookups.singleton(tagName)); - - super.setName(tagName); - super.setDisplayName(tagName + " (" + artifacts.size() + ")"); - - if (tagName.equals(BOOKMARK_TAG_NAME)) { - this.setIconBaseWithExtension(BOOKMARK_ICON_PATH); - } else { - this.setIconBaseWithExtension(TAG_ICON_PATH); - } - } - - @Override - protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set ss = s.get(Sheet.PROPERTIES); - if (ss == null) { - ss = Sheet.createPropertiesSet(); - s.put(ss); - } - - ss.put(new NodeProperty("Name", - "Name", - "no description", - getName())); - - return s; - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return v.visit(this); - } - - @Override - public boolean isLeafTypeNode() { - return true; - } - } - - /** - * Node representing an individual Tag artifact. For each TagsNodeRoot under - * Results > Tags, this is one of the nodes listed in the result viewer. - */ - private class TagsChildrenNode extends ChildFactory { - - private List artifacts; - private BlackboardArtifact.ARTIFACT_TYPE tagType; - private String tagName; - - private TagsChildrenNode(BlackboardArtifact.ARTIFACT_TYPE tagType, String tagName, List artifacts) { - super(); - this.tagType = tagType; - this.tagName = tagName; - this.artifacts = artifacts; - } - - @Override - protected boolean createKeys(List list) { - list.addAll(artifacts); - return true; - } - - @Override - protected Node createNodeForKey(final BlackboardArtifact artifact) { - //create node with action - BlackboardArtifactNode tagNode = null; - - String iconPath; - if (tagName.equals(BOOKMARK_TAG_NAME)) { - iconPath = BOOKMARK_ICON_PATH; - } else { - iconPath = TAG_ICON_PATH; - } - - //create actions here where Tag logic belongs - //instead of DataResultFilterNode w/visitors, which is much less pluggable and cluttered - if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) { - //in case of result tag, add a action by sublcassing bb art node - //this action will be merged with other actions set DataResultFIlterNode - //otherwise in case of - tagNode = new BlackboardArtifactNode(artifact, iconPath) { - @Override - public Action[] getActions(boolean bln) { - //Action [] actions = super.getActions(bln); //To change body of generated methods, choose Tools | Templates. - Action[] actions = new Action[1]; - actions[0] = new AbstractAction("View Source Result") { - @Override - public void actionPerformed(ActionEvent e) { - //open the source artifact in dir tree - BlackboardArtifact sourceArt = Tags.getArtifactFromTag(artifact.getArtifactID()); - if (sourceArt != null) { - BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class); - v.viewArtifact(sourceArt); - } - } - }; - return actions; - } - }; - } else { - //for file tag, don't subclass to add the additional actions - tagNode = new BlackboardArtifactNode(artifact, iconPath); - } - - //add some additional node properties - int artifactTypeID = artifact.getArtifactTypeID(); - final String NO_DESCR = "no description"; - if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { - BlackboardArtifact sourceResult = Tags.getArtifactFromTag(artifact.getArtifactID()); - String resultType = sourceResult.getDisplayName(); - - NodeProperty resultTypeProp = new NodeProperty("Source Result Type", - "Result Type", - NO_DESCR, - resultType); - - - tagNode.addNodeProperty(resultTypeProp); - - } - try { - //add source path property - final AbstractFile sourceFile = skCase.getAbstractFileById(artifact.getObjectID()); - final String sourcePath = sourceFile.getUniquePath(); - NodeProperty sourcePathProp = new NodeProperty("Source File Path", - "Source File Path", - NO_DESCR, - sourcePath); - - - tagNode.addNodeProperty(sourcePathProp); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting a file from artifact to get source file path for a tag, ", ex); - } - - return tagNode; - } - } - /** * Create a tag for a file with TSK_TAG_NAME as tagName. * @@ -448,9 +63,7 @@ public class Tags implements AutopsyVisitableItem { "", comment); attrs.add(attr2); } - bookArt.addAttributes(attrs); - - updateTagNamesAppSetting(tagName); + bookArt.addAttributes(attrs); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Failed to create tag for " + file.getName(), ex); @@ -488,30 +101,13 @@ public class Tags implements AutopsyVisitableItem { attrs.add(attr1); attrs.add(attr3); - bookArt.addAttributes(attrs); - - updateTagNamesAppSetting(tagName); + bookArt.addAttributes(attrs); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Failed to create tag for artifact " + artifact.getArtifactID(), ex); } } - private static void updateTagNamesAppSetting(String tagName) { - // If this tag name is not in the current tag names app setting... - if (!appSettingTagNames.contains(tagName)) { - // Add it to the lookup. - appSettingTagNames.add(tagName); - - // Add it to the setting and write the setting back to the app settings file. - if (tagNamesAppSetting.length() != 0) { - tagNamesAppSetting.append(","); - } - tagNamesAppSetting.append(tagName); - ModuleSettings.setConfigSetting(APP_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY, tagNamesAppSetting.toString()); - } - } - /** * Create a bookmark tag for a file. * @@ -557,7 +153,6 @@ public class Tags implements AutopsyVisitableItem { public static TreeSet getAllTagNames() { // Use a TreeSet<> so the union of the tag names from the two sources will be sorted. TreeSet tagNames = getTagNamesFromCurrentCase(); - tagNames.addAll(appSettingTagNames); // Make sure the book mark tag is always included. tagNames.add(BOOKMARK_TAG_NAME); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java index e5d121ada6..3f1813a647 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java @@ -43,6 +43,10 @@ public class TagsNode extends DisplayableItemNode { this.setIconBaseWithExtension(ICON_PATH); } + public static String getNodeName() { + return DISPLAY_NAME; + } + @Override public boolean isLeafTypeNode() { return false; @@ -70,7 +74,7 @@ public class TagsNode extends DisplayableItemNode { private static class TagNameNodeFactory extends ChildFactory { @Override protected boolean createKeys(List keys) { - Case.getCurrentCase().getServices().getTagsManager().getAllTagNames(keys); // RJCTODO: Change this call to filtered call + Case.getCurrentCase().getServices().getTagsManager().getAllTagNames(keys); return true; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java index 7eb1e21a4e..b7acf5dd72 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java @@ -81,7 +81,7 @@ public class BlackboardArtifactTagTypeNode extends DisplayableItemNode { @Override protected boolean createKeys(List keys) { // Use the blackboard artifact tags bearing the specified tag name as the keys. - Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTags(tagName, keys); + Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, keys); return true; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 7303734772..1619c18ccf 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -63,8 +63,6 @@ import org.sleuthkit.autopsy.datamodel.LayoutFileNode; import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode; import org.sleuthkit.autopsy.datamodel.RecentFilesNode; import org.sleuthkit.autopsy.datamodel.FileTypesNode; -import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot; -import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -405,16 +403,6 @@ public class DataResultFilterNode extends FilterNode { return openChild(atn); } - @Override - public AbstractAction visit(TagNodeRoot tnr) { - return openChild(tnr); - } - - @Override - public AbstractAction visit(TagsNodeRoot tnr) { - return openChild(tnr); - } - @Override public AbstractAction visit(DirectoryNode dn) { if (dn.getDisplayName().equals(DirectoryNode.DOTDOTDIR)) {