mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-13 00:16:16 +00:00
First draft of implementation of multi-select tagging and export
This commit is contained in:
parent
655e7e5787
commit
a5a69b8036
@ -62,7 +62,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
ov.setAllowedDropActions(DnDConstants.ACTION_NONE);
|
ov.setAllowedDropActions(DnDConstants.ACTION_NONE);
|
||||||
|
|
||||||
// only allow one item to be selected at a time
|
// 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
|
// don't show the root node
|
||||||
ov.getOutline().setRootVisible(false);
|
ov.getOutline().setRootVisible(false);
|
||||||
|
@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.datamodel;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
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.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
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());
|
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 <T> type of the AbstractFile data to encapsulate
|
||||||
* @param abstractFile file to encapsulate
|
* @param abstractFile file to encapsulate
|
||||||
@ -154,7 +164,6 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill map with AbstractFile properties
|
* 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());
|
map.put(AbstractFilePropertyType.MD5HASH.toString(), content.getMd5Hash() == null ? "" : content.getMd5Hash());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static TagAbstractFileAction getTagAbstractFileActionInstance() {
|
||||||
|
return tagAction;
|
||||||
|
}
|
||||||
|
|
||||||
static String getContentDisplayName(AbstractFile file) {
|
protected static ExtractAction getExtractActionInstance() {
|
||||||
|
return extractAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String getContentDisplayName(AbstractFile file) {
|
||||||
String name = file.getName();
|
String name = file.getName();
|
||||||
if (name.equals("..")) {
|
if (name.equals("..")) {
|
||||||
name = DirectoryNode.DOTDOTDIR;
|
name = DirectoryNode.DOTDOTDIR;
|
||||||
|
@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel;
|
|||||||
import org.openide.nodes.AbstractNode;
|
import org.openide.nodes.AbstractNode;
|
||||||
import org.openide.nodes.Children.Keys;
|
import org.openide.nodes.Children.Keys;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
|
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
|
||||||
import org.sleuthkit.datamodel.DerivedFile;
|
import org.sleuthkit.datamodel.DerivedFile;
|
||||||
import org.sleuthkit.datamodel.Directory;
|
import org.sleuthkit.datamodel.Directory;
|
||||||
|
@ -23,7 +23,6 @@ import java.util.List;
|
|||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.TagAction;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Directory;
|
import org.sleuthkit.datamodel.Directory;
|
||||||
@ -67,16 +66,16 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Action[] getActions(boolean popup) {
|
public Action[] getActions(boolean popup) {
|
||||||
List<Action> actions = new ArrayList<Action>();
|
List<Action> actions = new ArrayList<>();
|
||||||
if (!getDirectoryBrowseMode()) {
|
if (!getDirectoryBrowseMode()) {
|
||||||
actions.add(new ViewContextAction("View File in Directory", this));
|
actions.add(new ViewContextAction("View File in Directory", this));
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
}
|
}
|
||||||
actions.add(new NewWindowViewAction("View in New Window", this));
|
actions.add(new NewWindowViewAction("View in New Window", this));
|
||||||
actions.add(null); // creates a menu separator
|
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(null); // creates a menu separator
|
||||||
actions.add(new TagAction(this));
|
actions.add(getTagAbstractFileActionInstance());
|
||||||
return actions.toArray(new Action[0]);
|
return actions.toArray(new Action[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,14 +21,13 @@ package org.sleuthkit.autopsy.datamodel;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
|
import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.getExtractActionInstance;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.TagAction;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
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_DB_FILES_TYPE_ENUM;
|
||||||
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
||||||
|
|
||||||
@ -74,7 +73,7 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Action[] getActions(boolean popup) {
|
public Action[] getActions(boolean popup) {
|
||||||
List<Action> actionsList = new ArrayList<Action>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
if (!this.getDirectoryBrowseMode()) {
|
if (!this.getDirectoryBrowseMode()) {
|
||||||
actionsList.add(new ViewContextAction("View File in Directory", this));
|
actionsList.add(new ViewContextAction("View File in Directory", this));
|
||||||
actionsList.add(null); // creates a menu separator
|
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 NewWindowViewAction("View in New Window", this));
|
||||||
actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
|
actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
|
||||||
actionsList.add(null); // creates a menu separator
|
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(new HashSearchAction("Search for files with the same MD5 hash", this));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(new TagAction(this));
|
actionsList.add(getTagAbstractFileActionInstance());
|
||||||
return actionsList.toArray(new Action[0]);
|
return actionsList.toArray(new Action[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +165,6 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
}
|
}
|
||||||
// Else return the default
|
// Else return the default
|
||||||
return "org/sleuthkit/autopsy/images/file-icon.png";
|
return "org/sleuthkit/autopsy/images/file-icon.png";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -24,11 +24,11 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.openide.nodes.Sheet;
|
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.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.TagAction;
|
|
||||||
import org.sleuthkit.datamodel.LayoutFile;
|
import org.sleuthkit.datamodel.LayoutFile;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
|
||||||
@ -104,14 +104,12 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
|||||||
@Override
|
@Override
|
||||||
public Action[] getActions(boolean context) {
|
public Action[] getActions(boolean context) {
|
||||||
List<Action> actionsList = new ArrayList<Action>();
|
List<Action> actionsList = new ArrayList<Action>();
|
||||||
|
|
||||||
actionsList.add(new NewWindowViewAction("View in New Window", this));
|
actionsList.add(new NewWindowViewAction("View in New Window", this));
|
||||||
actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
|
actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
|
||||||
actionsList.add(null); // creates a menu separator
|
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(null); // creates a menu separator
|
||||||
actionsList.add(new TagAction(content));
|
actionsList.add(getTagAbstractFileActionInstance());
|
||||||
|
|
||||||
return actionsList.toArray(new Action[0]);
|
return actionsList.toArray(new Action[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,14 +25,14 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.openide.nodes.Sheet;
|
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.datamodel.DisplayableItemNode.TYPE;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.TagAction;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.LocalFile;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Node for a LocalFile or DerivedFile content object.
|
* A Node for a LocalFile or DerivedFile content object.
|
||||||
@ -86,16 +86,14 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Action[] getActions(boolean context) {
|
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 NewWindowViewAction("View in New Window", this));
|
||||||
actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
|
actionsList.add(new ExternalViewerAction("Open in External Viewer", this));
|
||||||
actionsList.add(null); // creates a menu separator
|
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(new HashSearchAction("Search for files with the same MD5 hash", this));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(new TagAction(content));
|
actionsList.add(getTagAbstractFileActionInstance());
|
||||||
|
|
||||||
return actionsList.toArray(new Action[0]);
|
return actionsList.toArray(new Action[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ import java.awt.event.ActionEvent;
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -656,36 +655,4 @@ public class Tags implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
return tagNames;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,9 @@ import java.util.Map;
|
|||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
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.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.TagAction;
|
|
||||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
|
||||||
@ -76,13 +76,12 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Action[] getActions(boolean popup) {
|
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(new NewWindowViewAction("View in New Window", this));
|
||||||
actions.add(null); // creates a menu separator
|
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(null); // creates a menu separator
|
||||||
actions.add(new TagAction(this));
|
actions.add(getTagAbstractFileActionInstance());
|
||||||
return actions.toArray(new Action[0]);
|
return actions.toArray(new Action[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +81,15 @@ import org.sleuthkit.datamodel.VirtualDirectory;
|
|||||||
*/
|
*/
|
||||||
public class DataResultFilterNode extends FilterNode {
|
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 ExplorerManager sourceEm;
|
||||||
private final DisplayableItemNodeVisitor<List<Action>> getActionsDIV;
|
private final DisplayableItemNodeVisitor<List<Action>> getActionsDIV;
|
||||||
private final DisplayableItemNodeVisitor<AbstractAction> getPreferredActionsDIV;
|
private final DisplayableItemNodeVisitor<AbstractAction> getPreferredActionsDIV;
|
||||||
@ -105,7 +114,7 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
@Override
|
@Override
|
||||||
public Action[] getActions(boolean popup) {
|
public Action[] getActions(boolean popup) {
|
||||||
|
|
||||||
List<Action> actions = new ArrayList<Action>();
|
List<Action> actions = new ArrayList<>();
|
||||||
|
|
||||||
final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal();
|
final DisplayableItemNode originalNode = (DisplayableItemNode) this.getOriginal();
|
||||||
actions.addAll(originalNode.accept(getActionsDIV));
|
actions.addAll(originalNode.accept(getActionsDIV));
|
||||||
@ -167,7 +176,7 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
//TODO all actions need to be consolidated in single place!
|
//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
|
//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
|
//merge predefined specific node actions if bban subclasses have their own
|
||||||
for (Action a : ban.getActions(true)) {
|
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 NewWindowViewAction("View in New Window", fn));
|
||||||
actions.add(new ExternalViewerAction("Open in External Viewer", fn));
|
actions.add(new ExternalViewerAction("Open in External Viewer", fn));
|
||||||
actions.add(null); // creates a menu separator
|
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));
|
actions.add(new HashSearchAction("Search for files with the same MD5 hash", fn));
|
||||||
|
|
||||||
//add file/result tag if itself is not a tag
|
//add file/result tag if itself is not a tag
|
||||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(new TagAction(f));
|
actions.add(fileTagAction);
|
||||||
actions.add(new TagAction(ba));
|
actions.add(resultTagAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((d = ban.getLookup().lookup(Directory.class)) != null) {
|
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 NewWindowViewAction("View in New Window", dn));
|
||||||
actions.add(new ExternalViewerAction("Open in External Viewer", dn));
|
actions.add(new ExternalViewerAction("Open in External Viewer", dn));
|
||||||
actions.add(null); // creates a menu separator
|
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
|
//add file/result tag if itself is not a tag
|
||||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(new TagAction(d));
|
actions.add(fileTagAction);
|
||||||
actions.add(new TagAction(ba));
|
actions.add(resultTagAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((vd = ban.getLookup().lookup(VirtualDirectory.class)) != null) {
|
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 NewWindowViewAction("View in New Window", dn));
|
||||||
actions.add(new ExternalViewerAction("Open in External Viewer", dn));
|
actions.add(new ExternalViewerAction("Open in External Viewer", dn));
|
||||||
actions.add(null); // creates a menu separator
|
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
|
//add file/result tag if itself is not a tag
|
||||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(new TagAction(d));
|
actions.add(fileTagAction);
|
||||||
actions.add(new TagAction(ba));
|
actions.add(resultTagAction);
|
||||||
}
|
}
|
||||||
} else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) {
|
} else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) {
|
||||||
LayoutFileNode lfn = new LayoutFileNode(lf);
|
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 NewWindowViewAction("View in New Window", lfn));
|
||||||
actions.add(new ExternalViewerAction("Open in External Viewer", lfn));
|
actions.add(new ExternalViewerAction("Open in External Viewer", lfn));
|
||||||
actions.add(null); // creates a menu separator
|
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
|
//add tag if itself is not a tag
|
||||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(new TagAction(lf));
|
actions.add(fileTagAction);
|
||||||
actions.add(new TagAction(ba));
|
actions.add(resultTagAction);
|
||||||
}
|
}
|
||||||
} else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null
|
} else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null
|
||||||
|| (locF = ban.getLookup().lookup(DerivedFile.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 NewWindowViewAction("View in New Window", locfn));
|
||||||
actions.add(new ExternalViewerAction("Open in External Viewer", locfn));
|
actions.add(new ExternalViewerAction("Open in External Viewer", locfn));
|
||||||
actions.add(null); // creates a menu separator
|
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
|
//add tag if itself is not a tag
|
||||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(new TagAction(lf));
|
actions.add(fileTagAction);
|
||||||
actions.add(new TagAction(ba));
|
actions.add(resultTagAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +287,7 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
@Override
|
@Override
|
||||||
protected List<Action> defaultVisit(DisplayableItemNode ditem) {
|
protected List<Action> defaultVisit(DisplayableItemNode ditem) {
|
||||||
//preserve the default node's actions
|
//preserve the default node's actions
|
||||||
List<Action> actions = new ArrayList<Action>();
|
List<Action> actions = new ArrayList<>();
|
||||||
|
|
||||||
for (Action action : ditem.getActions(true)) {
|
for (Action action : ditem.getActions(true)) {
|
||||||
actions.add(action);
|
actions.add(action);
|
||||||
|
@ -47,6 +47,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
class DirectoryTreeFilterNode extends FilterNode {
|
class DirectoryTreeFilterNode extends FilterNode {
|
||||||
|
|
||||||
private static final Action collapseAll = new CollapseAction("Collapse All");
|
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());
|
private static final Logger logger = Logger.getLogger(DirectoryTreeFilterNode.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -99,8 +100,7 @@ class DirectoryTreeFilterNode extends FilterNode {
|
|||||||
//extract dir action
|
//extract dir action
|
||||||
Directory dir = this.getLookup().lookup(Directory.class);
|
Directory dir = this.getLookup().lookup(Directory.class);
|
||||||
if (dir != null) {
|
if (dir != null) {
|
||||||
actions.add(new ExtractAction("Extract Directory",
|
actions.add(extractAction);
|
||||||
getOriginal()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// file search action
|
// file search action
|
||||||
|
@ -47,6 +47,13 @@ import org.sleuthkit.datamodel.VirtualDirectory;
|
|||||||
import org.sleuthkit.datamodel.Volume;
|
import org.sleuthkit.datamodel.Volume;
|
||||||
|
|
||||||
public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? extends Action>> {
|
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();
|
private static ExplorerNodeActionVisitor instance = new ExplorerNodeActionVisitor();
|
||||||
|
|
||||||
@ -101,39 +108,39 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
|||||||
@Override
|
@Override
|
||||||
public List<? extends Action> visit(final Directory d) {
|
public List<? extends Action> visit(final Directory d) {
|
||||||
List<Action> actions = new ArrayList<Action>();
|
List<Action> actions = new ArrayList<Action>();
|
||||||
actions.add(new TagAction(d));
|
actions.add(tagAction);
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<? extends Action> visit(final VirtualDirectory d) {
|
public List<? extends Action> visit(final VirtualDirectory d) {
|
||||||
List<Action> actions = new ArrayList<Action>();
|
List<Action> actions = new ArrayList<Action>();
|
||||||
actions.add(new TagAction(d));
|
actions.add(extractAction);
|
||||||
actions.add(new ExtractAction("Extract Directory", d));
|
actions.add(tagAction);
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<? extends Action> visit(final DerivedFile d) {
|
public List<? extends Action> visit(final DerivedFile d) {
|
||||||
List<Action> actions = new ArrayList<Action>();
|
List<Action> actions = new ArrayList<Action>();
|
||||||
actions.add(new ExtractAction("Extract File", d));
|
actions.add(extractAction);
|
||||||
actions.add(new TagAction(d));
|
actions.add(tagAction);
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<? extends Action> visit(final LocalFile d) {
|
public List<? extends Action> visit(final LocalFile d) {
|
||||||
List<Action> actions = new ArrayList<Action>();
|
List<Action> actions = new ArrayList<Action>();
|
||||||
actions.add(new ExtractAction("Extract File", d));
|
actions.add(extractAction);
|
||||||
actions.add(new TagAction(d));
|
actions.add(tagAction);
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
|
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
|
||||||
List<Action> actions = new ArrayList<Action>();
|
List<Action> actions = new ArrayList<Action>();
|
||||||
actions.add(new ExtractAction("Extract File", d));
|
actions.add(extractAction);
|
||||||
actions.add(new TagAction(d));
|
actions.add(tagAction);
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,11 +32,15 @@ import org.netbeans.api.progress.ProgressHandle;
|
|||||||
import org.netbeans.api.progress.ProgressHandleFactory;
|
import org.netbeans.api.progress.ProgressHandleFactory;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.util.Cancellable;
|
import org.openide.util.Cancellable;
|
||||||
|
import org.openide.util.Lookup;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
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.FileUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor;
|
import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.Tags;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.ContentVisitor;
|
import org.sleuthkit.datamodel.ContentVisitor;
|
||||||
@ -47,64 +51,10 @@ import org.sleuthkit.datamodel.Directory;
|
|||||||
*/
|
*/
|
||||||
public final class ExtractAction extends AbstractAction {
|
public final class ExtractAction extends AbstractAction {
|
||||||
|
|
||||||
private static final InitializeContentVisitor initializeCV = new InitializeContentVisitor();
|
|
||||||
private AbstractFile content;
|
|
||||||
private Logger logger = Logger.getLogger(ExtractAction.class.getName());
|
private Logger logger = Logger.getLogger(ExtractAction.class.getName());
|
||||||
|
|
||||||
public ExtractAction(String title, Node contentNode) {
|
public ExtractAction() {
|
||||||
super(title);
|
super("Export");
|
||||||
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<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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,10 +64,35 @@ public final class ExtractAction extends AbstractAction {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
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
|
// Get content and check that it's okay to overwrite existing content
|
||||||
JFileChooser fc = new JFileChooser();
|
JFileChooser fc = new JFileChooser();
|
||||||
fc.setCurrentDirectory(new File(Case.getCurrentCase().getCaseDirectory()));
|
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());
|
int returnValue = fc.showSaveDialog((Component) e.getSource());
|
||||||
|
|
||||||
if (returnValue == JFileChooser.APPROVE_OPTION) {
|
if (returnValue == JFileChooser.APPROVE_OPTION) {
|
||||||
@ -144,7 +119,7 @@ public final class ExtractAction extends AbstractAction {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
ExtractFileThread extract = new ExtractFileThread();
|
ExtractFileThread extract = new ExtractFileThread();
|
||||||
extract.init(this.content, e, destination);
|
extract.init(file, e, destination);
|
||||||
extract.execute();
|
extract.execute();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.log(Level.WARNING, "Unable to start background thread.", ex);
|
logger.log(Level.WARNING, "Unable to start background thread.", ex);
|
||||||
@ -231,5 +206,4 @@ public final class ExtractAction extends AbstractAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
51
Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java
Executable file
51
Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java
Executable 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,102 +21,38 @@ package org.sleuthkit.autopsy.directorytree;
|
|||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.JMenu;
|
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.util.actions.Presenter;
|
import org.openide.util.actions.Presenter;
|
||||||
|
import org.openide.util.Lookup;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import org.sleuthkit.datamodel.ContentVisitor;
|
|
||||||
import org.sleuthkit.datamodel.Directory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action on a file or artifact that adds a tag and
|
* Action on a file or artifact that adds a tag and reloads the directory tree.
|
||||||
* reloads the directory tree. Supports tagging of AbstractFiles and
|
* Supports tagging of AbstractFiles and BlackboardArtifacts.
|
||||||
* BlackboardArtifacts.
|
|
||||||
*
|
|
||||||
* TODO add use enters description and hierarchy (TSK_TAG_NAME with slashes)
|
|
||||||
*/
|
*/
|
||||||
public class TagAction extends AbstractAction implements Presenter.Popup {
|
public abstract 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JMenuItem getPopupPresenter() {
|
public JMenuItem getPopupPresenter() {
|
||||||
return tagMenu;
|
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");
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
return null;
|
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
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
// Do nothing - this action should never be performed
|
// Do nothing - this action should never be performed
|
||||||
|
@ -30,28 +30,50 @@ import javax.swing.JFrame;
|
|||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
import org.openide.windows.WindowManager;
|
import org.openide.windows.WindowManager;
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
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.
|
* Tag dialog for tagging files and results. User enters an optional comment.
|
||||||
*/
|
*/
|
||||||
public class TagAndCommentDialog extends JDialog {
|
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 static final String NO_TAG_MESSAGE = "No Tags";
|
||||||
|
private String tagName = "";
|
||||||
|
private String comment = "";
|
||||||
|
|
||||||
private Taggable taggable;
|
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
|
* Creates new form TagDialog
|
||||||
*/
|
*/
|
||||||
public TagAndCommentDialog(Taggable taggable) {
|
private TagAndCommentDialog() {
|
||||||
super((JFrame)WindowManager.getDefault().getMainWindow(), "Tag and Comment", true);
|
super((JFrame)WindowManager.getDefault().getMainWindow(), "Tag and Comment", true);
|
||||||
|
|
||||||
this.taggable = taggable;
|
|
||||||
|
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
// Close the dialog when Esc is pressed
|
// 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);
|
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
|
||||||
ActionMap actionMap = getRootPane().getActionMap();
|
ActionMap actionMap = getRootPane().getActionMap();
|
||||||
actionMap.put(cancelName, new AbstractAction() {
|
actionMap.put(cancelName, new AbstractAction() {
|
||||||
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
//doClose(RET_CANCEL);
|
|
||||||
dispose();
|
dispose();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -82,14 +104,9 @@ public class TagAndCommentDialog extends JDialog {
|
|||||||
//center it
|
//center it
|
||||||
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
||||||
|
|
||||||
customizeComponent();
|
|
||||||
|
|
||||||
setVisible(true); // blocks
|
setVisible(true); // blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
private void customizeComponent() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to initialize the form.
|
* 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
|
* 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
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
||||||
//doClose(RET_OK);
|
tagName = (String)tagCombo.getSelectedItem();
|
||||||
|
comment = commentText.getText();
|
||||||
// get the selected tag and comment
|
|
||||||
String selectedTag = (String)tagCombo.getSelectedItem();
|
|
||||||
String comment = commentText.getText();
|
|
||||||
|
|
||||||
// create the tag
|
|
||||||
taggable.createTag(selectedTag, comment);
|
|
||||||
|
|
||||||
refreshDirectoryTree();
|
|
||||||
|
|
||||||
dispose();
|
dispose();
|
||||||
}//GEN-LAST:event_okButtonActionPerformed
|
}//GEN-LAST:event_okButtonActionPerformed
|
||||||
|
|
||||||
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
||||||
//doClose(RET_CANCEL);
|
|
||||||
dispose();
|
dispose();
|
||||||
}//GEN-LAST:event_cancelButtonActionPerformed
|
}//GEN-LAST:event_cancelButtonActionPerformed
|
||||||
|
|
||||||
@ -218,14 +225,12 @@ public class TagAndCommentDialog extends JDialog {
|
|||||||
* Closes the dialog
|
* Closes the dialog
|
||||||
*/
|
*/
|
||||||
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
|
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
|
||||||
//doClose(RET_CANCEL);
|
|
||||||
dispose();
|
dispose();
|
||||||
}//GEN-LAST:event_closeDialog
|
}//GEN-LAST:event_closeDialog
|
||||||
|
|
||||||
private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
|
private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
|
||||||
String newTagName = CreateTagDialog.getNewTagNameDialog(null);
|
String newTagName = CreateTagDialog.getNewTagNameDialog(null);
|
||||||
if (newTagName != null) {
|
if (newTagName != null) {
|
||||||
//tagsModel.addElement(newTagName);
|
|
||||||
tagCombo.addItem(newTagName);
|
tagCombo.addItem(newTagName);
|
||||||
tagCombo.setSelectedItem(newTagName);
|
tagCombo.setSelectedItem(newTagName);
|
||||||
}
|
}
|
||||||
@ -240,12 +245,4 @@ public class TagAndCommentDialog extends JDialog {
|
|||||||
private javax.swing.JComboBox tagCombo;
|
private javax.swing.JComboBox tagCombo;
|
||||||
private javax.swing.JLabel tagLabel;
|
private javax.swing.JLabel tagLabel;
|
||||||
// End of variables declaration//GEN-END:variables
|
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,39 +23,26 @@ import java.awt.event.ActionListener;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.JMenu;
|
import javax.swing.JMenu;
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
|
import org.openide.nodes.Node;
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
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;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The menu that results when one right-clicks on a file or artifact.
|
* 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;
|
private Node[] nodes;
|
||||||
|
|
||||||
public TagMenu(AbstractFile file) {
|
public TagMenu(String menuItemText, Node[] selectedNodes) {
|
||||||
super("Tag File");
|
super(menuItemText);
|
||||||
tagCreator = new TaggableFile(file);
|
this.nodes = selectedNodes;
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TagMenu(BlackboardArtifact bba) {
|
// Create the 'Quick Tag' sub-menu and add it to the tag menu.
|
||||||
super("Tag Result");
|
|
||||||
tagCreator = new TaggableBlackboardArtifact(bba);
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init() {
|
|
||||||
|
|
||||||
// create the 'Quick Tag' menu and add it to the 'Tag File' menu
|
|
||||||
JMenu quickTagMenu = new JMenu("Quick Tag");
|
JMenu quickTagMenu = new JMenu("Quick Tag");
|
||||||
add(quickTagMenu);
|
add(quickTagMenu);
|
||||||
|
|
||||||
// create the 'Quick Tag' sub-menu items and add them to the 'Quick Tag' menu
|
// Get the existing tag names.
|
||||||
List<String> tagNames = Tags.getTagNames();
|
List<String> tagNames = Tags.getTagNames();
|
||||||
if (tagNames.isEmpty()) {
|
if (tagNames.isEmpty()) {
|
||||||
JMenuItem empty = new JMenuItem("No tags");
|
JMenuItem empty = new JMenuItem("No tags");
|
||||||
@ -63,46 +50,56 @@ public class TagMenu extends JMenu {
|
|||||||
quickTagMenu.add(empty);
|
quickTagMenu.add(empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a menu item for each existing tag name to the 'Quick Tag' menu.
|
||||||
for (final String tagName : tagNames) {
|
for (final String tagName : tagNames) {
|
||||||
JMenuItem tagItem = new JMenuItem(tagName);
|
JMenuItem tagNameItem = new JMenuItem(tagName);
|
||||||
tagItem.addActionListener(new ActionListener() {
|
tagNameItem.addActionListener(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
tagCreator.createTag(tagName, "");
|
tagNodes(tagName, "");
|
||||||
refreshDirectoryTree();
|
refreshDirectoryTree();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
quickTagMenu.add(tagItem);
|
quickTagMenu.add(tagNameItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
quickTagMenu.addSeparator();
|
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");
|
JMenuItem newTagMenuItem = new JMenuItem("New Tag");
|
||||||
newTagMenuItem.addActionListener(new ActionListener() {
|
newTagMenuItem.addActionListener(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
String newTagName = CreateTagDialog.getNewTagNameDialog(null);
|
String tagName = CreateTagDialog.getNewTagNameDialog(null);
|
||||||
if (newTagName != null) {
|
if (tagName != null) {
|
||||||
tagCreator.createTag(newTagName, "");
|
tagNodes(tagName, "");
|
||||||
refreshDirectoryTree();
|
refreshDirectoryTree();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// add the 'New Tag' menu item to the 'Quick Tag' menu
|
|
||||||
quickTagMenu.add(newTagMenuItem);
|
quickTagMenu.add(newTagMenuItem);
|
||||||
|
|
||||||
JMenuItem newTagItem = new JMenuItem("Tag and Comment");
|
// Create the 'Tag and Comment' menu item and add it to the tag menu.
|
||||||
newTagItem.addActionListener(new ActionListener() {
|
JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment");
|
||||||
|
tagAndCommentItem.addActionListener(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
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() {
|
private void refreshDirectoryTree() {
|
||||||
//TODO instead should send event to node children, which will call its refresh() / refreshKeys()
|
//TODO instead should send event to node children, which will call its refresh() / refreshKeys()
|
||||||
DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance();
|
DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user