From a5a69b803604a5c7959daddb00f40b6b2297b70c Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 16 Jul 2013 18:07:37 -0400 Subject: [PATCH 01/15] First draft of implementation of multi-select tagging and export --- .../corecomponents/DataResultViewerTable.java | 2 +- .../datamodel/AbstractAbstractFileNode.java | 26 ++++- .../datamodel/AbstractContentChildren.java | 1 - .../autopsy/datamodel/DirectoryNode.java | 9 +- .../sleuthkit/autopsy/datamodel/FileNode.java | 14 ++- .../autopsy/datamodel/LayoutFileNode.java | 10 +- .../autopsy/datamodel/LocalFileNode.java | 12 +-- .../org/sleuthkit/autopsy/datamodel/Tags.java | 33 ------ .../datamodel/VirtualDirectoryNode.java | 11 +- .../directorytree/DataResultFilterNode.java | 45 ++++---- .../DirectoryTreeFilterNode.java | 4 +- .../ExplorerNodeActionVisitor.java | 25 +++-- .../autopsy/directorytree/ExtractAction.java | 96 ++++++----------- .../directorytree/TagAbstractFileAction.java | 51 +++++++++ .../autopsy/directorytree/TagAction.java | 102 ++++-------------- .../directorytree/TagAndCommentDialog.java | 75 +++++++------ .../TagBlackboardArtifactAction.java | 51 +++++++++ .../autopsy/directorytree/TagMenu.java | 73 ++++++------- 18 files changed, 318 insertions(+), 322 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java create mode 100755 Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index 9ab0d40dea..6f5368578b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -62,7 +62,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { ov.setAllowedDropActions(DnDConstants.ACTION_NONE); // only allow one item to be selected at a time - ov.getOutline().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + ov.getOutline().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); // don't show the root node ov.getOutline().setRootVisible(false); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index adb6cb6249..51b2781c60 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.datamodel; import java.util.Map; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; +import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; @@ -33,6 +35,14 @@ public abstract class AbstractAbstractFileNode extends A private static Logger logger = Logger.getLogger(AbstractAbstractFileNode.class.getName()); + /** + * These Actions are class instances to support multi-selection of nodes corresponding to AbstractFiles. + * They must be a class instances because org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick + * up an Action if every selected node returns a reference to it from Node.getActions(boolean). + */ + private static TagAbstractFileAction tagAction = new TagAbstractFileAction(); + private static ExtractAction extractAction = new ExtractAction(); + /** * @param type of the AbstractFile data to encapsulate * @param abstractFile file to encapsulate @@ -153,8 +163,7 @@ public abstract class AbstractAbstractFileNode extends A } } } - - + /** * Fill map with AbstractFile properties * @@ -191,8 +200,15 @@ public abstract class AbstractAbstractFileNode extends A map.put(AbstractFilePropertyType.MD5HASH.toString(), content.getMd5Hash() == null ? "" : content.getMd5Hash()); } - - static String getContentDisplayName(AbstractFile file) { + protected static TagAbstractFileAction getTagAbstractFileActionInstance() { + return tagAction; + } + + protected static ExtractAction getExtractActionInstance() { + return extractAction; + } + + protected static String getContentDisplayName(AbstractFile file) { String name = file.getName(); if (name.equals("..")) { name = DirectoryNode.DOTDOTDIR; @@ -201,4 +217,4 @@ public abstract class AbstractAbstractFileNode extends A } return name; } -} +} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index 76ad367ace..3e10b86c93 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children.Keys; import org.openide.nodes.Node; -import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode; import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.Directory; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index a364071ac7..827552cfa2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -23,7 +23,6 @@ import java.util.List; import javax.swing.Action; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.TagAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Directory; @@ -34,7 +33,7 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; * are more directories. */ public class DirectoryNode extends AbstractFsContentNode { - + public static final String DOTDOTDIR = "[parent folder]"; public static final String DOTDIR = "[current folder]"; @@ -67,16 +66,16 @@ public class DirectoryNode extends AbstractFsContentNode { */ @Override public Action[] getActions(boolean popup) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); if (!getDirectoryBrowseMode()) { actions.add(new ViewContextAction("View File in Directory", this)); actions.add(null); // creates a menu separator } actions.add(new NewWindowViewAction("View in New Window", this)); actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract Directory", this)); + actions.add(getExtractActionInstance()); actions.add(null); // creates a menu separator - actions.add(new TagAction(this)); + actions.add(getTagAbstractFileActionInstance()); return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 6c3f739624..efbaf4e517 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -21,14 +21,13 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; +import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.getExtractActionInstance; 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.TagAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.FsContent; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; @@ -37,7 +36,7 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; * files children. */ public class FileNode extends AbstractFsContentNode { - + /** * @param file underlying Content */ @@ -74,7 +73,7 @@ public class FileNode extends AbstractFsContentNode { */ @Override public Action[] getActions(boolean popup) { - List actionsList = new ArrayList(); + List actionsList = new ArrayList<>(); if (!this.getDirectoryBrowseMode()) { actionsList.add(new ViewContextAction("View File in Directory", this)); actionsList.add(null); // creates a menu separator @@ -82,10 +81,10 @@ public class FileNode extends AbstractFsContentNode { actionsList.add(new NewWindowViewAction("View in New Window", this)); actionsList.add(new ExternalViewerAction("Open in External Viewer", this)); actionsList.add(null); // creates a menu separator - actionsList.add(new ExtractAction("Extract File", this)); + actionsList.add(getExtractActionInstance()); actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); - actionsList.add(null); // creates a menu separator - actionsList.add(new TagAction(this)); + actionsList.add(null); // creates a menu separator + actionsList.add(getTagAbstractFileActionInstance()); return actionsList.toArray(new Action[0]); } @@ -166,7 +165,6 @@ public class FileNode extends AbstractFsContentNode { } // Else return the default return "org/sleuthkit/autopsy/images/file-icon.png"; - } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index 36f2fc8c02..899c8b045b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -24,11 +24,11 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; -import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor; +import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.getExtractActionInstance; +import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.getTagAbstractFileActionInstance; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.TagAction; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.TskData; @@ -104,14 +104,12 @@ public class LayoutFileNode extends AbstractAbstractFileNode { @Override public Action[] getActions(boolean context) { List actionsList = new ArrayList(); - actionsList.add(new NewWindowViewAction("View in New Window", this)); actionsList.add(new ExternalViewerAction("Open in External Viewer", this)); actionsList.add(null); // creates a menu separator - actionsList.add(new ExtractAction("Extract File", content)); + actionsList.add(getExtractActionInstance()); actionsList.add(null); // creates a menu separator - actionsList.add(new TagAction(content)); - + actionsList.add(getTagAbstractFileActionInstance()); 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 f2dc17d9a0..60d535e4ce 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -25,14 +25,14 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; +import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.getExtractActionInstance; +import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.getTagAbstractFileActionInstance; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE; 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.TagAction; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.LocalFile; /** * A Node for a LocalFile or DerivedFile content object. @@ -86,16 +86,14 @@ public class LocalFileNode extends AbstractAbstractFileNode { @Override public Action[] getActions(boolean context) { - List actionsList = new ArrayList(); - + List actionsList = new ArrayList<>(); actionsList.add(new NewWindowViewAction("View in New Window", this)); actionsList.add(new ExternalViewerAction("Open in External Viewer", this)); actionsList.add(null); // creates a menu separator - actionsList.add(new ExtractAction("Extract", content)); //might not need this actions - already local file + actionsList.add(getExtractActionInstance()); actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator - actionsList.add(new TagAction(content)); - + actionsList.add(getTagAbstractFileActionInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 319d36e737..064f953660 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -22,7 +22,6 @@ import java.awt.event.ActionEvent; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; -import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; @@ -656,36 +655,4 @@ public class Tags implements AutopsyVisitableItem { return tagNames; } - - public interface Taggable { - void createTag(String name, String comment); - } - - public static class TaggableFile implements Taggable { - - private AbstractFile file; - - public TaggableFile(AbstractFile file) { - this.file = file; - } - - @Override - public void createTag(String name, String comment) { - Tags.createTag(file, name, comment); - } - } - - public static class TaggableBlackboardArtifact implements Taggable { - - private BlackboardArtifact bba; - - public TaggableBlackboardArtifact(BlackboardArtifact bba) { - this.bba = bba; - } - - @Override - public void createTag(String name, String comment) { - Tags.createTag(bba, name, comment); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 59e523ff81..ac612e225f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -25,9 +25,9 @@ import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.coreutils.Logger; +import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.getExtractActionInstance; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.TagAction; import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.TskData; @@ -76,16 +76,15 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode actions = new ArrayList(); - + List actions = new ArrayList<>(); actions.add(new NewWindowViewAction("View in New Window", this)); actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract Directory", this)); + actions.add(getExtractActionInstance()); actions.add(null); // creates a menu separator - actions.add(new TagAction(this)); + actions.add(getTagAbstractFileActionInstance()); return actions.toArray(new Action[0]); } - + @Override protected Sheet createSheet() { Sheet s = super.createSheet(); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index a439a066bf..6ea9191bf5 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -81,6 +81,15 @@ import org.sleuthkit.datamodel.VirtualDirectory; */ public class DataResultFilterNode extends FilterNode { + /** + * These are class instances to support multi-selection of nodes corresponding to AbstractFiles and BlackboardArtifacts. + * They are required because org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every selected + * node returns a reference to it from Node.getActions(boolean). + */ + private final static Action extractAction = new ExtractAction(); + private final static Action fileTagAction = new TagAbstractFileAction(); + private final static Action resultTagAction = new TagBlackboardArtifactAction(); + private ExplorerManager sourceEm; private final DisplayableItemNodeVisitor> getActionsDIV; private final DisplayableItemNodeVisitor getPreferredActionsDIV; @@ -105,7 +114,7 @@ public class DataResultFilterNode extends FilterNode { @Override public Action[] getActions(boolean popup) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal(); actions.addAll(originalNode.accept(getActionsDIV)); @@ -167,7 +176,7 @@ public class DataResultFilterNode extends FilterNode { //TODO all actions need to be consolidated in single place! //they should be set in individual Node subclass and using a utility to get Actions per Content sub-type - List actions = new ArrayList(); + List actions = new ArrayList<>(); //merge predefined specific node actions if bban subclasses have their own for (Action a : ban.getActions(true)) { @@ -197,15 +206,15 @@ public class DataResultFilterNode extends FilterNode { actions.add(new NewWindowViewAction("View in New Window", fn)); actions.add(new ExternalViewerAction("Open in External Viewer", fn)); actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract File", new FileNode(f))); + actions.add(extractAction); actions.add(new HashSearchAction("Search for files with the same MD5 hash", fn)); //add file/result tag if itself is not a tag if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { actions.add(null); // creates a menu separator - actions.add(new TagAction(f)); - actions.add(new TagAction(ba)); + actions.add(fileTagAction); + actions.add(resultTagAction); } } if ((d = ban.getLookup().lookup(Directory.class)) != null) { @@ -214,14 +223,14 @@ public class DataResultFilterNode extends FilterNode { actions.add(new NewWindowViewAction("View in New Window", dn)); actions.add(new ExternalViewerAction("Open in External Viewer", dn)); actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract Directory", dn)); + actions.add(extractAction); //add file/result tag if itself is not a tag if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { actions.add(null); // creates a menu separator - actions.add(new TagAction(d)); - actions.add(new TagAction(ba)); + actions.add(fileTagAction); + actions.add(resultTagAction); } } if ((vd = ban.getLookup().lookup(VirtualDirectory.class)) != null) { @@ -230,14 +239,14 @@ public class DataResultFilterNode extends FilterNode { actions.add(new NewWindowViewAction("View in New Window", dn)); actions.add(new ExternalViewerAction("Open in External Viewer", dn)); actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract Directory", dn)); + actions.add(extractAction); //add file/result tag if itself is not a tag if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { actions.add(null); // creates a menu separator - actions.add(new TagAction(d)); - actions.add(new TagAction(ba)); + actions.add(fileTagAction); + actions.add(resultTagAction); } } else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) { LayoutFileNode lfn = new LayoutFileNode(lf); @@ -245,14 +254,14 @@ public class DataResultFilterNode extends FilterNode { actions.add(new NewWindowViewAction("View in New Window", lfn)); actions.add(new ExternalViewerAction("Open in External Viewer", lfn)); actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract File", lfn)); + actions.add(extractAction); //add tag if itself is not a tag if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { actions.add(null); // creates a menu separator - actions.add(new TagAction(lf)); - actions.add(new TagAction(ba)); + actions.add(fileTagAction); + actions.add(resultTagAction); } } else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null || (locF = ban.getLookup().lookup(DerivedFile.class)) != null) { @@ -261,14 +270,14 @@ public class DataResultFilterNode extends FilterNode { actions.add(new NewWindowViewAction("View in New Window", locfn)); actions.add(new ExternalViewerAction("Open in External Viewer", locfn)); actions.add(null); // creates a menu separator - actions.add(new ExtractAction("Extract File", locfn)); + actions.add(extractAction); //add tag if itself is not a tag if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { actions.add(null); // creates a menu separator - actions.add(new TagAction(lf)); - actions.add(new TagAction(ba)); + actions.add(fileTagAction); + actions.add(resultTagAction); } } @@ -278,7 +287,7 @@ public class DataResultFilterNode extends FilterNode { @Override protected List defaultVisit(DisplayableItemNode ditem) { //preserve the default node's actions - List actions = new ArrayList(); + List actions = new ArrayList<>(); for (Action action : ditem.getActions(true)) { actions.add(action); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java index 018679ae2c..034e392e80 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java @@ -47,6 +47,7 @@ import org.sleuthkit.datamodel.TskCoreException; class DirectoryTreeFilterNode extends FilterNode { private static final Action collapseAll = new CollapseAction("Collapse All"); + private static final Action extractAction = new ExtractAction(); private static final Logger logger = Logger.getLogger(DirectoryTreeFilterNode.class.getName()); /** @@ -99,8 +100,7 @@ class DirectoryTreeFilterNode extends FilterNode { //extract dir action Directory dir = this.getLookup().lookup(Directory.class); if (dir != null) { - actions.add(new ExtractAction("Extract Directory", - getOriginal())); + actions.add(extractAction); } // file search action diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java index 28479e83c3..96af70d439 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java @@ -47,6 +47,13 @@ import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.Volume; public class ExplorerNodeActionVisitor extends ContentVisitor.Default> { + /** + * These are class instances to support multi-selection of nodes corresponding to AbstractFiles and BlackboardArtifacts. + * They are required because org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every selected + * node returns a reference to it from Node.getActions(boolean). + */ + private static Action extractAction = new ExtractAction(); + private static Action tagAction = new TagAbstractFileAction(); private static ExplorerNodeActionVisitor instance = new ExplorerNodeActionVisitor(); @@ -101,39 +108,39 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final Directory d) { List actions = new ArrayList(); - actions.add(new TagAction(d)); + actions.add(tagAction); return actions; } @Override public List visit(final VirtualDirectory d) { List actions = new ArrayList(); - actions.add(new TagAction(d)); - actions.add(new ExtractAction("Extract Directory", d)); + actions.add(extractAction); + actions.add(tagAction); return actions; } @Override public List visit(final DerivedFile d) { List actions = new ArrayList(); - actions.add(new ExtractAction("Extract File", d)); - actions.add(new TagAction(d)); + actions.add(extractAction); + actions.add(tagAction); return actions; } @Override public List visit(final LocalFile d) { List actions = new ArrayList(); - actions.add(new ExtractAction("Extract File", d)); - actions.add(new TagAction(d)); + actions.add(extractAction); + actions.add(tagAction); return actions; } @Override public List visit(final org.sleuthkit.datamodel.File d) { List actions = new ArrayList(); - actions.add(new ExtractAction("Extract File", d)); - actions.add(new TagAction(d)); + actions.add(extractAction); + actions.add(tagAction); return actions; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java index 6b183644f1..630b5d1a02 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java @@ -32,11 +32,15 @@ import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.nodes.Node; import org.openide.util.Cancellable; +import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; +import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor; +import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; @@ -47,66 +51,12 @@ import org.sleuthkit.datamodel.Directory; */ public final class ExtractAction extends AbstractAction { - private static final InitializeContentVisitor initializeCV = new InitializeContentVisitor(); - private AbstractFile content; private Logger logger = Logger.getLogger(ExtractAction.class.getName()); - public ExtractAction(String title, Node contentNode) { - super(title); - Content tempContent = contentNode.getLookup().lookup(Content.class); - - this.content = tempContent.accept(initializeCV); - this.setEnabled(content != null); + public ExtractAction() { + super("Export"); } - public ExtractAction(String title, Content content) { - super(title); - - this.content = content.accept(initializeCV); - this.setEnabled(this.content != null); - } - - /** - * Returns the FsContent if it is supported, otherwise null - */ - private static class InitializeContentVisitor extends ContentVisitor.Default { - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.File f) { - return f; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.LayoutFile lf) { - return lf; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.DerivedFile df) { - return df; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.LocalFile lf) { - return lf; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.VirtualDirectory vd) { - return vd; - } - - @Override - public AbstractFile visit(Directory dir) { - return ContentUtils.isDotDirectory(dir) ? null : dir; - } - - @Override - protected AbstractFile defaultVisit(Content cntnt) { - return null; - } - } - /** * Asks user to choose destination, then extracts content/directory to * destination (recursing on directories) @@ -114,10 +64,35 @@ public final class ExtractAction extends AbstractAction { */ @Override public void actionPerformed(ActionEvent e) { + DataResultViewerTable resultViewer = (DataResultViewerTable)Lookup.getDefault().lookup(DataResultViewer.class); + if (null == resultViewer) { + Logger.getLogger(TagAction.class.getName()).log(Level.SEVERE, "Could not get DataResultViewerTable from Lookup"); + return; + } + + Node[] selectedNodes = resultViewer.getExplorerManager().getSelectedNodes(); + if (selectedNodes.length <= 0) { + Logger.getLogger(TagAction.class.getName()).log(Level.SEVERE, "Tried to perform tagging of Nodes with no Nodes selected"); + return; + } + + for (Node node : selectedNodes) { + AbstractFile file = node.getLookup().lookup(AbstractFile.class); + if (null != file) { + extractFile(e, file); + } + else { + // RJCTODO +// Logger.getLogger(org.sleuthkit.autopsy.directorytree.TagAbstractFileAction.TagAbstractFileMenu.class.getName()).log(Level.SEVERE, "Node not associated with an AbstractFile object"); + } + } + } + + private void extractFile(ActionEvent e, AbstractFile file) { // Get content and check that it's okay to overwrite existing content JFileChooser fc = new JFileChooser(); fc.setCurrentDirectory(new File(Case.getCurrentCase().getCaseDirectory())); - fc.setSelectedFile(new File(this.content.getName())); + fc.setSelectedFile(new File(file.getName())); int returnValue = fc.showSaveDialog((Component) e.getSource()); if (returnValue == JFileChooser.APPROVE_OPTION) { @@ -144,12 +119,12 @@ public final class ExtractAction extends AbstractAction { try { ExtractFileThread extract = new ExtractFileThread(); - extract.init(this.content, e, destination); + extract.init(file, e, destination); extract.execute(); } catch (Exception ex) { logger.log(Level.WARNING, "Unable to start background thread.", ex); } - } + } } private class ExtractFileThread extends SwingWorker { @@ -230,6 +205,5 @@ public final class ExtractAction extends AbstractAction { } } } - } - + } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java new file mode 100755 index 0000000000..6ba7a518ed --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java @@ -0,0 +1,51 @@ +/* + * 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.directorytree; + +import java.util.logging.Level; +import org.openide.nodes.Node; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.Tags; +import org.sleuthkit.datamodel.AbstractFile; + +public class TagAbstractFileAction extends TagAction { + @Override + protected TagMenu getTagMenu(Node[] selectedNodes) { + return new TagAbstractFileMenu(selectedNodes); + } + + private static class TagAbstractFileMenu extends TagMenu { + public TagAbstractFileMenu(Node[] nodes) { + super((nodes.length > 1 ? "Tag Files" : "Tag File"), nodes); + } + + @Override + protected void tagNodes(String tagName, String comment) { + for (Node node : getNodes()) { + AbstractFile file = node.getLookup().lookup(AbstractFile.class); + if (null != file) { + Tags.createTag(file, tagName, comment); + } + else { + Logger.getLogger(org.sleuthkit.autopsy.directorytree.TagAbstractFileAction.TagAbstractFileMenu.class.getName()).log(Level.SEVERE, "Node not associated with an AbstractFile object"); + } + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagAction.java index 35c755c0e2..436e3e4541 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagAction.java @@ -21,102 +21,38 @@ package org.sleuthkit.autopsy.directorytree; import java.awt.event.ActionEvent; import java.util.logging.Level; import javax.swing.AbstractAction; -import javax.swing.JMenu; import javax.swing.JMenuItem; import org.openide.nodes.Node; import org.openide.util.actions.Presenter; +import org.openide.util.Lookup; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentVisitor; -import org.sleuthkit.datamodel.Directory; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; +import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; /** - * Action on a file or artifact that adds a tag and - * reloads the directory tree. Supports tagging of AbstractFiles and - * BlackboardArtifacts. - * - * TODO add use enters description and hierarchy (TSK_TAG_NAME with slashes) + * Action on a file or artifact that adds a tag and reloads the directory tree. + * Supports tagging of AbstractFiles and BlackboardArtifacts. */ -public class TagAction extends AbstractAction implements Presenter.Popup { - - private static final Logger logger = Logger.getLogger(TagAction.class.getName()); - private JMenu tagMenu; - private final InitializeBookmarkFileV initializer = new InitializeBookmarkFileV(); - - public TagAction(Node contentNode) { - AbstractFile file = contentNode.getLookup().lookup(AbstractFile.class); - if (file != null) { - tagMenu = new TagMenu(file); - return; - } - - BlackboardArtifact bba = contentNode.getLookup().lookup(BlackboardArtifact.class); - if (bba != null) { - tagMenu = new TagMenu(bba); - return; - } - - logger.log(Level.SEVERE, "Tried to create a " + TagAction.class.getName() - + " using a Node whose lookup did not contain an AbstractFile or a BlackboardArtifact."); - } - - public TagAction(AbstractFile file) { - tagMenu = new TagMenu(file); - } - - public TagAction(BlackboardArtifact bba) { - tagMenu = new TagMenu(bba); - } - +public abstract class TagAction extends AbstractAction implements Presenter.Popup { @Override public JMenuItem getPopupPresenter() { - return tagMenu; - } - - /** - * Returns the FsContent if it is supported, otherwise null - */ - private static class InitializeBookmarkFileV extends ContentVisitor.Default { - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.File f) { - return f; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.LayoutFile lf) { - return lf; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.DerivedFile lf) { - return lf; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.LocalFile lf) { - return lf; - } - - @Override - public AbstractFile visit(org.sleuthkit.datamodel.VirtualDirectory ld) { - return ld; - } - - @Override - public AbstractFile visit(Directory dir) { - return ContentUtils.isDotDirectory(dir) ? null : dir; - } - - @Override - protected AbstractFile defaultVisit(Content cntnt) { + DataResultViewerTable resultViewer = (DataResultViewerTable)Lookup.getDefault().lookup(DataResultViewer.class); + if (null == resultViewer) { + Logger.getLogger(TagAction.class.getName()).log(Level.SEVERE, "Could not get DataResultViewerTable from Lookup"); return null; } + + Node[] selectedNodes = resultViewer.getExplorerManager().getSelectedNodes(); + if (selectedNodes.length <= 0) { + Logger.getLogger(TagAction.class.getName()).log(Level.SEVERE, "Tried to perform tagging of Nodes with no Nodes selected"); + return null; + } + + return getTagMenu(selectedNodes); } + protected abstract TagMenu getTagMenu(Node[] selectedNodes); + @Override public void actionPerformed(ActionEvent e) { // Do nothing - this action should never be performed diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.java index a36a78809b..6a66e55689 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.java @@ -30,28 +30,50 @@ import javax.swing.JFrame; import javax.swing.KeyStroke; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.datamodel.Tags; -import org.sleuthkit.autopsy.datamodel.Tags.Taggable; -import org.sleuthkit.datamodel.BlackboardArtifact; /** * Tag dialog for tagging files and results. User enters an optional comment. */ public class TagAndCommentDialog extends JDialog { - private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; - private static final String BOOKMARK_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png"; - private static final String NO_TAG_MESSAGE = "No Tags"; - - private Taggable taggable; + private static final String NO_TAG_MESSAGE = "No Tags"; + private String tagName = ""; + private String comment = ""; + public static class CommentedTag { + private String name; + private String comment; + + CommentedTag(String name, String comment) { + this.name = name; + this.comment = comment; + } + + public String getName() { + return name; + } + + public String getComment() { + return comment; + } + } + + public static CommentedTag doDialog() { + TagAndCommentDialog dialog = new TagAndCommentDialog(); + if (!dialog.tagName.isEmpty()) { + return new CommentedTag(dialog.tagName, dialog.comment); + } + else { + return null; + } + } + /** * Creates new form TagDialog */ - public TagAndCommentDialog(Taggable taggable) { + private TagAndCommentDialog() { super((JFrame)WindowManager.getDefault().getMainWindow(), "Tag and Comment", true); - this.taggable = taggable; - initComponents(); // Close the dialog when Esc is pressed @@ -60,8 +82,8 @@ public class TagAndCommentDialog extends JDialog { inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); ActionMap actionMap = getRootPane().getActionMap(); actionMap.put(cancelName, new AbstractAction() { + @Override public void actionPerformed(ActionEvent e) { - //doClose(RET_CANCEL); dispose(); } }); @@ -81,15 +103,10 @@ public class TagAndCommentDialog extends JDialog { //center it this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); - - customizeComponent(); setVisible(true); // blocks } - - private void customizeComponent() { - } - + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -195,22 +212,12 @@ public class TagAndCommentDialog extends JDialog { }// //GEN-END:initComponents private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - //doClose(RET_OK); - - // get the selected tag and comment - String selectedTag = (String)tagCombo.getSelectedItem(); - String comment = commentText.getText(); - - // create the tag - taggable.createTag(selectedTag, comment); - - refreshDirectoryTree(); - + tagName = (String)tagCombo.getSelectedItem(); + comment = commentText.getText(); dispose(); }//GEN-LAST:event_okButtonActionPerformed private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed - //doClose(RET_CANCEL); dispose(); }//GEN-LAST:event_cancelButtonActionPerformed @@ -218,14 +225,12 @@ public class TagAndCommentDialog extends JDialog { * Closes the dialog */ private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog - //doClose(RET_CANCEL); dispose(); }//GEN-LAST:event_closeDialog private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed String newTagName = CreateTagDialog.getNewTagNameDialog(null); if (newTagName != null) { - //tagsModel.addElement(newTagName); tagCombo.addItem(newTagName); tagCombo.setSelectedItem(newTagName); } @@ -240,12 +245,4 @@ public class TagAndCommentDialog extends JDialog { private javax.swing.JComboBox tagCombo; private javax.swing.JLabel tagLabel; // End of variables declaration//GEN-END:variables - //private int returnStatus = RET_CANCEL; - - private void refreshDirectoryTree() { - //TODO instead should send event to node children, which will call its refresh() / refreshKeys() - DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance(); - viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); - viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); - } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java new file mode 100755 index 0000000000..b8f7fefb96 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java @@ -0,0 +1,51 @@ +/* + * 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.directorytree; + +import java.util.logging.Level; +import org.openide.nodes.Node; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.Tags; +import org.sleuthkit.datamodel.BlackboardArtifact; + +public class TagBlackboardArtifactAction extends TagAction { + @Override + protected TagMenu getTagMenu(Node[] selectedNodes) { + return new TagBlackboardArtifactMenu(selectedNodes); + } + + private static class TagBlackboardArtifactMenu extends TagMenu { + public TagBlackboardArtifactMenu(Node[] nodes) { + super((nodes.length > 1 ? "Tag Results" : "Tag Result"), nodes); + } + + @Override + protected void tagNodes(String tagName, String comment) { + for (Node node : getNodes()) { + BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class); + if (null != artifact) { + Tags.createTag(artifact, tagName, comment); + } + else { + Logger.getLogger(org.sleuthkit.autopsy.directorytree.TagBlackboardArtifactAction.TagBlackboardArtifactMenu.class.getName()).log(Level.SEVERE, "Node not associated with a BlackboardArtifact object"); + } + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagMenu.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagMenu.java index af432e199a..9d6709f39b 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagMenu.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagMenu.java @@ -23,39 +23,26 @@ import java.awt.event.ActionListener; import java.util.List; import javax.swing.JMenu; import javax.swing.JMenuItem; +import org.openide.nodes.Node; import org.sleuthkit.autopsy.datamodel.Tags; -import org.sleuthkit.autopsy.datamodel.Tags.Taggable; -import org.sleuthkit.autopsy.datamodel.Tags.TaggableBlackboardArtifact; -import org.sleuthkit.autopsy.datamodel.Tags.TaggableFile; -import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; /** * The menu that results when one right-clicks on a file or artifact. */ -public class TagMenu extends JMenu { +public abstract class TagMenu extends JMenu { - private Taggable tagCreator; - - public TagMenu(AbstractFile file) { - super("Tag File"); - tagCreator = new TaggableFile(file); - init(); - } - - public TagMenu(BlackboardArtifact bba) { - super("Tag Result"); - tagCreator = new TaggableBlackboardArtifact(bba); - init(); - } + private Node[] nodes; - private void init() { - - // create the 'Quick Tag' menu and add it to the 'Tag File' menu + public TagMenu(String menuItemText, Node[] selectedNodes) { + super(menuItemText); + this.nodes = selectedNodes; + + // Create the 'Quick Tag' sub-menu and add it to the tag menu. JMenu quickTagMenu = new JMenu("Quick Tag"); - add(quickTagMenu); - - // create the 'Quick Tag' sub-menu items and add them to the 'Quick Tag' menu + add(quickTagMenu); + + // Get the existing tag names. List tagNames = Tags.getTagNames(); if (tagNames.isEmpty()) { JMenuItem empty = new JMenuItem("No tags"); @@ -63,46 +50,56 @@ public class TagMenu extends JMenu { quickTagMenu.add(empty); } + // Add a menu item for each existing tag name to the 'Quick Tag' menu. for (final String tagName : tagNames) { - JMenuItem tagItem = new JMenuItem(tagName); - tagItem.addActionListener(new ActionListener() { + JMenuItem tagNameItem = new JMenuItem(tagName); + tagNameItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - tagCreator.createTag(tagName, ""); + tagNodes(tagName, ""); refreshDirectoryTree(); } }); - quickTagMenu.add(tagItem); + quickTagMenu.add(tagNameItem); } quickTagMenu.addSeparator(); - // create the 'New Tag' menu item + // Create the 'New Tag' menu item and add it to the 'Quick Tag' menu. JMenuItem newTagMenuItem = new JMenuItem("New Tag"); newTagMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - String newTagName = CreateTagDialog.getNewTagNameDialog(null); - if (newTagName != null) { - tagCreator.createTag(newTagName, ""); + String tagName = CreateTagDialog.getNewTagNameDialog(null); + if (tagName != null) { + tagNodes(tagName, ""); refreshDirectoryTree(); } } }); - - // add the 'New Tag' menu item to the 'Quick Tag' menu quickTagMenu.add(newTagMenuItem); - JMenuItem newTagItem = new JMenuItem("Tag and Comment"); - newTagItem.addActionListener(new ActionListener() { + // Create the 'Tag and Comment' menu item and add it to the tag menu. + JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment"); + tagAndCommentItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - new TagAndCommentDialog(tagCreator); + TagAndCommentDialog.CommentedTag commentedTag = TagAndCommentDialog.doDialog(); + if (null != commentedTag) { + tagNodes(commentedTag.getName(), commentedTag.getComment()); + refreshDirectoryTree(); + } } }); - add(newTagItem); + add(tagAndCommentItem); } + protected Node[] getNodes() { + return nodes; + } + + protected abstract void tagNodes(String tagName, String comment); + private void refreshDirectoryTree() { //TODO instead should send event to node children, which will call its refresh() / refreshKeys() DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance(); From d6e82a872181aec8f3983f008c6cb336ea4909f6 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 18 Jul 2013 15:08:10 -0400 Subject: [PATCH 02/15] Backed out addition of multi-selection feature for file extraction. --- .../datamodel/AbstractAbstractFileNode.java | 12 +-- .../autopsy/datamodel/DirectoryNode.java | 2 +- .../sleuthkit/autopsy/datamodel/FileNode.java | 3 +- .../autopsy/datamodel/LayoutFileNode.java | 3 +- .../autopsy/datamodel/LocalFileNode.java | 3 +- .../datamodel/VirtualDirectoryNode.java | 3 +- .../directorytree/DataResultFilterNode.java | 13 ++- .../DirectoryTreeFilterNode.java | 4 +- .../ExplorerNodeActionVisitor.java | 23 +++-- .../autopsy/directorytree/ExtractAction.java | 96 ++++++++++++------- .../directorytree/TagAbstractFileAction.java | 0 .../TagBlackboardArtifactAction.java | 0 .../KeywordSearchFilterNode.java | 21 ++-- .../recentactivity/RAImageIngestModule.java | 0 14 files changed, 102 insertions(+), 81 deletions(-) mode change 100755 => 100644 Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java mode change 100755 => 100644 Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java mode change 100755 => 100644 RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index 51b2781c60..ce0a57d13e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -22,7 +22,6 @@ import java.util.Map; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; -import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; @@ -36,12 +35,11 @@ public abstract class AbstractAbstractFileNode extends A private static Logger logger = Logger.getLogger(AbstractAbstractFileNode.class.getName()); /** - * These Actions are class instances to support multi-selection of nodes corresponding to AbstractFiles. - * They must be a class instances because org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick + * This Action is a class instance to support multi-selection of nodes corresponding to AbstractFiles. + * It must be a class instances because org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick * up an Action if every selected node returns a reference to it from Node.getActions(boolean). */ private static TagAbstractFileAction tagAction = new TagAbstractFileAction(); - private static ExtractAction extractAction = new ExtractAction(); /** * @param type of the AbstractFile data to encapsulate @@ -203,11 +201,7 @@ public abstract class AbstractAbstractFileNode extends A protected static TagAbstractFileAction getTagAbstractFileActionInstance() { return tagAction; } - - protected static ExtractAction getExtractActionInstance() { - return extractAction; - } - + protected static String getContentDisplayName(AbstractFile file) { String name = file.getName(); if (name.equals("..")) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 827552cfa2..6b3a474535 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -73,7 +73,7 @@ public class DirectoryNode extends AbstractFsContentNode { } actions.add(new NewWindowViewAction("View in New Window", this)); actions.add(null); // creates a menu separator - actions.add(getExtractActionInstance()); + actions.add(new ExtractAction("Extract Directory", this)); actions.add(null); // creates a menu separator actions.add(getTagAbstractFileActionInstance()); return actions.toArray(new Action[0]); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index efbaf4e517..b4b8930d97 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; -import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.getExtractActionInstance; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -81,7 +80,7 @@ public class FileNode extends AbstractFsContentNode { actionsList.add(new NewWindowViewAction("View in New Window", this)); actionsList.add(new ExternalViewerAction("Open in External Viewer", this)); actionsList.add(null); // creates a menu separator - actionsList.add(getExtractActionInstance()); + actionsList.add(new ExtractAction("Extract File", this)); actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator actionsList.add(getTagAbstractFileActionInstance()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index 899c8b045b..09d3b41f15 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; -import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.getExtractActionInstance; import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.getTagAbstractFileActionInstance; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; @@ -107,7 +106,7 @@ public class LayoutFileNode extends AbstractAbstractFileNode { actionsList.add(new NewWindowViewAction("View in New Window", this)); actionsList.add(new ExternalViewerAction("Open in External Viewer", this)); actionsList.add(null); // creates a menu separator - actionsList.add(getExtractActionInstance()); + actionsList.add(new ExtractAction("Extract", content)); //might not need this actions - already local file actionsList.add(null); // creates a menu separator actionsList.add(getTagAbstractFileActionInstance()); 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 60d535e4ce..b9eee78aba 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -25,7 +25,6 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; -import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.getExtractActionInstance; import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.getTagAbstractFileActionInstance; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; @@ -90,7 +89,7 @@ public class LocalFileNode extends AbstractAbstractFileNode { actionsList.add(new NewWindowViewAction("View in New Window", this)); actionsList.add(new ExternalViewerAction("Open in External Viewer", this)); actionsList.add(null); // creates a menu separator - actionsList.add(getExtractActionInstance()); + actionsList.add(new ExtractAction("Extract", content)); //might not need this actions - already local file actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator actionsList.add(getTagAbstractFileActionInstance()); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index ac612e225f..39be8bfedb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -25,7 +25,6 @@ import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.coreutils.Logger; -import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.getExtractActionInstance; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.datamodel.VirtualDirectory; @@ -79,7 +78,7 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode actions = new ArrayList<>(); actions.add(new NewWindowViewAction("View in New Window", this)); actions.add(null); // creates a menu separator - actions.add(getExtractActionInstance()); + actions.add(new ExtractAction("Extract Directory", this)); actions.add(null); // creates a menu separator actions.add(getTagAbstractFileActionInstance()); return actions.toArray(new Action[0]); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 6ea9191bf5..ab5fe89c20 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -86,7 +86,6 @@ public class DataResultFilterNode extends FilterNode { * They are required because org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every selected * node returns a reference to it from Node.getActions(boolean). */ - private final static Action extractAction = new ExtractAction(); private final static Action fileTagAction = new TagAbstractFileAction(); private final static Action resultTagAction = new TagBlackboardArtifactAction(); @@ -206,7 +205,7 @@ public class DataResultFilterNode extends FilterNode { actions.add(new NewWindowViewAction("View in New Window", fn)); actions.add(new ExternalViewerAction("Open in External Viewer", fn)); actions.add(null); // creates a menu separator - actions.add(extractAction); + actions.add(new ExtractAction("Extract File", new FileNode(f))); actions.add(new HashSearchAction("Search for files with the same MD5 hash", fn)); //add file/result tag if itself is not a tag @@ -223,7 +222,7 @@ public class DataResultFilterNode extends FilterNode { actions.add(new NewWindowViewAction("View in New Window", dn)); actions.add(new ExternalViewerAction("Open in External Viewer", dn)); actions.add(null); // creates a menu separator - actions.add(extractAction); + actions.add(new ExtractAction("Extract Directory", dn)); //add file/result tag if itself is not a tag if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() @@ -239,7 +238,7 @@ public class DataResultFilterNode extends FilterNode { actions.add(new NewWindowViewAction("View in New Window", dn)); actions.add(new ExternalViewerAction("Open in External Viewer", dn)); actions.add(null); // creates a menu separator - actions.add(extractAction); + actions.add(new ExtractAction("Extract Directory", dn)); //add file/result tag if itself is not a tag if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() @@ -254,7 +253,7 @@ public class DataResultFilterNode extends FilterNode { actions.add(new NewWindowViewAction("View in New Window", lfn)); actions.add(new ExternalViewerAction("Open in External Viewer", lfn)); actions.add(null); // creates a menu separator - actions.add(extractAction); + actions.add(new ExtractAction("Extract File", lfn)); //add tag if itself is not a tag if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() @@ -270,8 +269,8 @@ public class DataResultFilterNode extends FilterNode { actions.add(new NewWindowViewAction("View in New Window", locfn)); actions.add(new ExternalViewerAction("Open in External Viewer", locfn)); actions.add(null); // creates a menu separator - actions.add(extractAction); - + actions.add(new ExtractAction("Extract File", locfn)); + //add tag if itself is not a tag if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java index 034e392e80..018679ae2c 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterNode.java @@ -47,7 +47,6 @@ import org.sleuthkit.datamodel.TskCoreException; class DirectoryTreeFilterNode extends FilterNode { private static final Action collapseAll = new CollapseAction("Collapse All"); - private static final Action extractAction = new ExtractAction(); private static final Logger logger = Logger.getLogger(DirectoryTreeFilterNode.class.getName()); /** @@ -100,7 +99,8 @@ class DirectoryTreeFilterNode extends FilterNode { //extract dir action Directory dir = this.getLookup().lookup(Directory.class); if (dir != null) { - actions.add(extractAction); + actions.add(new ExtractAction("Extract Directory", + getOriginal())); } // file search action diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java index 96af70d439..551718b5f3 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java @@ -48,11 +48,10 @@ import org.sleuthkit.datamodel.Volume; public class ExplorerNodeActionVisitor extends ContentVisitor.Default> { /** - * These are class instances to support multi-selection of nodes corresponding to AbstractFiles and BlackboardArtifacts. - * They are required because org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every selected + * This is a class instance to support multi-selection of nodes corresponding to AbstractFiles and BlackboardArtifacts. + * It is required because org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every selected * node returns a reference to it from Node.getActions(boolean). */ - private static Action extractAction = new ExtractAction(); private static Action tagAction = new TagAbstractFileAction(); private static ExplorerNodeActionVisitor instance = new ExplorerNodeActionVisitor(); @@ -85,7 +84,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final Image img) { - List lst = new ArrayList(); + List lst = new ArrayList<>(); lst.add(new ImageDetails("Image Details", img)); //TODO lst.add(new ExtractAction("Extract Image", img)); lst.add(new ExtractUnallocAction("Extract Unallocated Space to Single Files", img)); @@ -99,7 +98,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final Volume vol) { - List lst = new ArrayList(); + List lst = new ArrayList<>(); lst.add(new VolumeDetails("Volume Details", vol)); lst.add(new ExtractUnallocAction("Extract Unallocated Space to Single File", vol)); return lst; @@ -107,23 +106,23 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final Directory d) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); actions.add(tagAction); return actions; } @Override public List visit(final VirtualDirectory d) { - List actions = new ArrayList(); - actions.add(extractAction); + List actions = new ArrayList<>(); + actions.add(new ExtractAction("Extract Directory", d)); actions.add(tagAction); return actions; } @Override public List visit(final DerivedFile d) { - List actions = new ArrayList(); - actions.add(extractAction); + List actions = new ArrayList<>(); + actions.add(new ExtractAction("Extract Directory", d)); actions.add(tagAction); return actions; } @@ -131,7 +130,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final LocalFile d) { List actions = new ArrayList(); - actions.add(extractAction); + actions.add(new ExtractAction("Extract File", d)); actions.add(tagAction); return actions; } @@ -139,7 +138,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final org.sleuthkit.datamodel.File d) { List actions = new ArrayList(); - actions.add(extractAction); + actions.add(new ExtractAction("Extract File", d)); actions.add(tagAction); return actions; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java index 630b5d1a02..6b183644f1 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java @@ -32,15 +32,11 @@ import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.nodes.Node; import org.openide.util.Cancellable; -import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; -import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor; -import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; @@ -51,12 +47,66 @@ import org.sleuthkit.datamodel.Directory; */ public final class ExtractAction extends AbstractAction { + private static final InitializeContentVisitor initializeCV = new InitializeContentVisitor(); + private AbstractFile content; private Logger logger = Logger.getLogger(ExtractAction.class.getName()); - public ExtractAction() { - super("Export"); + public ExtractAction(String title, Node contentNode) { + super(title); + Content tempContent = contentNode.getLookup().lookup(Content.class); + + this.content = tempContent.accept(initializeCV); + this.setEnabled(content != null); } + public ExtractAction(String title, Content content) { + super(title); + + this.content = content.accept(initializeCV); + this.setEnabled(this.content != null); + } + + /** + * Returns the FsContent if it is supported, otherwise null + */ + private static class InitializeContentVisitor extends ContentVisitor.Default { + + @Override + public AbstractFile visit(org.sleuthkit.datamodel.File f) { + return f; + } + + @Override + public AbstractFile visit(org.sleuthkit.datamodel.LayoutFile lf) { + return lf; + } + + @Override + public AbstractFile visit(org.sleuthkit.datamodel.DerivedFile df) { + return df; + } + + @Override + public AbstractFile visit(org.sleuthkit.datamodel.LocalFile lf) { + return lf; + } + + @Override + public AbstractFile visit(org.sleuthkit.datamodel.VirtualDirectory vd) { + return vd; + } + + @Override + public AbstractFile visit(Directory dir) { + return ContentUtils.isDotDirectory(dir) ? null : dir; + } + + @Override + protected AbstractFile defaultVisit(Content cntnt) { + return null; + } + } + /** * Asks user to choose destination, then extracts content/directory to * destination (recursing on directories) @@ -64,35 +114,10 @@ public final class ExtractAction extends AbstractAction { */ @Override public void actionPerformed(ActionEvent e) { - DataResultViewerTable resultViewer = (DataResultViewerTable)Lookup.getDefault().lookup(DataResultViewer.class); - if (null == resultViewer) { - Logger.getLogger(TagAction.class.getName()).log(Level.SEVERE, "Could not get DataResultViewerTable from Lookup"); - return; - } - - Node[] selectedNodes = resultViewer.getExplorerManager().getSelectedNodes(); - if (selectedNodes.length <= 0) { - Logger.getLogger(TagAction.class.getName()).log(Level.SEVERE, "Tried to perform tagging of Nodes with no Nodes selected"); - return; - } - - for (Node node : selectedNodes) { - AbstractFile file = node.getLookup().lookup(AbstractFile.class); - if (null != file) { - extractFile(e, file); - } - else { - // RJCTODO -// Logger.getLogger(org.sleuthkit.autopsy.directorytree.TagAbstractFileAction.TagAbstractFileMenu.class.getName()).log(Level.SEVERE, "Node not associated with an AbstractFile object"); - } - } - } - - private void extractFile(ActionEvent e, AbstractFile file) { // Get content and check that it's okay to overwrite existing content JFileChooser fc = new JFileChooser(); fc.setCurrentDirectory(new File(Case.getCurrentCase().getCaseDirectory())); - fc.setSelectedFile(new File(file.getName())); + fc.setSelectedFile(new File(this.content.getName())); int returnValue = fc.showSaveDialog((Component) e.getSource()); if (returnValue == JFileChooser.APPROVE_OPTION) { @@ -119,12 +144,12 @@ public final class ExtractAction extends AbstractAction { try { ExtractFileThread extract = new ExtractFileThread(); - extract.init(file, e, destination); + extract.init(this.content, e, destination); extract.execute(); } catch (Exception ex) { logger.log(Level.WARNING, "Unable to start background thread.", ex); } - } + } } private class ExtractFileThread extends SwingWorker { @@ -205,5 +230,6 @@ public final class ExtractAction extends AbstractAction { } } } - } + } + } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java old mode 100755 new mode 100644 diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java old mode 100755 new mode 100644 diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index bb9945dfa4..a1c6da0284 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -33,6 +33,7 @@ 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.TagAbstractFileAction; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.DerivedFile; @@ -44,7 +45,13 @@ import org.sleuthkit.datamodel.File; * the full highlighted content as a MarkupSource */ class KeywordSearchFilterNode extends FilterNode { - + /** + * This Action is a class instance to support multi-selection of nodes corresponding to AbstractFiles. + * It must be a class instances because org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick + * up an Action if every selected node returns a reference to it from Node.getActions(boolean). + */ + private static TagAbstractFileAction tagAction = new TagAbstractFileAction(); + String solrQuery; int previewChunk; @@ -123,7 +130,7 @@ class KeywordSearchFilterNode extends FilterNode { @Override public Action[] getActions(boolean popup) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); Content content = this.getOriginal().getLookup().lookup(Content.class); actions.addAll(content.accept(new GetPopupActionsContentVisitor())); @@ -137,33 +144,33 @@ class KeywordSearchFilterNode extends FilterNode { @Override public List visit(File f) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); actions.add(new NewWindowViewAction("View in New Window", KeywordSearchFilterNode.this)); actions.add(new ExternalViewerAction("Open in External Viewer", getOriginal())); actions.add(null); actions.add(new ExtractAction("Extract File", getOriginal())); actions.add(new HashSearchAction("Search for files with the same MD5 hash", getOriginal())); actions.add(null); // creates a menu separator - actions.add(new TagAction(getOriginal())); + actions.add(tagAction); return actions; } @Override public List visit(DerivedFile f) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); actions.add(new NewWindowViewAction("View in New Window", KeywordSearchFilterNode.this)); actions.add(new ExternalViewerAction("Open in External Viewer", getOriginal())); actions.add(null); actions.add(new ExtractAction("Extract File", getOriginal())); actions.add(new HashSearchAction("Search for files with the same MD5 hash", getOriginal())); actions.add(null); // creates a menu separator - actions.add(new TagAction(getOriginal())); + actions.add(tagAction); return actions; } @Override protected List defaultVisit(Content c) { - return new ArrayList(); + return new ArrayList<>(); } } } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java old mode 100755 new mode 100644 From a431a747be88010acdd629a9e44697135d1e83fd Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 18 Jul 2013 15:10:40 -0400 Subject: [PATCH 03/15] Additional files for back out of mult-select feature for file extraction --- Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java | 0 .../sleuthkit/autopsy/directorytree/TagAbstractFileAction.java | 0 .../autopsy/directorytree/TagBlackboardArtifactAction.java | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractAction.java old mode 100644 new mode 100755 diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java old mode 100644 new mode 100755 diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java old mode 100644 new mode 100755 From 486307391a8eec5158e3d17d031d7f3430e32e42 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 19 Jul 2013 11:57:11 -0400 Subject: [PATCH 04/15] Removed ability to tag dot directories and added multi-selection tagging support to KeywaordSearchFilterNode class --- .../autopsy/datamodel/DirectoryNode.java | 18 ++++++++++++++++-- .../keywordsearch/KeywordSearchFilterNode.java | 1 - 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 6b3a474535..555aa49905 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -20,7 +20,9 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; import javax.swing.Action; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; @@ -67,6 +69,13 @@ public class DirectoryNode extends AbstractFsContentNode { @Override public Action[] getActions(boolean popup) { List actions = new ArrayList<>(); + + AbstractFile file = getLookup().lookup(AbstractFile.class); + if (file == null) { + Logger.getLogger(DirectoryNode.class.getName()).log(Level.SEVERE, "Node not associated with an AbstractFile object"); + return actions.toArray(new Action[0]); + } + if (!getDirectoryBrowseMode()) { actions.add(new ViewContextAction("View File in Directory", this)); actions.add(null); // creates a menu separator @@ -74,8 +83,13 @@ public class DirectoryNode extends AbstractFsContentNode { actions.add(new NewWindowViewAction("View in New Window", this)); actions.add(null); // creates a menu separator actions.add(new ExtractAction("Extract Directory", this)); - actions.add(null); // creates a menu separator - actions.add(getTagAbstractFileActionInstance()); + + String name = getDisplayName(); + if (!name.equals(DirectoryNode.DOTDIR) && !name.equals(DirectoryNode.DOTDOTDIR)) { + actions.add(null); // creates a menu separator + actions.add(getTagAbstractFileActionInstance()); + } + return actions.toArray(new Action[0]); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index a1c6da0284..2afbd608f2 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -28,7 +28,6 @@ import org.openide.nodes.PropertySupport; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; -import org.sleuthkit.autopsy.directorytree.TagAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; From 1a9d55c25d91c1633bfc0676d89e29291614f9ce Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 19 Jul 2013 12:11:54 -0400 Subject: [PATCH 05/15] Modified ReportWizardAction to allow use of report wizard independent of coupling to toolbar --- .../autopsy/report/ReportWizardAction.java | 82 ++++++++++--------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java index 34c58cf5cb..780e14351d 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java @@ -2,9 +2,9 @@ * * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2013 Basis Technology Corp. * - * Copyright 2012 42six Solutions. + * Copyright 2013 42six Solutions. * Contact: aebadirad 42six com * Project Contact/Architect: carrier sleuthkit org * @@ -30,7 +30,6 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.text.MessageFormat; import java.util.Map; -import java.util.Map.Entry; import java.util.logging.Level; import javax.swing.ImageIcon; import javax.swing.JButton; @@ -59,47 +58,12 @@ public final class ReportWizardAction extends CallableSystemAction implements P private JButton toolbarButton = new JButton(); private static final String ACTION_NAME = "Generate Report"; - public ReportWizardAction() { - setEnabled(false); - Case.addPropertyChangeListener(new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(Case.CASE_CURRENT_CASE)) { - Case newCase = (Case) evt.getNewValue(); - setEnabled(newCase != null); - - // Make the cases' Reoports folder, if it doesn't exist - if (newCase != null) { - boolean exists = (new File(newCase.getCaseDirectory() + File.separator + "Reports")).exists(); - if (!exists) { - boolean reportCreate = (new File(newCase.getCaseDirectory() + File.separator + "Reports")).mkdirs(); - if (!reportCreate) { - logger.log(Level.WARNING, "Could not create Reports directory for case. It does not exist."); - } - } - } - } - } - }); - - // Initialize the Generate Report button - toolbarButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - ReportWizardAction.this.actionPerformed(e); - } - }); - - } - /** * When the Generate Report button or menu item is selected, open the reporting wizard. * When the wizard is finished, create a ReportGenerator with the wizard information, * and start all necessary reports. */ - @Override - @SuppressWarnings("unchecked") - public void actionPerformed(ActionEvent e) { + public static void doReportWizard() { // Create the wizard WizardDescriptor wiz = new WizardDescriptor(new ReportWizardIterator()); wiz.setTitleFormat(new MessageFormat("{0} {1}")); @@ -133,7 +97,45 @@ public final class ReportWizardAction extends CallableSystemAction implements P // Open the progress window for the user generator.displayProgressPanels(); - } + } + } + + public ReportWizardAction() { + setEnabled(false); + Case.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals(Case.CASE_CURRENT_CASE)) { + Case newCase = (Case) evt.getNewValue(); + setEnabled(newCase != null); + + // Make the cases' Reoports folder, if it doesn't exist + if (newCase != null) { + boolean exists = (new File(newCase.getCaseDirectory() + File.separator + "Reports")).exists(); + if (!exists) { + boolean reportCreate = (new File(newCase.getCaseDirectory() + File.separator + "Reports")).mkdirs(); + if (!reportCreate) { + logger.log(Level.WARNING, "Could not create Reports directory for case. It does not exist."); + } + } + } + } + } + }); + + // Initialize the Generate Report button + toolbarButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + ReportWizardAction.this.actionPerformed(e); + } + }); + } + + @Override + @SuppressWarnings("unchecked") + public void actionPerformed(ActionEvent e) { + doReportWizard(); } @Override From 0cf8ee8b5aa0e27b04ce2b3348b4602c34a994a4 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 19 Jul 2013 12:16:32 -0400 Subject: [PATCH 06/15] HTML reporting module no longer provides view file hyperlink for directories --- Core/src/org/sleuthkit/autopsy/report/ReportHTML.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 2332814cd7..99893fe7cf 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -399,10 +399,10 @@ public class ReportHTML implements TableReportModule { try { AbstractFile file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(sourceArtifact.getObjectID()); - // Don't make a local copy of the file if it is unallocated space or a virtual directory. - if (file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS || - file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS || - file.getType() == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR) { + // Don't make a local copy of the file if it is a directory or unallocated space. + if (file.isDir() || + file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS || + file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) { row.add(""); return; } From 08bb9f8bc81b9c82796f4c4ee79fa842b6c98801 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 23 Jul 2013 13:28:58 -0400 Subject: [PATCH 07/15] Added temporary special handling of image read errors preliminary to API change to allow such errors to be distinguished --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 7d39d8f05a..5dee9feb54 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -56,7 +56,7 @@ import org.sleuthkit.datamodel.SleuthkitJNI.CaseDbHandle.AddImageProcess; * open at a time. Use getCurrentCase() to retrieve the object for the current * case. */ -public class Case { +public class Case implements SleuthkitCase.ErrorObserver { private static final String autopsyVer = Version.getVersion(); // current version of autopsy. Change it when the version is changed private static final String appName = Version.getName() + " " + autopsyVer; @@ -130,6 +130,7 @@ public class Case { this.xmlcm = xmlcm; this.db = db; this.services = new Services(db); + db.addErrorObserver(this); } /** @@ -983,4 +984,9 @@ public class Case { CoreComponentControl.closeCoreWindows(); } } + + @Override + public void receiveError(String context, String errorMessage) { + MessageNotifyUtil.Notify.error(context, errorMessage); + } } From 1f884055c52baa6cd8e2aa4f38ffdda316e4faac Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Thu, 25 Jul 2013 15:41:30 -0400 Subject: [PATCH 08/15] Added new interface to enable extensibility of CaseNewAction lookup. --- .../autopsy/casemodule/CaseNewAction.java | 4 ++-- .../casemodule/CaseNewActionInterface.java | 24 +++++++++++++++++++ .../autopsy/casemodule/CueBannerPanel.java | 2 +- .../netbeans/core/startup/Bundle.properties | 4 ++-- .../core/windows/view/ui/Bundle.properties | 6 ++--- 5 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/CaseNewActionInterface.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewAction.java index 03cdf27c96..066cd10149 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewAction.java @@ -30,8 +30,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; * * @author jantonius */ -@ServiceProvider(service = CaseNewAction.class) -public final class CaseNewAction implements ActionListener { +@ServiceProvider(service = CaseNewActionInterface.class) +public final class CaseNewAction implements CaseNewActionInterface { private NewCaseWizardAction wizard = SystemAction.get(NewCaseWizardAction.class); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewActionInterface.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewActionInterface.java new file mode 100644 index 0000000000..e770d35094 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseNewActionInterface.java @@ -0,0 +1,24 @@ +/** + * ************************************************************************* + ** This data and information is proprietary to, and a valuable trade secret * + * of, Basis Technology Corp. It is given in confidence by Basis Technology * + * and may only be used as permitted under the license agreement under which * + * it has been distributed, and in no other way. * * Copyright (c) 2013 Basis + * Technology Corp. All rights reserved. * * The technical data and information + * provided herein are provided with * `limited rights', and the computer + * software provided herein is provided * with `restricted rights' as those + * terms are defined in DAR and ASPR * 7-104.9(a). + * ************************************************************************* + */ + + +package org.sleuthkit.autopsy.casemodule; + +import java.awt.event.ActionListener; + +/** + * + */ +public interface CaseNewActionInterface extends ActionListener { + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index 8674fe0788..48cef48e24 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -195,7 +195,7 @@ public class CueBannerPanel extends javax.swing.JPanel { }// //GEN-END:initComponents private void newCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newCaseButtonActionPerformed - Lookup.getDefault().lookup(CaseNewAction.class).actionPerformed(evt); + Lookup.getDefault().lookup(CaseNewActionInterface.class).actionPerformed(evt); }//GEN-LAST:event_newCaseButtonActionPerformed private void openCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openCaseButtonActionPerformed diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index e5590ed3f3..89f5fc6173 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Sun, 02 Jun 2013 00:12:29 -0400 +#Thu, 25 Jul 2013 15:34:25 -0400 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=288 SPLASH_WIDTH=538 @@ -8,4 +8,4 @@ SplashRunningTextBounds=5,266,530,17 SplashRunningTextColor=0x0 SplashRunningTextFontSize=18 -currentVersion=Autopsy 20130602 +currentVersion=Autopsy 20130725 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index bbd446205d..cb822f501c 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Thu, 23 May 2013 00:04:58 -0400 +#Thu, 25 Jul 2013 15:34:25 -0400 -CTL_MainWindow_Title=Autopsy 20130523 -CTL_MainWindow_Title_No_Project=Autopsy 20130523 +CTL_MainWindow_Title=Autopsy 20130725 +CTL_MainWindow_Title_No_Project=Autopsy 20130725 From d83c58b9265e0d55cca92b8148e67b57dd590428 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Thu, 25 Jul 2013 17:19:53 -0400 Subject: [PATCH 09/15] Swapped positions of the Open Existing and Open Recent buttons. --- .../autopsy/casemodule/CueBannerPanel.form | 123 ++++++++---------- .../autopsy/casemodule/CueBannerPanel.java | 90 ++++++------- 2 files changed, 95 insertions(+), 118 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form index ef800ab9f0..22f3d74c28 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.form @@ -1,4 +1,4 @@ - +
@@ -36,7 +36,7 @@