First draft of implementation of multi-select tagging and export

This commit is contained in:
Richard Cordovano 2013-07-16 18:07:37 -04:00
parent 655e7e5787
commit a5a69b8036
18 changed files with 318 additions and 322 deletions

View File

@ -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);

View File

@ -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<T extends AbstractFile> 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 <T> type of the AbstractFile data to encapsulate
* @param abstractFile file to encapsulate
@ -153,8 +163,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
}
}
}
/**
* Fill map with AbstractFile properties
*
@ -191,8 +200,15 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> 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<T extends AbstractFile> extends A
}
return name;
}
}
}

View File

@ -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;

View File

@ -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<AbstractFile> {
public static final String DOTDOTDIR = "[parent folder]";
public static final String DOTDIR = "[current folder]";
@ -67,16 +66,16 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
*/
@Override
public Action[] getActions(boolean popup) {
List<Action> actions = new ArrayList<Action>();
List<Action> 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]);
}

View File

@ -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<AbstractFile> {
/**
* @param file underlying Content
*/
@ -74,7 +73,7 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
*/
@Override
public Action[] getActions(boolean popup) {
List<Action> actionsList = new ArrayList<Action>();
List<Action> 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<AbstractFile> {
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<AbstractFile> {
}
// Else return the default
return "org/sleuthkit/autopsy/images/file-icon.png";
}
@Override

View File

@ -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<LayoutFile> {
@Override
public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<Action>();
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]);
}

View File

@ -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<AbstractFile> {
@Override
public Action[] getActions(boolean context) {
List<Action> actionsList = new ArrayList<Action>();
List<Action> 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]);
}

View File

@ -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);
}
}
}

View File

@ -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<VirtualDirect
*/
@Override
public Action[] getActions(boolean popup) {
List<Action> actions = new ArrayList<Action>();
List<Action> 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();

View File

@ -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<List<Action>> getActionsDIV;
private final DisplayableItemNodeVisitor<AbstractAction> getPreferredActionsDIV;
@ -105,7 +114,7 @@ public class DataResultFilterNode extends FilterNode {
@Override
public Action[] getActions(boolean popup) {
List<Action> actions = new ArrayList<Action>();
List<Action> 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<Action> actions = new ArrayList<Action>();
List<Action> 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<Action> defaultVisit(DisplayableItemNode ditem) {
//preserve the default node's actions
List<Action> actions = new ArrayList<Action>();
List<Action> actions = new ArrayList<>();
for (Action action : ditem.getActions(true)) {
actions.add(action);

View File

@ -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

View File

@ -47,6 +47,13 @@ import org.sleuthkit.datamodel.VirtualDirectory;
import org.sleuthkit.datamodel.Volume;
public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? extends Action>> {
/**
* 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<List<? ext
@Override
public List<? extends Action> visit(final Directory d) {
List<Action> actions = new ArrayList<Action>();
actions.add(new TagAction(d));
actions.add(tagAction);
return actions;
}
@Override
public List<? extends Action> visit(final VirtualDirectory d) {
List<Action> actions = new ArrayList<Action>();
actions.add(new TagAction(d));
actions.add(new ExtractAction("Extract Directory", d));
actions.add(extractAction);
actions.add(tagAction);
return actions;
}
@Override
public List<? extends Action> visit(final DerivedFile d) {
List<Action> actions = new ArrayList<Action>();
actions.add(new ExtractAction("Extract File", d));
actions.add(new TagAction(d));
actions.add(extractAction);
actions.add(tagAction);
return actions;
}
@Override
public List<? extends Action> visit(final LocalFile d) {
List<Action> actions = new ArrayList<Action>();
actions.add(new ExtractAction("Extract File", d));
actions.add(new TagAction(d));
actions.add(extractAction);
actions.add(tagAction);
return actions;
}
@Override
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
List<Action> actions = new ArrayList<Action>();
actions.add(new ExtractAction("Extract File", d));
actions.add(new TagAction(d));
actions.add(extractAction);
actions.add(tagAction);
return actions;
}

View File

@ -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<AbstractFile> {
@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<Object,Void> {
@ -230,6 +205,5 @@ public final class ExtractAction extends AbstractAction {
}
}
}
}
}
}

View File

@ -0,0 +1,51 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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");
}
}
}
}
}

View File

@ -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<AbstractFile> {
@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

View File

@ -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 {
}// </editor-fold>//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);
}
}

View File

@ -0,0 +1,51 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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");
}
}
}
}
}

View File

@ -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<String> 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();