From edb05572e8c25079cc75a93560092b35b75c81bb Mon Sep 17 00:00:00 2001 From: APriestman Date: Fri, 29 May 2015 09:45:52 -0400 Subject: [PATCH 001/198] Catch case where Content is null --- Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java index 3223e29382..7e1dd9aa88 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java @@ -139,7 +139,7 @@ public final class ContentUtils { return TimeZone.getDefault(); } } - } catch (TskException ex) { + } catch (TskException | NullPointerException ex) { return TimeZone.getDefault(); } } From f433651b53690e85d9252c3d62990801ad8e7a67 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Mon, 1 Jun 2015 15:08:04 -0400 Subject: [PATCH 002/198] Added back in feature to open add data source iwzard if empty case is open --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index db1250ebf7..eb2ecf9011 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -1098,9 +1098,11 @@ public class Case implements SleuthkitCase.ErrorObserver { if (toChangeTo.hasData()) { // open all top components CoreComponentControl.openCoreWindows(); - } else { - // close all top components + } + // if case is empty, close windows and launch add data source wizard + else { CoreComponentControl.closeCoreWindows(); + Case.runAddImageAction(); } } else { // case is closed // close all top components first From 6bfae6adbc7a9be37f94308c1a672d0d9a773937 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Wed, 10 Jun 2015 23:04:44 -0400 Subject: [PATCH 003/198] Added comments to datamodel nodes --- .../autopsy/datamodel/AutopsyItemVisitor.java | 34 +++----- .../datamodel/AutopsyVisitableItem.java | 4 +- .../autopsy/datamodel/ContentNode.java | 10 ++- .../autopsy/datamodel/ContentNodeVisitor.java | 22 ++--- .../autopsy/datamodel/DataSources.java | 4 +- .../datamodel/DisplayableItemNode.java | 9 +- .../datamodel/DisplayableItemNodeVisitor.java | 84 +++++++------------ .../sleuthkit/autopsy/datamodel/FileNode.java | 3 + .../autopsy/datamodel/LocalFileNode.java | 3 + .../DirectoryTreeFilterChildren.java | 17 +++- 10 files changed, 89 insertions(+), 101 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java index 42d03c59a2..9d6040cbbd 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java @@ -18,46 +18,38 @@ */ package org.sleuthkit.autopsy.datamodel; - interface AutopsyItemVisitor { - T visit(ExtractedContent ec); +/** + * This visitor goes over the AutopsyVisitableItems, which are currently + * the nodes in the tree that are structural and not nodes that are from + * Sleuthkit-based data model objects. + */ +interface AutopsyItemVisitor { + T visit(DataSources i); + + T visit(Views v); T visit(FileTypeExtensionFilters sf); - T visit(FileTypeExtensionFilters.RootFilter fsf); - T visit(FileTypeExtensionFilters.DocumentFilter df); - T visit(FileTypeExtensionFilters.ExecutableFilter ef); - T visit(RecentFiles rf); - T visit(RecentFiles.RecentFilesFilter rff); - T visit(DeletedContent dc); - T visit(DeletedContent.DeletedContentFilter dcf); - T visit(FileSize fs); - T visit(FileSize.FileSizeFilter fsf); + + T visit(ExtractedContent ec); T visit(KeywordHits kh); - T visit(HashsetHits hh); - T visit(EmailExtracted ee); + T visit(InterestingHits ih); + T visit(Results r); T visit(Tags tagsNodeKey); - T visit(InterestingHits ih); - - T visit(DataSources i); - - T visit(Views v); - - T visit(Results r); - T visit(Reports reportsItem); static abstract public class Default implements AutopsyItemVisitor { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyVisitableItem.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyVisitableItem.java index 90d35b307c..4cade12048 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyVisitableItem.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyVisitableItem.java @@ -19,7 +19,9 @@ package org.sleuthkit.autopsy.datamodel; /** - * Abstraction for certain top level items displayed in the GUI + * AutopsyVisitableItems are the nodes in the directory tree that + * are for structure only. They are not associated with content + * objects. */ interface AutopsyVisitableItem { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNode.java index 89b7876015..7134d9bf50 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNode.java @@ -22,12 +22,14 @@ import org.openide.nodes.Children; import org.openide.util.Lookup; /** - * Interface class that all Data nodes inherit from. + * Content Nodes are for the content objects in the data + * source area of the tree. Other parts of the directory + * tree do not extend this. + * * Provides basic information such as ID, parent ID, etc. */ - - abstract class ContentNode extends DisplayableItemNode{ - + abstract class ContentNode extends DisplayableItemNode { + public ContentNode(Children children) { super(children); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java index 4fd9d12c54..b7dd5de0ee 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java @@ -19,24 +19,24 @@ package org.sleuthkit.autopsy.datamodel; /** - * Interface for visitor pattern on ContentNodes + * Visitor Pattern interface that goes over Content nodes + * in the data source area of the tree. + * + * The DisplayableItemNodeVisitor goes over all nodes in the tree. + * * @param visit method return type */ interface ContentNodeVisitor { - - T visit(DirectoryNode dn); - - T visit(FileNode fn); - + T visit(ImageNode in); - + T visit(VirtualDirectoryNode lcn); T visit(VolumeNode vn); - - T visit(LayoutFileNode lcn); - + T visit(DirectoryNode dn); + T visit(FileNode fn); + T visit(LayoutFileNode lcn); T visit(LocalFileNode dfn); - T visit(VirtualDirectoryNode lcn); + /** * Visitor with an implementable default behavior for all types. Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java index 53056d7039..2e255f3042 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSources.java @@ -20,9 +20,9 @@ package org.sleuthkit.autopsy.datamodel; /** - * Images nodes support + * Root node to store the data sources in a case */ -public class DataSources implements AutopsyVisitableItem{ +public class DataSources implements AutopsyVisitableItem { public DataSources() { } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNode.java index 9d150d53ad..74ef66a277 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 - 2013 Basis Technology Corp. + * Copyright 2011 - 2015 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,10 +23,11 @@ import org.openide.nodes.Children; import org.openide.util.Lookup; /** - * Interface for all displayable Nodes + * A DisplayableItem is any node in the Autopsy directory tree. + * All of the nodes in the tree will eventually extend this. + * This includes the data source, views, extracted results, etc. areas. */ public abstract class DisplayableItemNode extends AbstractNode { - public DisplayableItemNode(Children children) { super(children); } @@ -35,6 +36,6 @@ public abstract class DisplayableItemNode extends AbstractNode { super(children, lookup); } - abstract public boolean isLeafTypeNode(); + public abstract boolean isLeafTypeNode(); public abstract T accept(DisplayableItemNodeVisitor v); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 4a47fab11f..f185b9da49 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 - 2013 Basis Technology Corp. + * Copyright 2011 - 2015 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,86 +24,62 @@ import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNod import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootNode; /** - * Visitor pattern implementation for DisplayableItemNodes + * Visitor pattern that goes over all nodes in the directory tree. + * This includes extracted content, reports, and the data sources area. */ public interface DisplayableItemNodeVisitor { + /* Data Sources Area */ + T visit(DataSourcesNode in); + T visit(LayoutFileNode lfn); + T visit(LocalFileNode dfn); + T visit(VirtualDirectoryNode ldn); T visit(DirectoryNode dn); - T visit(FileNode fn); - T visit(ImageNode in); - T visit(VolumeNode vn); - T visit(BlackboardArtifactNode ban); - - T visit(ExtractedContent.TypeNode atn); - - T visit(ExtractedContent.RootNode ecn); - + /* Views Area */ + T visit(ViewsNode vn); T visit(FileTypeNode fsfn); - T visit(DeletedContentNode dcn); - T visit(DeletedContentsNode dcn); - T visit(FileSizeRootNode fsrn); - T visit(FileSizeNode fsn); - T visit(FileTypesNode sfn); - T visit(RecentFilesNode rfn); - T visit(RecentFilesFilterNode rffn); - - T visit(KeywordHits.RootNode khrn); - - T visit(KeywordHits.ListNode khsn); - - T visit(KeywordHits.TermNode khmln); - - T visit(HashsetHits.RootNode hhrn); - - T visit(HashsetHits.HashsetNameNode hhsn); - - T visit(EmailExtracted.RootNode eern); - - T visit(EmailExtracted.AccountNode eean); - - T visit(EmailExtracted.FolderNode eefn); - - T visit(Tags.RootNode node); + + + /* Extracted Results Area */ + T visit(ResultsNode rn); + T visit(BlackboardArtifactNode ban); + T visit(ExtractedContent.TypeNode atn); + T visit(ExtractedContent.RootNode ecn); + T visit(KeywordHits.RootNode khrn); + T visit(KeywordHits.ListNode khsn); + T visit(KeywordHits.TermNode khmln); + T visit(HashsetHits.RootNode hhrn); + T visit(HashsetHits.HashsetNameNode hhsn); + T visit(EmailExtracted.RootNode eern); + T visit(EmailExtracted.AccountNode eean); + T visit(EmailExtracted.FolderNode eefn); T visit(InterestingHits.RootNode ihrn); - T visit(InterestingHits.SetNameNode ihsn); + + /* Tags */ + T visit(Tags.RootNode node); T visit(Tags.TagNameNode node); - T visit(Tags.ContentTagTypeNode node); - T visit(ContentTagNode node); - T visit(Tags.BlackboardArtifactTagTypeNode node); - T visit(BlackboardArtifactTagNode node); - T visit(ViewsNode vn); - - T visit(ResultsNode rn); - - T visit(DataSourcesNode in); - - T visit(LayoutFileNode lfn); - - T visit(LocalFileNode dfn); - - T visit(VirtualDirectoryNode ldn); - + + /* Reports */ T visit(Reports.ReportsListNode reportsNode); - T visit(Reports.ReportNode reportNode); /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 2acd46e80e..ef7d82e4b8 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -177,6 +177,9 @@ public class FileNode extends AbstractFsContentNode { @Override public boolean isLeafTypeNode() { + // This seems wrong, but it also seems that it is never called + // because the visitor to figure out if there are children or + // not will check if it has children using the Content API return true; } } \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index e368271a89..ccaeb7f6ef 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -110,6 +110,9 @@ public class LocalFileNode extends AbstractAbstractFileNode { @Override public boolean isLeafTypeNode() { + // This seems wrong, but it also seems that it is never called + // because the visitor to figure out if there are children or + // not will check if it has children using the Content API return true; //!this.hasContentChildren(); } } \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java index 7d85a1b2dd..e67844a1d7 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeFilterChildren.java @@ -69,25 +69,34 @@ class DirectoryTreeFilterChildren extends FilterNode.Children { return new DirectoryTreeFilterNode(arg0, createChildren); } + + + /* This method takes in a node as an argument and will create + * a new one if it should be displayed in the tree. If it is + * to be displayed, it also figures out if it is a leaf or not + * (i.e. should it have a + sign in the tree). + * + * It does NOT create children nodes + */ @Override protected Node[] createNodes(Node origNode) { if (origNode == null || !(origNode instanceof DisplayableItemNode)) { return new Node[]{}; } + // Shoudl this node be displayed in the tree or not final DisplayableItemNode diNode = (DisplayableItemNode) origNode; - if (diNode.accept(showItemV) == false) { //do not show return new Node[]{}; } - // filter out the FileNode and the "." and ".." directories - // do not set children, if we know the node type is a leaf node type + // If it is going to be displayed, then determine if it should + // have a '+' next to it based on if it has children of itself. + // We will filter out the "." and ".." directories final boolean isLeaf = diNode.accept(isLeafItemV); return new Node[]{this.copyNode(origNode, !isLeaf)}; - } /** From 23e17c3a7764149290b2e490f2e07a89d4d266d9 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Wed, 10 Jun 2015 23:15:37 -0400 Subject: [PATCH 004/198] revert previous commit to open wizard --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index eb2ecf9011..db1250ebf7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -1098,11 +1098,9 @@ public class Case implements SleuthkitCase.ErrorObserver { if (toChangeTo.hasData()) { // open all top components CoreComponentControl.openCoreWindows(); - } - // if case is empty, close windows and launch add data source wizard - else { + } else { + // close all top components CoreComponentControl.closeCoreWindows(); - Case.runAddImageAction(); } } else { // case is closed // close all top components first From 820135d7723c229a1028ace0e458d3852f018310 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 11 Jun 2015 00:40:07 -0400 Subject: [PATCH 005/198] Created Keys class for DataSource to update more cleanly when new data sources are added --- .../datamodel/AbstractContentChildren.java | 6 +- .../autopsy/datamodel/DataSourcesNode.java | 58 ++++++++++++++++++- .../DirectoryTreeTopComponent.java | 3 +- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index 77ca0752fb..0719a18c3c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -176,11 +176,7 @@ abstract class AbstractContentChildren extends Keys { @Override public AbstractNode visit(DataSources i) { - try { - return new DataSourcesNode(Case.getCurrentCase().getDataSources()); - } catch (TskCoreException ex) { - return defaultVisit(i); - } + return new DataSourcesNode(); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index 4d0ed1feb4..1d45eec0dc 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -18,26 +18,78 @@ */ package org.sleuthkit.autopsy.datamodel; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Collections; import java.util.List; - import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; /** * Nodes for the images */ public class DataSourcesNode extends DisplayableItemNode { - public static final String NAME = NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.name"); + // NOTE: The images passed in via argument will be ignored. + @Deprecated public DataSourcesNode(List images) { - super(new RootContentChildren(images), Lookups.singleton(NAME)); + super(new DataSourcesNodeChildren(), Lookups.singleton(NAME)); + init(); + } + + public DataSourcesNode() { + super(new DataSourcesNodeChildren(), Lookups.singleton(NAME)); + init(); + } + + private void init() { setName(NAME); setDisplayName(NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); //NON-NLS } + + /* Custom Keys implementation that listens for new data sources being added. */ + private static class DataSourcesNodeChildren extends AbstractContentChildren { + private static final Logger logger = Logger.getLogger(DataSourcesNodeChildren.class.getName()); + + public DataSourcesNodeChildren() { + super(); + } + + private final PropertyChangeListener pcl = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + String eventType = evt.getPropertyName(); + if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { + addNotify(); + } + } + }; + + + @Override + protected void addNotify() { + Case.addPropertyChangeListener(pcl); + try { + setKeys(Case.getCurrentCase().getDataSources()); + } catch (TskCoreException | IllegalStateException ex) { + logger.severe("Error getting data sources: " + ex.getMessage()); // NON-NLS + setKeys(Collections.EMPTY_SET); + } + } + + @Override + protected void removeNotify() { + Case.removePropertyChangeListener(pcl); + setKeys(Collections.EMPTY_SET); + } + } @Override public boolean isLeafTypeNode() { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 8161914bb9..c22515dfe2 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -573,7 +573,8 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } } // if the image is added to the case else if (changed.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { - componentOpened(); + // we don't need to do anything in here. + // DataSourcesNode is listening for these events and updates itself } // change in node selection else if (changed.equals(ExplorerManager.PROP_SELECTED_NODES)) { From eab558bac5235889e409882bfd495977affbb459 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 11 Jun 2015 00:42:32 -0400 Subject: [PATCH 006/198] formatting --- .../autopsy/datamodel/DataSourcesNode.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index 1d45eec0dc..e247882240 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -34,6 +34,7 @@ import org.sleuthkit.datamodel.TskCoreException; * Nodes for the images */ public class DataSourcesNode extends DisplayableItemNode { + public static final String NAME = NbBundle.getMessage(DataSourcesNode.class, "DataSourcesNode.name"); // NOTE: The images passed in via argument will be ignored. @@ -42,22 +43,23 @@ public class DataSourcesNode extends DisplayableItemNode { super(new DataSourcesNodeChildren(), Lookups.singleton(NAME)); init(); } - + public DataSourcesNode() { super(new DataSourcesNodeChildren(), Lookups.singleton(NAME)); init(); } - - private void init() { + + private void init() { setName(NAME); setDisplayName(NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/image.png"); //NON-NLS } - + /* Custom Keys implementation that listens for new data sources being added. */ private static class DataSourcesNodeChildren extends AbstractContentChildren { + private static final Logger logger = Logger.getLogger(DataSourcesNodeChildren.class.getName()); - + public DataSourcesNodeChildren() { super(); } @@ -71,7 +73,6 @@ public class DataSourcesNode extends DisplayableItemNode { } } }; - @Override protected void addNotify() { From 6648873dbb6dd2a4cd01514b88cd0d0b20b7fabe Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 11 Jun 2015 00:51:36 -0400 Subject: [PATCH 007/198] added reloadKeys method to DataSourcesNode --- .../autopsy/datamodel/DataSourcesNode.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index e247882240..ba162f6e25 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -69,7 +69,7 @@ public class DataSourcesNode extends DisplayableItemNode { public void propertyChange(PropertyChangeEvent evt) { String eventType = evt.getPropertyName(); if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { - addNotify(); + reloadKeys(); } } }; @@ -77,6 +77,16 @@ public class DataSourcesNode extends DisplayableItemNode { @Override protected void addNotify() { Case.addPropertyChangeListener(pcl); + reloadKeys(); + } + + @Override + protected void removeNotify() { + Case.removePropertyChangeListener(pcl); + setKeys(Collections.EMPTY_SET); + } + + private void reloadKeys() { try { setKeys(Case.getCurrentCase().getDataSources()); } catch (TskCoreException | IllegalStateException ex) { @@ -84,12 +94,6 @@ public class DataSourcesNode extends DisplayableItemNode { setKeys(Collections.EMPTY_SET); } } - - @Override - protected void removeNotify() { - Case.removePropertyChangeListener(pcl); - setKeys(Collections.EMPTY_SET); - } } @Override From d3b66102c59a7985f0f979d3542a78d6ef24f687 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 11 Jun 2015 01:14:19 -0400 Subject: [PATCH 008/198] Expose child class so that it can be casted in DirectoryTree --- .../autopsy/datamodel/DataSourcesNode.java | 22 +++++++++++++++++-- .../DirectoryTreeTopComponent.java | 2 +- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index ba162f6e25..2a1e62d9e1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.openide.nodes.Sheet; @@ -56,10 +57,13 @@ public class DataSourcesNode extends DisplayableItemNode { } /* Custom Keys implementation that listens for new data sources being added. */ - private static class DataSourcesNodeChildren extends AbstractContentChildren { + // @@@ This can become private once DirectoryTree doesn't want to refresh the entire tree + public static class DataSourcesNodeChildren extends AbstractContentChildren { private static final Logger logger = Logger.getLogger(DataSourcesNodeChildren.class.getName()); + List currentKeys = new ArrayList(); + public DataSourcesNodeChildren() { super(); } @@ -88,12 +92,26 @@ public class DataSourcesNode extends DisplayableItemNode { private void reloadKeys() { try { - setKeys(Case.getCurrentCase().getDataSources()); + currentKeys.addAll(Case.getCurrentCase().getDataSources()); + setKeys(currentKeys); } catch (TskCoreException | IllegalStateException ex) { logger.severe("Error getting data sources: " + ex.getMessage()); // NON-NLS setKeys(Collections.EMPTY_SET); } } + + /** + * Refresh all content keys + * This creates new nodes of keys have changed. + */ + // I think this goes away once we get more listeners in place + // It was added as an interim stage + @Deprecated + public void refreshContentKeys() { + for (Content key : currentKeys) { + refreshKey(key); + } + } } @Override diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index c22515dfe2..8d0a814355 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -779,7 +779,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat Node imagesNode = imagesNodeOrig.getNode(); - RootContentChildren contentRootChildren = (RootContentChildren) imagesNode.getChildren(); + DataSourcesNode.DataSourcesNodeChildren contentRootChildren = (DataSourcesNode.DataSourcesNodeChildren) imagesNode.getChildren(); contentRootChildren.refreshContentKeys(); //final TreeView tree = getTree(); From f82d53fabcaf079a32de37219dd9606cd92dcffa Mon Sep 17 00:00:00 2001 From: Sidhesh Mhatre Date: Thu, 11 Jun 2015 09:10:14 -0400 Subject: [PATCH 009/198] Excession logging issue fixed Embedded File Extractor Module no longer logs "Procession XYZ file..." messages. --- .../EmbeddedFileExtractorIngestModule.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java index faa1d5c31f..90da2dca79 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java @@ -132,8 +132,6 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule return ProcessResult.OK; } - logger.log(Level.INFO, "Processing with embedded file extractor: {0}", abstractFile.getName()); //NON-NLS - // call the archive extractor if archiveextraction flag is set. if (this.archivextraction) { archiveExtractor.unpack(abstractFile); @@ -172,4 +170,4 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule protected static String getLocalRootAbsPath(String localRootRelPath) { return moduleDirAbsolute + File.separator + localRootRelPath; } -} \ No newline at end of file +} From fa3adf63597a12701c4b0e3857c5e51785f07472 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 10:10:33 -0400 Subject: [PATCH 010/198] update to ControlsFX 8.20.9 --- CoreLibs/ivy.xml | 2 +- CoreLibs/nbproject/project.properties | 6 +++--- CoreLibs/nbproject/project.xml | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CoreLibs/ivy.xml b/CoreLibs/ivy.xml index ef93dcd0ad..e45de956c4 100644 --- a/CoreLibs/ivy.xml +++ b/CoreLibs/ivy.xml @@ -36,7 +36,7 @@ - + diff --git a/CoreLibs/nbproject/project.properties b/CoreLibs/nbproject/project.properties index 587d08f723..1bfc0f7c81 100644 --- a/CoreLibs/nbproject/project.properties +++ b/CoreLibs/nbproject/project.properties @@ -12,7 +12,7 @@ file.reference.commons-lang3-3.0.jar=release/modules/ext/commons-lang3-3.0.jar file.reference.commons-logging-1.1.2-javadoc.jar=release/modules/ext/commons-logging-1.1.2-javadoc.jar file.reference.commons-logging-1.1.2-sources.jar=release/modules/ext/commons-logging-1.1.2-sources.jar file.reference.commons-logging-1.1.2.jar=release/modules/ext/commons-logging-1.1.2.jar -file.reference.controlsfx-8.20.8.jar=release/modules/ext/controlsfx-8.20.8.jar +file.reference.controlsfx-8.20.9.jar=release/modules/ext/controlsfx-8.20.9.jar file.reference.dom4j-1.6.1.jar=release/modules/ext/dom4j-1.6.1.jar file.reference.geronimo-jms_1.1_spec-1.0.jar=release/modules/ext/geronimo-jms_1.1_spec-1.0.jar file.reference.gson-1.4.jar=release/modules/ext/gson-1.4.jar @@ -59,6 +59,6 @@ file.reference.xml-apis-1.0.b2.jar=release/modules/ext/xml-apis-1.0.b2.jar file.reference.xmlbeans-2.3.0.jar=release/modules/ext/xmlbeans-2.3.0.jar javac.source=1.7 javac.compilerargs=-Xlint -Xlint:-serial -javadoc.reference.controlsfx-8.20.8.jar=release/modules/ext/controlsfx-8.20.8-javadoc.jar +javadoc.reference.controlsfx-8.20.9.jar=release/modules/ext/controlsfx-8.20.9-javadoc.jar nbm.needs.restart=true -source.reference.controlsfx-8.20.8.jar=release/modules/ext/controlsfx-8.20.8-sources.jar +source.reference.controlsfx-8.20.9.jar=release/modules/ext/controlsfx-8.20.9-sources.jar diff --git a/CoreLibs/nbproject/project.xml b/CoreLibs/nbproject/project.xml index e5761ecd29..d5e9d24b5f 100644 --- a/CoreLibs/nbproject/project.xml +++ b/CoreLibs/nbproject/project.xml @@ -748,10 +748,6 @@ ext/jfxtras-fxml-8.0-r1-javadoc.jar release/modules/ext/jfxtras-fxml-8.0-r1-javadoc.jar - - ext/controlsfx-8.20.8.jar - release/modules/ext/controlsfx-8.20.8.jar - ext/jfxtras-fxml-8.0-r1.jar release/modules/ext/jfxtras-fxml-8.0-r1.jar @@ -772,6 +768,10 @@ ext/slf4j-simple-1.6.1.jar release/modules/ext/slf4j-simple-1.6.1.jar + + ext/controlsfx-8.20.9.jar + release/modules/ext/controlsfx-8.20.9.jar + ext/commons-lang3-3.0-javadoc.jar release/modules/ext/commons-lang3-3.0-javadoc.jar From 4876776d9972958afd828b552d75e278a907077e Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 10:12:26 -0400 Subject: [PATCH 011/198] change the project name in the build script --- ImageGallery/build.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ImageGallery/build.xml b/ImageGallery/build.xml index 4cbe0d1139..e3b252b7c3 100644 --- a/ImageGallery/build.xml +++ b/ImageGallery/build.xml @@ -2,7 +2,7 @@ - - Builds, tests, and runs the project com.basistech.imageanalysis. + + Builds, tests, and runs the project org.sleuthkit.autopsy.imagegallery. From 9d3453daceb5fd38b47a6f12f8c393437e1c2e9e Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 11:42:41 -0400 Subject: [PATCH 012/198] fix npe resulting from mising bundle property --- .../autopsy/imagegallery/Bundle.properties | 7 ++- .../ImageGalleryOptionsPanel.form | 34 +++++------ .../ImageGalleryOptionsPanel.java | 60 +++++++++---------- 3 files changed, 51 insertions(+), 50 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/Bundle.properties b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/Bundle.properties index e7ee7697b2..b7d2ba3d30 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/Bundle.properties +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/Bundle.properties @@ -4,9 +4,10 @@ OpenIDE-Module-Long-Description=\ It is not available on the sleuthkit.org site and has been distributed to limited users. OpenIDE-Module-Name=ImageGallery OpenIDE-Module-Short-Description=Advanced image and video gallery -ImageGalleryOptionsPanel.jLabel1.text=To minimize its startup times, Image Gallery will constantly update its internal database.
This can cause ingest to be slower if you do not need the Image Gallery features.
Use these settings to disable Image Gallery if you do not need it. ImageGalleryOptionsPanel.enabledForCaseBox.text=Enable Image Gallery updates for the current case. ImageGalleryOptionsPanel.enabledByDefaultBox.text=Enable Image Gallery for new cases by default. -ImageGalleryOptionsPanel.jTextArea2.text=If Image Gallery is disabled, only the fact that an update is needed is recorded. If Image Gallery is enabled after ingest, it will do one bulk update based on the results form ingest. If Image Gallery is disabled, you will be prompted to enable it when attempting to open its window. -ImageGalleryOptionsPanel.jLabel3.text= ImageGalleryOptionsPanel.enabledForCaseBox.toolTipText=If Image Gallery is disabled, only the fact that an update is needed is recorded. If Image Gallery is enabled after ingest, it will do one bulk update based on the results form ingest. If Image Gallery is disabled, you will be prompted to enable it when attempting to open its window. +ImageGalleryOptionsPanel.descriptionLabel.text=To minimize its startup times, Image Gallery will constantly update its internal database.
This can cause ingest to be slower if you do not need the Image Gallery features.
Use these settings to disable Image Gallery if you do not need it. +ImageGalleryOptionsPanel.furtherDescriptionArea.text=If Image Gallery is disabled, only the fact that an update is needed is recorded. If Image Gallery is enabled after ingest, it will do one bulk update based on the results form ingest. If Image Gallery is disabled, you will be prompted to enable it when attempting to open its window. +ImageGalleryOptionsPanel.unavailableDuringInjestLabel.text=This setting is unavailable during ingest. +ImageGalleryOptionsPanel.infoIconLabel.text= diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.form b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.form index b3e30d7a61..52fed374cc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.form +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.form @@ -21,18 +21,18 @@ - + - + - + - + @@ -43,17 +43,17 @@ - + - - + + - - + + @@ -84,14 +84,14 @@ - + - + - + @@ -103,7 +103,7 @@ - + @@ -111,23 +111,23 @@ - + - + - + - + diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.java index 3c0af2b516..be83d9e236 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.java @@ -59,10 +59,10 @@ final class ImageGalleryOptionsPanel extends javax.swing.JPanel { enabledByDefaultBox = new javax.swing.JCheckBox(); enabledForCaseBox = new javax.swing.JCheckBox(); - jLabel1 = new javax.swing.JLabel(); - jTextArea2 = new javax.swing.JTextArea(); - jLabel3 = new javax.swing.JLabel(); - jLabel2 = new javax.swing.JLabel(); + descriptionLabel = new javax.swing.JLabel(); + furtherDescriptionArea = new javax.swing.JTextArea(); + infoIconLabel = new javax.swing.JLabel(); + unavailableDuringInjestLabel = new javax.swing.JLabel(); org.openide.awt.Mnemonics.setLocalizedText(enabledByDefaultBox, org.openide.util.NbBundle.getMessage(ImageGalleryOptionsPanel.class, "ImageGalleryOptionsPanel.enabledByDefaultBox.text")); // NOI18N enabledByDefaultBox.addActionListener(new java.awt.event.ActionListener() { @@ -79,22 +79,22 @@ final class ImageGalleryOptionsPanel extends javax.swing.JPanel { } }); - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(ImageGalleryOptionsPanel.class, "ImageGalleryOptionsPanel.jLabel1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(ImageGalleryOptionsPanel.class, "ImageGalleryOptionsPanel.descriptionLabel.text")); // NOI18N - jTextArea2.setBackground(new java.awt.Color(240, 240, 240)); - jTextArea2.setColumns(20); - jTextArea2.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N - jTextArea2.setLineWrap(true); - jTextArea2.setRows(5); - jTextArea2.setText(NbBundle.getMessage(ImageGalleryOptionsPanel.class, "ImageGalleryOptionsPanel.jTextArea2.text")); // NOI18N - jTextArea2.setWrapStyleWord(true); - jTextArea2.setPreferredSize(new java.awt.Dimension(378, 74)); + furtherDescriptionArea.setBackground(new java.awt.Color(240, 240, 240)); + furtherDescriptionArea.setColumns(20); + furtherDescriptionArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + furtherDescriptionArea.setLineWrap(true); + furtherDescriptionArea.setRows(5); + furtherDescriptionArea.setText(NbBundle.getMessage(ImageGalleryOptionsPanel.class, "ImageGalleryOptionsPanel.furtherDescriptionArea.text")); // NOI18N + furtherDescriptionArea.setWrapStyleWord(true); + furtherDescriptionArea.setPreferredSize(new java.awt.Dimension(378, 74)); - jLabel3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/imagegallery/images/info-icon-16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel3, NbBundle.getMessage(ImageGalleryOptionsPanel.class, "ImageGalleryOptionsPanel.jLabel3.text")); // NOI18N + infoIconLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/imagegallery/images/info-icon-16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(infoIconLabel, NbBundle.getMessage(ImageGalleryOptionsPanel.class, "ImageGalleryOptionsPanel.infoIconLabel.text")); // NOI18N - jLabel2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/imagegallery/images/warning16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel2, NbBundle.getMessage(ImageGalleryOptionsPanel.class, "ImageGalleryOptionsPanel.jLabel2.text")); // NOI18N + unavailableDuringInjestLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/imagegallery/images/warning16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(unavailableDuringInjestLabel, NbBundle.getMessage(ImageGalleryOptionsPanel.class, "ImageGalleryOptionsPanel.unavailableDuringInjestLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -105,33 +105,33 @@ final class ImageGalleryOptionsPanel extends javax.swing.JPanel { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(21, 21, 21) - .addComponent(jLabel2)) + .addComponent(unavailableDuringInjestLabel)) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addGroup(layout.createSequentialGroup() .addGap(21, 21, 21) - .addComponent(jLabel3) + .addComponent(infoIconLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jTextArea2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(furtherDescriptionArea, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addComponent(enabledByDefaultBox) .addComponent(enabledForCaseBox) - .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) .addContainerGap(46, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(enabledByDefaultBox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(enabledForCaseBox) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(unavailableDuringInjestLabel) + .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel3) - .addComponent(jTextArea2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(infoIconLabel) + .addComponent(furtherDescriptionArea, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(45, 45, 45)) ); }// //GEN-END:initComponents @@ -174,11 +174,11 @@ final class ImageGalleryOptionsPanel extends javax.swing.JPanel { } // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel descriptionLabel; private javax.swing.JCheckBox enabledByDefaultBox; private javax.swing.JCheckBox enabledForCaseBox; - private javax.swing.JLabel jLabel1; - private javax.swing.JLabel jLabel2; - private javax.swing.JLabel jLabel3; - private javax.swing.JTextArea jTextArea2; + private javax.swing.JTextArea furtherDescriptionArea; + private javax.swing.JLabel infoIconLabel; + private javax.swing.JLabel unavailableDuringInjestLabel; // End of variables declaration//GEN-END:variables } From 33d1231c5c463608ca20c783560afb0b96f93724 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 13:24:41 -0400 Subject: [PATCH 013/198] fix npe caused by attempting to select all files in an empty group --- .../autopsy/imagegallery/FileIDSelectionModel.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileIDSelectionModel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileIDSelectionModel.java index 8a9f574926..5392a619d0 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileIDSelectionModel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileIDSelectionModel.java @@ -70,7 +70,11 @@ public class FileIDSelectionModel { public void clearAndSelectAll(Long... ids) { selected.clear(); selected.addAll(Arrays.asList(ids)); - setLastSelected(ids[ids.length - 1]); + if (ids.length > 0) { + setLastSelected(ids[ids.length - 1]); + } else { + setLastSelected(null); + } } public void clearAndSelect(Long id) { From f4f568bff131f6bb5e1a6a40beb2dc96f971fab4 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 13:27:31 -0400 Subject: [PATCH 014/198] GroupPane bug fixes: don't show context menu when right clicking empty group; create new slideshowpane to force category border update cleanup DrawableTile, DrawableView, DrawableViewBase, GroupPane. SlideShowView --- .../imagegallery/gui/DrawableTile.java | 14 ++- .../imagegallery/gui/DrawableView.java | 14 +-- .../imagegallery/gui/DrawableViewBase.java | 93 ++++++++++--------- .../autopsy/imagegallery/gui/GroupPane.java | 92 +++++++++--------- .../imagegallery/gui/MetaDataPane.java | 4 +- .../imagegallery/gui/SlideShowView.java | 61 ++++++------ 6 files changed, 143 insertions(+), 135 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java index 7a9cba6011..80f16a3d7a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java @@ -78,7 +78,7 @@ public class DrawableTile extends DrawableViewBase implements TagUtils.TagListen globalSelectionModel.lastSelectedProperty().addListener((observable, oldValue, newValue) -> { try { - setEffect(Objects.equals(newValue, fileID) ? LAST_SELECTED_EFFECT : null); + setEffect(Objects.equals(newValue, getFileID()) ? LAST_SELECTED_EFFECT : null); } catch (java.lang.IllegalStateException ex) { Logger.getLogger(DrawableTile.class.getName()).log(Level.WARNING, "Error displaying tile"); } @@ -86,9 +86,8 @@ public class DrawableTile extends DrawableViewBase implements TagUtils.TagListen } public DrawableTile(GroupPane gp) { - super(); + super(gp); FXMLConstructor.construct(this, "DrawableTile.fxml"); - groupPane = gp; } @Override @@ -103,7 +102,7 @@ public class DrawableTile extends DrawableViewBase implements TagUtils.TagListen @Override protected void updateSelectionState() { super.updateSelectionState(); - final boolean lastSelected = Objects.equals(globalSelectionModel.lastSelectedProperty().get(), fileID); + final boolean lastSelected = Objects.equals(globalSelectionModel.lastSelectedProperty().get(), getFileID()); Platform.runLater(() -> { setEffect(lastSelected ? LAST_SELECTED_EFFECT : null); }); @@ -111,7 +110,7 @@ public class DrawableTile extends DrawableViewBase implements TagUtils.TagListen @Override protected Runnable getContentUpdateRunnable() { - Image image = file.getThumbnail(); + Image image = getFile().getThumbnail(); return () -> { imageView.setImage(image); @@ -119,8 +118,7 @@ public class DrawableTile extends DrawableViewBase implements TagUtils.TagListen } @Override - @ThreadConfined(type = ThreadType.UI) - protected String getLabelText() { - return file.getName(); + protected String getTextForLabel() { + return getFile().getName(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 566fcb079b..8f91cdf932 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -48,7 +48,7 @@ public interface DrawableView extends TagUtils.TagListener { static final Border CAT0_BORDER = new Border(new BorderStroke(Category.ZERO.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); - Region getBorderable(); + Region getCategoryBorderRegion(); DrawableFile getFile(); @@ -83,8 +83,6 @@ public interface DrawableView extends TagUtils.TagListener { static Border getCategoryBorder(Category category) { switch (category) { - case ZERO: - return CAT0_BORDER; case ONE: return CAT1_BORDER; case TWO: @@ -94,8 +92,11 @@ public interface DrawableView extends TagUtils.TagListener { case FOUR: return CAT4_BORDER; case FIVE: - default: return CAT5_BORDER; + case ZERO: + default: + return CAT0_BORDER; + } } @@ -104,10 +105,11 @@ public interface DrawableView extends TagUtils.TagListener { final Category category = getFile().getCategory(); final Border border = hasHashHit() && (category == Category.ZERO) ? HASH_BORDER - : DrawableView.getCategoryBorder(category); + : getCategoryBorder(category); Platform.runLater(() -> { - getBorderable().setBorder(border); + getCategoryBorderRegion().setBorder(border); + getCategoryBorderRegion().requestLayout(); }); return category; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 6792d6d38f..23164f41fb 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -50,7 +50,6 @@ import javafx.scene.layout.Region; import javafx.scene.paint.Color; import javax.swing.Action; import javax.swing.SwingUtilities; -import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.actions.Presenter; import org.openide.windows.TopComponent; @@ -137,17 +136,22 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie static private ContextMenu contextMenu; - protected DrawableFile file; + private DrawableFile file; - protected Long fileID; + private Long fileID; /** * the groupPane this {@link DrawableViewBase} is embedded in */ - protected GroupPane groupPane; + final private GroupPane groupPane; + private boolean registered = false; - protected DrawableViewBase() { + GroupPane getGroupPane() { + return groupPane; + } + protected DrawableViewBase(GroupPane groupPane) { + this.groupPane = groupPane; globalSelectionModel.getSelected().addListener((Observable observable) -> { updateSelectionState(); }); @@ -254,11 +258,12 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie protected abstract Runnable getContentUpdateRunnable(); - protected abstract String getLabelText(); + protected abstract String getTextForLabel(); @SuppressWarnings("deprecation") protected void initialize() { followUpToggle.setOnAction((ActionEvent t) -> { + if (followUpToggle.isSelected() == true) { globalSelectionModel.clearAndSelect(fileID); try { @@ -273,7 +278,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie // remove file from old category group controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); - List contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(getFile()); + List contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(file); for (ContentTag ct : contentTagsByContent) { if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(ct); @@ -285,6 +290,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } } + }); } @@ -311,36 +317,19 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie return tagNames.stream().anyMatch((tn) -> tn.getDisplayName().equals(followUpTagName)); } - protected void updateUI(final boolean isVideo, final boolean hasHashSetHits, final String text) { - if (isVideo) { - fileTypeImageView.setImage(videoIcon); - } else { - fileTypeImageView.setImage(null); - } - - if (hasHashSetHits) { - hashHitImageView.setImage(hashHitIcon); - } else { - hashHitImageView.setImage(null); - } - - nameLabel.setText(text); - nameLabel.setTooltip(new Tooltip(text)); - } - @Override - public Long getFileID() { + synchronized public Long getFileID() { return fileID; } @Override - public void handleTagsChanged(Collection ids) { + synchronized public void handleTagsChanged(Collection ids) { if (fileID != null && ids.contains(fileID)) { updateFollowUpIcon(); } } - protected void updateFollowUpIcon() { + synchronized protected void updateFollowUpIcon() { if (file != null) { try { boolean hasFollowUp = hasFollowUp(); @@ -349,63 +338,77 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie followUpToggle.setSelected(hasFollowUp); }); } catch (TskCoreException ex) { - Exceptions.printStackTrace(ex); + LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); } } } @Override - public void setFile(final Long fileID) { + synchronized public void setFile(final Long fileID) { if (Objects.equals(fileID, this.fileID) == false) { this.fileID = fileID; disposeContent(); if (this.fileID == null || Case.isCaseOpen() == false) { - ImageGalleryController.getDefault().getCategoryManager().unregisterListener(this); - TagUtils.unregisterListener(this); + if (registered == true) { + ImageGalleryController.getDefault().getCategoryManager().unregisterListener(this); + TagUtils.unregisterListener(this); + registered = false; + } file = null; Platform.runLater(() -> { clearContent(); }); } else { - ImageGalleryController.getDefault().getCategoryManager().registerListener(this); - TagUtils.registerListener(this); - + if (registered == false) { + ImageGalleryController.getDefault().getCategoryManager().registerListener(this); + TagUtils.registerListener(this); + registered = true; + } + file = null; getFile(); updateSelectionState(); updateCategoryBorder(); updateFollowUpIcon(); - final String text = getLabelText(); - final boolean isVideo = file.isVideo(); - final boolean hasHashSetHits = hasHashHit(); - Platform.runLater(() -> { - updateUI(isVideo, hasHashSetHits, text); - }); + updateUI(); Platform.runLater(getContentUpdateRunnable()); } } } + private void updateUI() { + final boolean isVideo = getFile().isVideo(); + final boolean hasHashSetHits = hasHashHit(); + final String text = getTextForLabel(); + + Platform.runLater(() -> { + fileTypeImageView.setImage(isVideo ? videoIcon : null); + hashHitImageView.setImage(hasHashSetHits ? hashHitIcon : null); + nameLabel.setText(text); + nameLabel.setTooltip(new Tooltip(text)); + }); + } + /** * update the visual representation of the selection state of this * DrawableView */ - protected void updateSelectionState() { - final boolean selected = globalSelectionModel.isSelected(fileID); + synchronized protected void updateSelectionState() { + final boolean selected = globalSelectionModel.isSelected(getFileID()); Platform.runLater(() -> { setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER); }); } @Override - public Region getBorderable() { + public Region getCategoryBorderRegion() { return imageBorder; } @Subscribe @Override - public void handleCategoryChanged(CategoryChangeEvent evt) { - if (evt.getIds().contains(fileID)) { + synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { + if (evt.getIds().contains(getFileID())) { updateCategoryBorder(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java index ddca55e4a6..5e7acd875a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java @@ -143,6 +143,8 @@ public class GroupPane extends BorderPane implements GroupView { ); private static final FileIDSelectionModel globalSelectionModel = FileIDSelectionModel.getInstance(); + private static final List categoryKeyCodes = Arrays.asList(KeyCode.NUMPAD0, KeyCode.NUMPAD1, KeyCode.NUMPAD2, KeyCode.NUMPAD3, KeyCode.NUMPAD4, KeyCode.NUMPAD5, + KeyCode.DIGIT0, KeyCode.DIGIT1, KeyCode.DIGIT2, KeyCode.DIGIT3, KeyCode.DIGIT4, KeyCode.DIGIT5); private final Back backAction; @@ -232,7 +234,8 @@ public class GroupPane extends BorderPane implements GroupView { FXMLConstructor.construct(this, "GroupPane.fxml"); } - public void activateSlideShowViewer(Long slideShowFileId) { + @ThreadConfined(type = ThreadType.JFX) + public void activateSlideShowViewer(Long slideShowFileID) { groupViewMode.set(GroupViewMode.SLIDE_SHOW); //make a new slideShowPane if necessary @@ -241,13 +244,14 @@ public class GroupPane extends BorderPane implements GroupView { } //assign last selected file or if none first file in group - if (slideShowFileId == null || grouping.get().fileIds().contains(slideShowFileId) == false) { - slideShowPane.setFile(grouping.get().fileIds().get(0)); + if (slideShowFileID == null || getGrouping().fileIds().contains(slideShowFileID) == false) { + slideShowPane.setFile(getGrouping().fileIds().get(0)); } else { - slideShowPane.setFile(slideShowFileId); + slideShowPane.setFile(slideShowFileID); } setCenter(slideShowPane); slideShowPane.requestFocus(); + } public void activateTileViewer() { @@ -258,6 +262,7 @@ public class GroupPane extends BorderPane implements GroupView { if (slideShowPane != null) { slideShowPane.disposeContent(); } + slideShowPane = null; this.scrollToFileID(globalSelectionModel.lastSelectedProperty().get()); } @@ -456,12 +461,14 @@ public class GroupPane extends BorderPane implements GroupView { if (t.getClickCount() == 1) { selectAllFiles(); } - if (contextMenu == null) { - contextMenu = buildContextMenu(); - } + if (globalSelectionModel.getSelected().isEmpty() == false) { + if (contextMenu == null) { + contextMenu = buildContextMenu(); + } - contextMenu.hide(); - contextMenu.show(GroupPane.this, t.getScreenX(), t.getScreenY()); + contextMenu.hide(); + contextMenu.show(GroupPane.this, t.getScreenX(), t.getScreenY()); + } t.consume(); break; } @@ -574,15 +581,15 @@ public class GroupPane extends BorderPane implements GroupView { if (isNull(viewState) || isNull(viewState.getGroup())) { this.grouping.set(null); - final List fileIds = Collections.emptyList(); - final String header = ""; + gridView.getItems().setAll(Collections.emptyList()); Platform.runLater(() -> { setCenter(null); - gridView.getItems().setAll(fileIds); - groupLabel.setText(header); + + groupLabel.setText(""); resetScrollBar(); if (false == Case.isCaseOpen()) { cellMap.values().stream().forEach(DrawableCell::resetItem); + cellMap.clear(); } }); @@ -593,9 +600,9 @@ public class GroupPane extends BorderPane implements GroupView { this.getGrouping().fileIds().addListener(filesSyncListener); final String header = getHeaderString(); - final ObservableList fileIds = getGrouping().fileIds(); + + gridView.getItems().setAll(getGrouping().fileIds()); Platform.runLater(() -> { - gridView.getItems().setAll(fileIds); groupLabel.setText(header); resetScrollBar(); if (viewState.getMode() == GroupViewMode.TILE) { @@ -615,6 +622,31 @@ public class GroupPane extends BorderPane implements GroupView { }); } + @ThreadConfined(type = ThreadType.JFX) + private Optional getScrollBar() { + if (gridView == null || gridView.getSkin() == null) { + return Optional.empty(); + } + return Optional.ofNullable((ScrollBar) gridView.getSkin().getNode().lookup(".scroll-bar")); + } + + void makeSelection(Boolean shiftDown, Long newFileID) { + + if (shiftDown) { + //TODO: do more hear to implement slicker multiselect + int endIndex = grouping.get().fileIds().indexOf(newFileID); + int startIndex = IntStream.of(grouping.get().fileIds().size(), selectionAnchorIndex, endIndex).min().getAsInt(); + endIndex = IntStream.of(0, selectionAnchorIndex, endIndex).max().getAsInt(); + List subList = grouping.get().fileIds().subList(Math.max(0, startIndex), Math.min(endIndex, grouping.get().fileIds().size()) + 1); + + globalSelectionModel.clearAndSelectAll(subList.toArray(new Long[subList.size()])); + globalSelectionModel.select(newFileID); + } else { + selectionAnchorIndex = null; + globalSelectionModel.clearAndSelect(newFileID); + } + } + private class DrawableCell extends GridCell { private final DrawableTile tile = new DrawableTile(GroupPane.this); @@ -648,14 +680,11 @@ public class GroupPane extends BorderPane implements GroupView { } void resetItem() { - updateItem(null, true); +// updateItem(null, true); tile.setFile(null); } } - private static final List categoryKeyCodes = Arrays.asList(KeyCode.NUMPAD0, KeyCode.NUMPAD1, KeyCode.NUMPAD2, KeyCode.NUMPAD3, KeyCode.NUMPAD4, KeyCode.NUMPAD5, - KeyCode.DIGIT0, KeyCode.DIGIT1, KeyCode.DIGIT2, KeyCode.DIGIT3, KeyCode.DIGIT4, KeyCode.DIGIT5); - /** * implements the key handler for tile navigation ( up, down , left, right * arrows) @@ -772,29 +801,4 @@ public class GroupPane extends BorderPane implements GroupView { } } - @ThreadConfined(type = ThreadType.JFX) - private Optional getScrollBar() { - if (gridView == null || gridView.getSkin() == null) { - return Optional.empty(); - } - return Optional.ofNullable((ScrollBar) gridView.getSkin().getNode().lookup(".scroll-bar")); - } - - void makeSelection(Boolean shiftDown, Long newFileID) { - - if (shiftDown) { - //TODO: do more hear to implement slicker multiselect - int endIndex = grouping.get().fileIds().indexOf(newFileID); - int startIndex = IntStream.of(grouping.get().fileIds().size(), selectionAnchorIndex, endIndex).min().getAsInt(); - endIndex = IntStream.of(0, selectionAnchorIndex, endIndex).max().getAsInt(); - List subList = grouping.get().fileIds().subList(Math.max(0, startIndex), Math.min(endIndex, grouping.get().fileIds().size()) + 1); - - globalSelectionModel.clearAndSelectAll(subList.toArray(new Long[subList.size()])); - globalSelectionModel.select(newFileID); - } else { - selectionAnchorIndex = null; - globalSelectionModel.clearAndSelect(newFileID); - } - } - } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index e5382173c4..b4319ac815 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -176,7 +176,7 @@ public class MetaDataPane extends AnchorPane implements TagUtils.TagListener, Dr Platform.runLater(() -> { imageView.setImage(null); tableView.getItems().clear(); - getBorderable().setBorder(null); + getCategoryBorderRegion().setBorder(null); }); } else { @@ -216,7 +216,7 @@ public class MetaDataPane extends AnchorPane implements TagUtils.TagListener, Dr } @Override - public Region getBorderable() { + public Region getCategoryBorderRegion() { return imageBorder; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index 56811ae7a6..88467e1973 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -56,6 +56,8 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.ImageFile; import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile; +import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.HASH_BORDER; +import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.getCategoryBorder; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -191,10 +193,10 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe syncButtonVisibility(); - groupPane.grouping().addListener((Observable observable) -> { + getGroupPane().grouping().addListener((Observable observable) -> { syncButtonVisibility(); - if (groupPane.getGrouping() != null) { - groupPane.getGrouping().fileIds().addListener((Observable observable1) -> { + if (getGroupPane().getGrouping() != null) { + getGroupPane().getGrouping().fileIds().addListener((Observable observable1) -> { syncButtonVisibility(); }); } @@ -204,7 +206,7 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe @ThreadConfined(type = ThreadType.ANY) private void syncButtonVisibility() { try { - final boolean hasMultipleFiles = groupPane.getGrouping().fileIds().size() > 1; + final boolean hasMultipleFiles = getGroupPane().getGrouping().fileIds().size() > 1; Platform.runLater(() -> { rightButton.setVisible(hasMultipleFiles); leftButton.setVisible(hasMultipleFiles); @@ -218,8 +220,7 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe } SlideShowView(GroupPane gp) { - super(); - groupPane = gp; + super(gp); FXMLConstructor.construct(this, "SlideShow.fxml"); } @@ -232,10 +233,10 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe } @Override - public void setFile(final Long fileID) { + synchronized public void setFile(final Long fileID) { super.setFile(fileID); - if (this.fileID != null) { - groupPane.makeSelection(false, this.fileID); + if (this.getFileID() != null) { + getGroupPane().makeSelection(false, this.getFileID()); } } @@ -253,12 +254,12 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe @Override protected Runnable getContentUpdateRunnable() { - if (file.isVideo()) { + if (getFile().isVideo()) { return () -> { - imageBorder.setCenter(MediaControl.create((VideoFile) file)); + imageBorder.setCenter(MediaControl.create((VideoFile) getFile())); }; } else { - ImageView imageView = new ImageView(((ImageFile) file).getFullSizeImage()); + ImageView imageView = new ImageView(((ImageFile) getFile()).getFullSizeImage()); imageView.setPreserveRatio(true); imageView.fitWidthProperty().bind(imageBorder.widthProperty().subtract(CAT_BORDER_WIDTH * 2)); imageView.fitHeightProperty().bind(this.heightProperty().subtract(CAT_BORDER_WIDTH * 4).subtract(footer.heightProperty()).subtract(toolBar.heightProperty())); @@ -269,23 +270,24 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe } @Override - protected String getLabelText() { - return file.getName() + " " + getSupplementalText(); + protected String getTextForLabel() { + return getFile().getName() + " " + getSupplementalText(); } + @ThreadConfined(type = ThreadType.JFX) private void cycleSlideShowImage(int d) { stopVideo(); - if (fileID != null) { - int index = groupPane.getGrouping().fileIds().indexOf(fileID); - final int size = groupPane.getGrouping().fileIds().size(); + if (getFileID() != null) { + int index = getGroupPane().getGrouping().fileIds().indexOf(getFileID()); + final int size = getGroupPane().getGrouping().fileIds().size(); index = (index + d) % size; if (index < 0) { index += size; } - setFile(groupPane.getGrouping().fileIds().get(index)); + setFile(getGroupPane().getGrouping().fileIds().get(index)); } else { - setFile(groupPane.getGrouping().fileIds().get(0)); + setFile(getGroupPane().getGrouping().fileIds().get(0)); } } @@ -294,23 +296,22 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe * of y" */ private String getSupplementalText() { - return " ( " + (groupPane.getGrouping().fileIds().indexOf(fileID) + 1) + " of " + groupPane.getGrouping().fileIds().size() + " in group )"; + return " ( " + (getGroupPane().getGrouping().fileIds().indexOf(getFileID()) + 1) + " of " + getGroupPane().getGrouping().fileIds().size() + " in group )"; } @Override @ThreadConfined(type = ThreadType.ANY) public Category updateCategoryBorder() { - final Category category = super.updateCategoryBorder(); + final Category category = getFile().getCategory(); + final Border border = hasHashHit() && (category == Category.ZERO) + ? HASH_BORDER + : getCategoryBorder(category); ToggleButton toggleForCategory = getToggleForCategory(category); - Runnable r = () -> { + Platform.runLater(() -> { + getCategoryBorderRegion().setBorder(border); toggleForCategory.setSelected(true); - }; - if (Platform.isFxApplicationThread()) { - r.run(); - } else { - Platform.runLater(r); - } + }); return category; } @@ -345,7 +346,7 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe @Override public void changed(ObservableValue ov, Boolean t, Boolean t1) { if (t1) { - FileIDSelectionModel.getInstance().clearAndSelect(fileID); + FileIDSelectionModel.getInstance().clearAndSelect(getFileID()); new CategorizeAction().addTag(cat.getTagName(), ""); } } From 1e6c97ce8462d022007034e45c4d2f0edf5283c8 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 13:27:48 -0400 Subject: [PATCH 015/198] remove references to obsolete .css file --- .../org/sleuthkit/autopsy/imagegallery/gui/SlideShow.fxml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShow.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShow.fxml index 83dcd77d4f..fb9e0aade4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShow.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShow.fxml @@ -7,7 +7,6 @@ - @@ -66,9 +65,7 @@ - - - + From 2ba6847c8072cfc76cec6e040ec3843715cb0a78 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 13:34:12 -0400 Subject: [PATCH 016/198] fix npe in GroupTreeCell --- .../autopsy/imagegallery/gui/navpanel/GroupTreeCell.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java index 44ccfb060d..5deaf88aa8 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java @@ -140,7 +140,9 @@ class GroupTreeCell extends TreeCell { } private String getGroupName() { - return StringUtils.defaultIfBlank(getItem().getPath(), DrawableGroup.getBlankGroupName()); + return Optional.ofNullable(getItem()) + .map((TreeNode t) -> StringUtils.defaultIfBlank(t.getPath(), DrawableGroup.getBlankGroupName())) + .orElse(""); } /** From 7b8b2431f30ecbf624dfa942f3a97eedbc56552b Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Thu, 11 Jun 2015 13:37:14 -0400 Subject: [PATCH 017/198] Old module name mapped with the new module name --- Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java index a0d0f35d67..0112d12bbb 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettings.java @@ -269,6 +269,9 @@ public class IngestJobSettings { case "E01 Verify": //NON-NLS moduleNames.add("E01 Verifier"); //NON-NLS break; + case "Archive Extractor": //NON-NLS + moduleNames.add("Embedded File Extractor"); + break; default: moduleNames.add(name); } From 26076037f12e90118058b5292a5c81d878d6e3b7 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 13:46:25 -0400 Subject: [PATCH 018/198] fix illegalstate exception from DrawableDB --- .../autopsy/imagegallery/datamodel/DrawableDB.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 4c2ce2c691..1cdaadf447 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -47,7 +47,6 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; -import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; @@ -1146,7 +1145,7 @@ public final class DrawableDB { Set getHashSetsForFile(long fileID) { try { Set hashNames = new HashSet<>(); - List arts = ImageGalleryController.getDefault().getSleuthKitCase().getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, fileID); + List arts = tskCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, fileID); for (BlackboardArtifact a : arts) { List attrs = a.getAttributes(); for (BlackboardAttribute attr : attrs) { @@ -1156,8 +1155,8 @@ public final class DrawableDB { } return hashNames; } - } catch (TskCoreException tskCoreException) { - throw new IllegalStateException(tskCoreException); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "failed to get hash sets for file", ex); } return Collections.emptySet(); } From 048c44cde2f82634e492d1b07c4662da82b77d64 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 14:09:05 -0400 Subject: [PATCH 019/198] rebuild the list of tagnames each time the list is shown --- .../autopsy/imagegallery/gui/GroupPane.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java index 5e7acd875a..c9220b174f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java @@ -347,11 +347,7 @@ public class GroupPane extends BorderPane implements GroupView { HBox.setHgrow(spacer, Priority.ALWAYS); spacer.setMinWidth(Region.USE_PREF_SIZE); - ArrayList grpTagMenues = new ArrayList<>(); - for (final TagName tn : TagUtils.getNonCategoryTagNames()) { - MenuItem menuItem = createGrpTagMenuItem(tn); - grpTagMenues.add(menuItem); - } + try { grpTagSplitMenu.setText(TagUtils.getFollowUpTagName().getDisplayName()); grpTagSplitMenu.setOnAction(createGrpTagMenuItem(TagUtils.getFollowUpTagName()).getOnAction()); @@ -359,7 +355,16 @@ public class GroupPane extends BorderPane implements GroupView { LOGGER.log(Level.WARNING, "failed to load FollowUpTagName", tskCoreException); } grpTagSplitMenu.setGraphic(new ImageView(DrawableAttribute.TAGS.getIcon())); - grpTagSplitMenu.getItems().setAll(grpTagMenues); + grpTagSplitMenu.showingProperty().addListener((ObservableValue ov, Boolean t, Boolean t1) -> { + if (t1) { + ArrayList selTagMenues = new ArrayList<>(); + for (final TagName tn : TagUtils.getNonCategoryTagNames()) { + MenuItem menuItem = TagUtils.createSelTagMenuItem(tn, grpTagSplitMenu); + selTagMenues.add(menuItem); + } + grpTagSplitMenu.getItems().setAll(selTagMenues); + } + }); ArrayList grpCategoryMenues = new ArrayList<>(); for (final Category cat : Category.values()) { From ccf2af40ca43216281c46b8a7172070ccedd2e84 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 14:29:07 -0400 Subject: [PATCH 020/198] remove duplicate Category value form values list --- .../datamodel/DrawableAttribute.java | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java index 70667a7f83..495aabf70f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java @@ -40,10 +40,10 @@ import org.sleuthkit.datamodel.TagName; public class DrawableAttribute> { public final static DrawableAttribute NAME - = new DrawableAttribute<>( AttributeName.NAME, "Name", true, "folder-rename.png", f -> Collections.singleton(f.getName())); + = new DrawableAttribute<>(AttributeName.NAME, "Name", true, "folder-rename.png", f -> Collections.singleton(f.getName())); public final static DrawableAttribute ANALYZED - = new DrawableAttribute<>( AttributeName.ANALYZED, "Analyzed", true, "", f -> Collections.singleton(f.isAnalyzed())); + = new DrawableAttribute<>(AttributeName.ANALYZED, "Analyzed", true, "", f -> Collections.singleton(f.isAnalyzed())); /** * since categories are really just tags in autopsy, they are not dealt with @@ -54,50 +54,48 @@ public class DrawableAttribute> { * advantage. move categories into DrawableDB */ public final static DrawableAttribute CATEGORY - = new DrawableAttribute<>( AttributeName.CATEGORY, "Category", false, "category-icon.png", f -> Collections.singleton(f.getCategory())); + = new DrawableAttribute<>(AttributeName.CATEGORY, "Category", false, "category-icon.png", f -> Collections.singleton(f.getCategory())); public final static DrawableAttribute TAGS - = new DrawableAttribute<>( AttributeName.TAGS, "Tags", false, "tag_red.png", DrawableFile::getTagNames); + = new DrawableAttribute<>(AttributeName.TAGS, "Tags", false, "tag_red.png", DrawableFile::getTagNames); public final static DrawableAttribute PATH = new DrawableAttribute<>(AttributeName.PATH, "Path", true, "folder_picture.png", f -> Collections.singleton(f.getDrawablePath())); public final static DrawableAttribute CREATED_TIME - = new DrawableAttribute<>( AttributeName.CREATED_TIME, "Created Time", true, "clock--plus.png", f -> Collections.singleton(ContentUtils.getStringTime(f.getCrtime(), f))); + = new DrawableAttribute<>(AttributeName.CREATED_TIME, "Created Time", true, "clock--plus.png", f -> Collections.singleton(ContentUtils.getStringTime(f.getCrtime(), f))); public final static DrawableAttribute MODIFIED_TIME - = new DrawableAttribute<>( AttributeName.MODIFIED_TIME, "Modified Time", true, "clock--pencil.png", f -> Collections.singleton(ContentUtils.getStringTime(f.getMtime(), f))); + = new DrawableAttribute<>(AttributeName.MODIFIED_TIME, "Modified Time", true, "clock--pencil.png", f -> Collections.singleton(ContentUtils.getStringTime(f.getMtime(), f))); public final static DrawableAttribute MAKE - = new DrawableAttribute<>( AttributeName.MAKE, "Camera Make", true, "camera.png", f -> Collections.singleton(f.getMake())); + = new DrawableAttribute<>(AttributeName.MAKE, "Camera Make", true, "camera.png", f -> Collections.singleton(f.getMake())); public final static DrawableAttribute MODEL - = new DrawableAttribute<>( AttributeName.MODEL, "Camera Model", true, "camera.png", f -> Collections.singleton(f.getModel())); + = new DrawableAttribute<>(AttributeName.MODEL, "Camera Model", true, "camera.png", f -> Collections.singleton(f.getModel())); public final static DrawableAttribute HASHSET = new DrawableAttribute<>(AttributeName.HASHSET, "Hashset", true, "hashset_hits.png", DrawableFile::getHashHitSetNames); public final static DrawableAttribute OBJ_ID - = new DrawableAttribute<>( AttributeName.OBJ_ID, "Internal Object ID", true, "", f -> Collections.singleton(f.getId())); + = new DrawableAttribute<>(AttributeName.OBJ_ID, "Internal Object ID", true, "", f -> Collections.singleton(f.getId())); public final static DrawableAttribute WIDTH = new DrawableAttribute<>(AttributeName.WIDTH, "Width", true, "arrow-resize.png", f -> Collections.singleton(f.getWidth())); public final static DrawableAttribute HEIGHT - = new DrawableAttribute<>( AttributeName.HEIGHT, "Height", true, "arrow-resize-090.png", f -> Collections.singleton(f.getHeight())); + = new DrawableAttribute<>(AttributeName.HEIGHT, "Height", true, "arrow-resize-090.png", f -> Collections.singleton(f.getHeight())); final private static List< DrawableAttribute> groupables = Arrays.asList(PATH, HASHSET, CATEGORY, TAGS, MAKE, MODEL); final private static List> values = Arrays.asList(NAME, ANALYZED, CATEGORY, TAGS, PATH, CREATED_TIME, - MODIFIED_TIME, HASHSET, CATEGORY, MAKE, MODEL, OBJ_ID, - WIDTH, HEIGHT); + MODIFIED_TIME, HASHSET, MAKE, MODEL, OBJ_ID, WIDTH, HEIGHT); private final Function, Collection> extractor; - - private DrawableAttribute( AttributeName name, String displayName, Boolean isDBColumn, String imageName, Function, Collection> extractor) { + private DrawableAttribute(AttributeName name, String displayName, Boolean isDBColumn, String imageName, Function, Collection> extractor) { this.attrName = name; this.displayName = new ReadOnlyStringWrapper(displayName); this.isDBColumn = isDBColumn; @@ -142,8 +140,19 @@ public class DrawableAttribute> { public static enum AttributeName { - NAME, ANALYZED, CATEGORY, TAGS, PATH, CREATED_TIME, MODIFIED_TIME, MAKE, - MODEL, HASHSET, OBJ_ID, WIDTH, HEIGHT; + NAME, + ANALYZED, + CATEGORY, + TAGS, + PATH, + CREATED_TIME, + MODIFIED_TIME, + MAKE, + MODEL, + HASHSET, + OBJ_ID, + WIDTH, + HEIGHT; } public Collection getValue(DrawableFile f) { From a87a665993df83c3aeb6ad079ed01d24affc23c9 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 14:30:35 -0400 Subject: [PATCH 021/198] don't mark groups as unseen unless a file was actually added or removed --- .../autopsy/imagegallery/grouping/DrawableGroup.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index 445b336ba9..59437df5be 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -133,16 +133,18 @@ public class DrawableGroup implements Comparable { synchronized public void addFile(Long f) { invalidateHashSetHitsCount(); - seen.set(false); if (fileIDs.contains(f) == false) { fileIDs.add(f); + seen.set(false); + } } synchronized public void removeFile(Long f) { invalidateHashSetHitsCount(); - seen.set(false); - fileIDs.removeAll(f); + if (fileIDs.removeAll(f)) { + seen.set(false); + } } // By default, sort by group key name From 13fefb1c178fa65d704d0dc79771b9b6ba68c943 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 14:48:50 -0400 Subject: [PATCH 022/198] keep a reference to public unmodifiable view of fileids so that listeners are not immediately garbage colelcted --- .../autopsy/imagegallery/grouping/DrawableGroup.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index 445b336ba9..779e13a815 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -41,13 +41,15 @@ public class DrawableGroup implements Comparable { } private final ObservableList fileIDs = FXCollections.observableArrayList(); + private final ObservableList unmodifiableFileIDS = FXCollections.unmodifiableObservableList(fileIDs); //cache the number of files in this groups with hashset hits private long hashSetHitsCount = -1; private final ReadOnlyBooleanWrapper seen = new ReadOnlyBooleanWrapper(false); + @SuppressWarnings("ReturnOfCollectionOrArrayField") synchronized public ObservableList fileIds() { - return FXCollections.unmodifiableObservableList(fileIDs); + return unmodifiableFileIDS; } final public GroupKey groupKey; From 291ff560a22c8ed35779aee9314dce299a4c52b0 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 14:57:37 -0400 Subject: [PATCH 023/198] update to openjfx-dialogs 1.0.3 note that this is necessary as long as we are still on the 8.20.x line of ControlsFX if we move to 8.40.x this extra jar is unneccesary, but we will have to baseline on java 8u40 --- CoreLibs/ivy.xml | 2 +- CoreLibs/nbproject/project.properties | 2 +- CoreLibs/nbproject/project.xml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CoreLibs/ivy.xml b/CoreLibs/ivy.xml index e45de956c4..99c18a955b 100644 --- a/CoreLibs/ivy.xml +++ b/CoreLibs/ivy.xml @@ -37,7 +37,7 @@ - + diff --git a/CoreLibs/nbproject/project.properties b/CoreLibs/nbproject/project.properties index 1bfc0f7c81..e1ebd74bb7 100644 --- a/CoreLibs/nbproject/project.properties +++ b/CoreLibs/nbproject/project.properties @@ -41,7 +41,7 @@ file.reference.jsr305-1.3.9.jar=release/modules/ext/jsr305-1.3.9.jar file.reference.log4j-1.2.17.jar=release/modules/ext/log4j-1.2.17.jar file.reference.logkit-1.0.1.jar=release/modules/ext/logkit-1.0.1.jar file.reference.mail-1.4.3.jar=release/modules/ext/mail-1.4.3.jar -file.reference.openjfx-dialogs-1.0.2.jar=release/modules/ext/openjfx-dialogs-1.0.2.jar +file.reference.openjfx-dialogs-1.0.2.jar=release/modules/ext/openjfx-dialogs-1.0.3.jar file.reference.platform-3.4.0.jar=release/modules/ext/platform-3.4.0.jar file.reference.poi-3.8.jar=release/modules/ext/poi-3.8.jar file.reference.poi-excelant-3.8.jar=release/modules/ext/poi-excelant-3.8.jar diff --git a/CoreLibs/nbproject/project.xml b/CoreLibs/nbproject/project.xml index d5e9d24b5f..ea65c1e7f9 100644 --- a/CoreLibs/nbproject/project.xml +++ b/CoreLibs/nbproject/project.xml @@ -617,8 +617,8 @@ release/modules/ext/logkit-1.0.1.jar
- ext/openjfx-dialogs-1.0.2.jar - release/modules/ext/openjfx-dialogs-1.0.2.jar + ext/openjfx-dialogs-1.0.3.jar + release/modules/ext/openjfx-dialogs-1.0.3.jar ext/imgscalr-lib-4.2-javadoc.jar From efd19fc56f0819e2c47a04498592471b1e075079 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 15:52:15 -0400 Subject: [PATCH 024/198] allow marking grouos as seen or unseen, update next unseen appropriatly --- .../imagegallery/actions/NextUnseenGroup.java | 5 +- .../imagegallery/datamodel/DrawableDB.java | 263 +++++++++--------- .../imagegallery/grouping/DrawableGroup.java | 5 +- .../imagegallery/grouping/GroupManager.java | 29 +- 4 files changed, 152 insertions(+), 150 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java index 5f8b13104b..ab8ef06401 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java @@ -56,14 +56,15 @@ public class NextUnseenGroup extends Action { }); controller.getGroupManager().getUnSeenGroups().addListener((Observable observable) -> { - updateButton(); + Platform.runLater(this::updateButton); + }); setEventHandler((ActionEvent t) -> { Optional.ofNullable(controller.viewState()) .map(ObjectExpression::getValue) .map(GroupViewState::getGroup) - .ifPresent(controller.getGroupManager()::markGroupSeen); + .ifPresent(group -> controller.getGroupManager().markGroupSeen(group, true)); if (false == controller.getGroupManager().getUnSeenGroups().isEmpty()) { controller.advance(GroupViewState.tile(controller.getGroupManager().getUnSeenGroups().get(0))); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 1cdaadf447..422ff028a9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -71,51 +71,51 @@ import org.sqlite.SQLiteJDBCLoader; * the future. see also {@link EventsDB} in the timeline viewer. */ public final class DrawableDB { - + private static final java.util.logging.Logger LOGGER = Logger.getLogger(DrawableDB.class.getName()); //column name constants////////////////////// private static final String ANALYZED = "analyzed"; - + private static final String OBJ_ID = "obj_id"; - + private static final String HASH_SET_NAME = "hash_set_name"; - + private final PreparedStatement insertHashSetStmt; - + private final PreparedStatement groupSeenQueryStmt; - + private final PreparedStatement insertGroupStmt; - + private final List preparedStatements = new ArrayList<>(); - + private final PreparedStatement removeFileStmt; - + private final PreparedStatement updateGroupStmt; - + private final PreparedStatement selectHashSetStmt; - + private final PreparedStatement selectHashSetNamesStmt; - + private final PreparedStatement insertHashHitStmt; - + private final PreparedStatement updateFileStmt; private PreparedStatement insertFileStmt; - + private final PreparedStatement pathGroupStmt; - + private final PreparedStatement nameGroupStmt; - + private final PreparedStatement created_timeGroupStmt; - + private final PreparedStatement modified_timeGroupStmt; - + private final PreparedStatement makeGroupStmt; - + private final PreparedStatement modelGroupStmt; - + private final PreparedStatement analyzedGroupStmt; - + private final PreparedStatement hashSetGroupStmt; /** @@ -128,13 +128,13 @@ public final class DrawableDB { * list of observers to be notified if the database changes */ private final HashSet updateListeners = new HashSet<>(); - + private GroupManager groupManager; - + private final Path dbPath; - + volatile private Connection con; - + private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true); //use fairness policy private final Lock DBLock = rwLock.writeLock(); //using exclusing lock for all db ops for now @@ -206,9 +206,9 @@ public final class DrawableDB { insertFileStmt = prepareStatement( "INSERT OR IGNORE INTO drawable_files (obj_id , path, name, created_time, modified_time, make, model, analyzed) " + "VALUES (?,?,?,?,?,?,?,?)"); - + removeFileStmt = prepareStatement("delete from drawable_files where obj_id = ?"); - + pathGroupStmt = prepareStatement("select obj_id , analyzed from drawable_files where path = ? ", DrawableAttribute.PATH); nameGroupStmt = prepareStatement("select obj_id , analyzed from drawable_files where name = ? ", DrawableAttribute.NAME); created_timeGroupStmt = prepareStatement("select obj_id , analyzed from drawable_files where created_time = ? ", DrawableAttribute.CREATED_TIME); @@ -217,23 +217,23 @@ public final class DrawableDB { modelGroupStmt = prepareStatement("select obj_id , analyzed from drawable_files where model = ? ", DrawableAttribute.MODEL); analyzedGroupStmt = prepareStatement("Select obj_id , analyzed from drawable_files where analyzed = ?", DrawableAttribute.ANALYZED); hashSetGroupStmt = prepareStatement("select drawable_files.obj_id as obj_id, analyzed from drawable_files , hash_sets , hash_set_hits where drawable_files.obj_id = hash_set_hits.obj_id and hash_sets.hash_set_id = hash_set_hits.hash_set_id and hash_sets.hash_set_name = ?", DrawableAttribute.HASHSET); - - updateGroupStmt = prepareStatement("update groups set seen = 1 where value = ? and attribute = ?"); + + updateGroupStmt = prepareStatement("update groups set seen = ? where value = ? and attribute = ?"); insertGroupStmt = prepareStatement("insert or replace into groups (value, attribute) values (?,?)"); - + groupSeenQueryStmt = prepareStatement("select seen from groups where value = ? and attribute = ?"); - + selectHashSetNamesStmt = prepareStatement("SELECT DISTINCT hash_set_name FROM hash_sets"); insertHashSetStmt = prepareStatement("insert or ignore into hash_sets (hash_set_name) values (?)"); selectHashSetStmt = prepareStatement("select hash_set_id from hash_sets where hash_set_name = ?"); - + insertHashHitStmt = prepareStatement("insert or ignore into hash_set_hits (hash_set_id, obj_id) values (?,?)"); - + initializeImageList(); } else { throw new ExceptionInInitializerError(); } - + } /** @@ -271,7 +271,7 @@ public final class DrawableDB { if (attr != null) { groupStatementMap.put(attr, prepareStatement); } - + return prepareStatement; } @@ -284,7 +284,7 @@ public final class DrawableDB { * @return */ public static DrawableDB getDrawableDB(Path dbPath, SleuthkitCase tskCase) { - + try { return new DrawableDB(dbPath.resolve("drawable.db"), tskCase); } catch (SQLException ex) { @@ -295,7 +295,7 @@ public final class DrawableDB { return null; } } - + private void setPragmas() throws SQLException { //this should match Sleuthkit db setupt @@ -321,7 +321,7 @@ public final class DrawableDB { //we never delete anything so... statement.execute("PRAGMA auto_vacuum = 0"); } - + try { LOGGER.log(Level.INFO, String.format("sqlite-jdbc version %s loaded in %s mode", SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode() @@ -329,7 +329,7 @@ public final class DrawableDB { } catch (Exception exception) { LOGGER.log(Level.WARNING, "exception while checking sqlite-jdbc version and mode", exception); } - + } /** @@ -344,7 +344,7 @@ public final class DrawableDB { openDBCon(); } setPragmas(); - + } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "problem accessing database", ex); return false; @@ -364,7 +364,7 @@ public final class DrawableDB { LOGGER.log(Level.SEVERE, "problem creating drawable_files table", ex); return false; } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE TABLE if not exists groups " + "(group_id INTEGER PRIMARY KEY, " @@ -377,7 +377,7 @@ public final class DrawableDB { LOGGER.log(Level.SEVERE, "problem creating groups table", ex); return false; } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE TABLE if not exists hash_sets " + "( hash_set_id INTEGER primary key," @@ -387,7 +387,7 @@ public final class DrawableDB { LOGGER.log(Level.SEVERE, "problem creating hash_sets table", ex); return false; } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE TABLE if not exists hash_set_hits " + "(hash_set_id INTEGER REFERENCES hash_sets(hash_set_id) not null, " @@ -398,45 +398,45 @@ public final class DrawableDB { LOGGER.log(Level.SEVERE, "problem creating hash_set_hits table", ex); return false; } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE INDEX if not exists path_idx ON drawable_files(path)"; stmt.execute(sql); } catch (SQLException ex) { LOGGER.log(Level.WARNING, "problem creating path_idx", ex); } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE INDEX if not exists name_idx ON drawable_files(name)"; stmt.execute(sql); } catch (SQLException ex) { LOGGER.log(Level.WARNING, "problem creating name_idx", ex); } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE INDEX if not exists make_idx ON drawable_files(make)"; stmt.execute(sql); } catch (SQLException ex) { LOGGER.log(Level.WARNING, "problem creating make_idx", ex); } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE INDEX if not exists model_idx ON drawable_files(model)"; stmt.execute(sql); } catch (SQLException ex) { LOGGER.log(Level.WARNING, "problem creating model_idx", ex); } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE INDEX if not exists analyzed_idx ON drawable_files(analyzed)"; stmt.execute(sql); } catch (SQLException ex) { LOGGER.log(Level.WARNING, "problem creating analyzed_idx", ex); } - + return true; } - + @Override public void finalize() throws Throwable { try { @@ -445,7 +445,7 @@ public final class DrawableDB { super.finalize(); } } - + public void closeDBCon() { if (con != null) { try { @@ -457,7 +457,7 @@ public final class DrawableDB { } con = null; } - + public void openDBCon() { try { if (con == null || con.isClosed()) { @@ -467,7 +467,7 @@ public final class DrawableDB { LOGGER.log(Level.WARNING, "Failed to open connection to drawable.db", ex); } } - + public boolean isClosed() throws SQLException { if (con == null) { return true; @@ -495,7 +495,7 @@ public final class DrawableDB { } return names; } - + public boolean isGroupSeen(GroupKey groupKey) { dbReadLock(); try { @@ -514,14 +514,15 @@ public final class DrawableDB { } return false; } - - public void markGroupSeen(GroupKey gk) { + + public void markGroupSeen(GroupKey gk, boolean seen) { dbWriteLock(); try { - //PreparedStatement updateGroup = con.prepareStatement("update groups set seen = 1 where value = ? and attribute = ?"); + //PreparedStatement updateGroup = con.prepareStatement("update groups set seen = ? where value = ? and attribute = ?"); updateGroupStmt.clearParameters(); - updateGroupStmt.setString(1, gk.getValueDisplayName()); - updateGroupStmt.setString(2, gk.getAttribute().attrName.toString()); + updateGroupStmt.setBoolean(1, seen); + updateGroupStmt.setString(2, gk.getValueDisplayName()); + updateGroupStmt.setString(3, gk.getAttribute().attrName.toString()); updateGroupStmt.execute(); } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "Error marking group as seen", ex); @@ -529,41 +530,41 @@ public final class DrawableDB { dbWriteUnlock(); } } - + public boolean removeFile(long id) { DrawableTransaction trans = beginTransaction(); boolean removeFile = removeFile(id, trans); commitTransaction(trans, true); return removeFile; } - + public void updateFile(DrawableFile f) { DrawableTransaction trans = beginTransaction(); updateFile(f, trans); commitTransaction(trans, true); } - + public void insertFile(DrawableFile f) { DrawableTransaction trans = beginTransaction(); insertFile(f, trans); commitTransaction(trans, true); } - + public void insertFile(DrawableFile f, DrawableTransaction tr) { insertOrUpdateFile(f, tr, insertFileStmt); } - + public void updateFile(DrawableFile f, DrawableTransaction tr) { insertOrUpdateFile(f, tr, updateFileStmt); } - + private void insertOrUpdateFile(DrawableFile f, DrawableTransaction tr, PreparedStatement stmt) { //TODO: implement batch version -jm if (tr.isClosed()) { throw new IllegalArgumentException("can't update database with closed transaction"); } - + dbWriteLock(); try { // Update the list of file IDs in memory @@ -579,9 +580,9 @@ public final class DrawableDB { stmt.setString(7, f.getModel()); stmt.setBoolean(8, f.isAnalyzed()); stmt.executeUpdate(); - + final Collection hashSetNames = DrawableAttribute.HASHSET.getValue(f); - + if (hashSetNames.isEmpty() == false) { for (String name : hashSetNames) { @@ -612,9 +613,9 @@ public final class DrawableDB { insertGroup(val.toString(), attr); } } - + tr.addUpdatedFile(f.getId()); - + } catch (SQLException | NullPointerException ex) { // This is one of the places where we get an error if the case is closed during processing, // which doesn't need to be reported here. @@ -625,38 +626,38 @@ public final class DrawableDB { dbWriteUnlock(); } } - + public DrawableTransaction beginTransaction() { return new DrawableTransaction(); } - + public void commitTransaction(DrawableTransaction tr, Boolean notify) { if (tr.isClosed()) { throw new IllegalArgumentException("can't close already closed transaction"); } tr.commit(notify); } - + public void addUpdatedFileListener(FileUpdateEvent.FileUpdateListener l) { updateListeners.add(l); } - + private void fireUpdatedFiles(Collection fileIDs) { for (FileUpdateEvent.FileUpdateListener listener : updateListeners) { listener.handleFileUpdate(FileUpdateEvent.newUpdateEvent(fileIDs, null)); } } - + private void fireRemovedFiles(Collection fileIDs) { for (FileUpdateEvent.FileUpdateListener listener : updateListeners) { listener.handleFileUpdate(FileUpdateEvent.newRemovedEvent(fileIDs)); } } - + public Boolean isFileAnalyzed(DrawableFile f) { return isFileAnalyzed(f.getId()); } - + public Boolean isFileAnalyzed(long fileId) { dbReadLock(); try (Statement stmt = con.createStatement(); @@ -669,12 +670,12 @@ public final class DrawableDB { } finally { dbReadUnlock(); } - + return false; } - + public Boolean areFilesAnalyzed(Collection fileIds) { - + dbReadLock(); try (Statement stmt = con.createStatement(); //Can't make this a preprared statement because of the IN ( ... ) @@ -687,15 +688,15 @@ public final class DrawableDB { } finally { dbReadUnlock(); } - + return false; } - + public Boolean isGroupAnalyzed(GroupKey gk) { dbReadLock(); try { List fileIDsInGroup = getFileIDsInGroup(gk); - + try { // In testing, this method appears to be a lot faster than doing one large select statement for (Long fileID : fileIDsInGroup) { @@ -708,7 +709,7 @@ public final class DrawableDB { } return true; } - + } catch (SQLException ex) { LOGGER.log(Level.WARNING, "problem counting analyzed files: ", ex); } @@ -862,9 +863,9 @@ public final class DrawableDB { * @return */ public > List findValuesForAttribute(DrawableAttribute groupBy, GroupSortBy sortBy, SortOrder sortOrder) { - + List vals = new ArrayList<>(); - + switch (groupBy.attrName) { case ANALYZED: case CATEGORY: @@ -876,7 +877,7 @@ public final class DrawableDB { dbReadLock(); //TODO: convert this to prepared statement StringBuilder query = new StringBuilder("select " + groupBy.attrName.toString() + ", count(*) from drawable_files group by " + groupBy.attrName.toString()); - + String orderByClause = ""; switch (sortBy) { case GROUP_BY_VALUE: @@ -889,12 +890,12 @@ public final class DrawableDB { // case PRIORITY: break; } - + query.append(orderByClause); - + if (orderByClause.equals("") == false) { String sortOrderClause = ""; - + switch (sortOrder) { case DESCENDING: sortOrderClause = " DESC"; @@ -907,7 +908,7 @@ public final class DrawableDB { } query.append(sortOrderClause); } - + try (Statement stmt = con.createStatement(); ResultSet valsResults = stmt.executeQuery(query.toString())) { while (valsResults.next()) { @@ -919,13 +920,13 @@ public final class DrawableDB { dbReadUnlock(); } } - + return vals; } - + public void insertGroup(final String value, DrawableAttribute groupBy) { dbWriteLock(); - + try { //PreparedStatement insertGroup = con.prepareStatement("insert or replace into groups (value, attribute, seen) values (?,?,0)"); insertGroupStmt.clearParameters(); @@ -979,9 +980,9 @@ public final class DrawableDB { return null; } } - + public List getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { - + if (groupKey.getAttribute().isDBColumn) { switch (groupKey.getAttribute().attrName) { case CATEGORY: @@ -995,7 +996,7 @@ public final class DrawableDB { try { PreparedStatement statement = getGroupStatment(groupKey.getAttribute()); statement.setObject(1, groupKey.getValue()); - + try (ResultSet valsResults = statement.executeQuery()) { while (valsResults.next()) { files.add(valsResults.getLong(OBJ_ID)); @@ -1006,10 +1007,10 @@ public final class DrawableDB { } finally { dbReadUnlock(); } - + return files; } - + public List> getFilesInGroup(GroupKey key) throws TskCoreException { List> files = new ArrayList<>(); dbReadLock(); @@ -1025,9 +1026,9 @@ public final class DrawableDB { default: statement = getGroupStatment(key.getAttribute()); } - + statement.setObject(1, key.getValue()); - + try (ResultSet valsResults = statement.executeQuery()) { while (valsResults.next()) { files.add(getFileFromID(valsResults.getLong(OBJ_ID), valsResults.getBoolean(ANALYZED))); @@ -1038,16 +1039,16 @@ public final class DrawableDB { } finally { dbReadUnlock(); } - + return files; } - + private void closeStatements() throws SQLException { for (PreparedStatement pStmt : preparedStatements) { pStmt.close(); } } - + public List> getFilesWithCategory(Category cat) throws TskCoreException, IllegalArgumentException { try { List> files = new ArrayList<>(); @@ -1064,18 +1065,18 @@ public final class DrawableDB { throw ex; } } - + private PreparedStatement getGroupStatment(DrawableAttribute groupBy) { return groupStatementMap.get(groupBy); - + } - + public int countAllFiles() { int result = -1; dbReadLock(); try (ResultSet rs = con.createStatement().executeQuery("select count(*) as COUNT from drawable_files")) { while (rs.next()) { - + result = rs.getInt("COUNT"); break; } @@ -1100,7 +1101,7 @@ public final class DrawableDB { } int valsResults = 0; dbWriteLock(); - + try { // Update the list of file IDs in memory removeImageFileFromList(id); @@ -1118,11 +1119,11 @@ public final class DrawableDB { //indicates succesfull removal of 1 file return valsResults == 1; } - + public class MultipleTransactionException extends IllegalStateException { - + private static final String CANNOT_HAVE_MORE_THAN_ONE_OPEN_TRANSACTIO = "cannot have more than one open transaction"; - + public MultipleTransactionException() { super(CANNOT_HAVE_MORE_THAN_ONE_OPEN_TRANSACTIO); } @@ -1168,31 +1169,31 @@ public final class DrawableDB { */ @GuardedBy("fileIDlist") private final Set fileIDsInDB = new HashSet<>(); - + public boolean isInDB(Long id) { synchronized (fileIDsInDB) { return fileIDsInDB.contains(id); } } - + private void addImageFileToList(Long id) { synchronized (fileIDsInDB) { fileIDsInDB.add(id); } } - + private void removeImageFileFromList(Long id) { synchronized (fileIDsInDB) { fileIDsInDB.remove(id); } } - + public int getNumberOfImageFilesInList() { synchronized (fileIDsInDB) { return fileIDsInDB.size(); } } - + private void initializeImageList() { synchronized (fileIDsInDB) { dbReadLock(); @@ -1214,7 +1215,7 @@ public final class DrawableDB { * For performance reasons, keep the file type in memory */ private final Map videoFileMap = new ConcurrentHashMap<>(); - + public boolean isVideoFile(AbstractFile f) { return videoFileMap.computeIfAbsent(f, ImageGalleryModule::isVideoFile); } @@ -1241,7 +1242,7 @@ public final class DrawableDB { .map(Content::getId) .filter(this::isInDB) .count(); - + } catch (IllegalStateException ex) { LOGGER.log(Level.WARNING, "Case closed while getting files"); } catch (TskCoreException ex1) { @@ -1254,11 +1255,11 @@ public final class DrawableDB { * inner class that can reference access database connection */ public class DrawableTransaction { - + private final Set updatedFiles; - + private final Set removedFiles; - + private boolean closed = false; /** @@ -1277,13 +1278,13 @@ public final class DrawableDB { dbWriteLock(); try { con.setAutoCommit(false); - + } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "failed to set auto-commit to to false", ex); } - + } - + synchronized public void rollback() { if (!closed) { try { @@ -1296,14 +1297,14 @@ public final class DrawableDB { } } } - + synchronized private void commit(Boolean notify) { if (!closed) { try { con.commit(); // make sure we close before we update, bc they'll need locks close(); - + if (notify) { fireUpdatedFiles(updatedFiles); fireRemovedFiles(removedFiles); @@ -1318,7 +1319,7 @@ public final class DrawableDB { } } } - + synchronized private void close() { if (!closed) { try { @@ -1335,15 +1336,15 @@ public final class DrawableDB { } } } - + synchronized public Boolean isClosed() { return closed; } - + synchronized private void addUpdatedFile(Long f) { updatedFiles.add(f); } - + synchronized private void addRemovedFile(long id) { removedFiles.add(id); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index 7a44d395e9..88aa65cb09 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -138,7 +138,6 @@ public class DrawableGroup implements Comparable { if (fileIDs.contains(f) == false) { fileIDs.add(f); seen.set(false); - } } @@ -155,8 +154,8 @@ public class DrawableGroup implements Comparable { return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName()); } - void setSeen() { - this.seen.set(true); + void setSeen(boolean isSeen) { + this.seen.set(isSeen); } public ReadOnlyBooleanWrapper seenProperty() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 1af4c4ea71..9f90ab6fca 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -245,6 +245,9 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { List newFiles = files == null ? new ArrayList<>() : files; DrawableGroup g = new DrawableGroup(groupKey, newFiles); + g.seenProperty().addListener((observable, oldSeen, newSeen) -> { + markGroupSeen(g, newSeen); + }); synchronized (groupMap) { groupMap.put(groupKey, g); } @@ -258,11 +261,15 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @param group the {@link DrawableGroup} to mark as seen */ @ThreadConfined(type = ThreadType.JFX) - public void markGroupSeen(DrawableGroup group) { - db.markGroupSeen(group.getGroupKey()); - group.setSeen(); - unSeenGroups.removeAll(group); - + public void markGroupSeen(DrawableGroup group, boolean seen) { + db.markGroupSeen(group.getGroupKey(), seen); + group.setSeen(seen); + if (seen) { + unSeenGroups.removeAll(group); + } else if (unSeenGroups.contains(group) == false) { + unSeenGroups.add(group); + FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); + } } /** @@ -324,19 +331,13 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { if (task == null || (task.isCancelled() == false)) { final boolean groupSeen = db.isGroupSeen(g.getGroupKey()); - if (groupSeen) { - g.setSeen(); - } + Platform.runLater(() -> { if (analyzedGroups.contains(g) == false) { analyzedGroups.add(g); } - if (groupSeen) { - unSeenGroups.removeAll(g); - } else if (unSeenGroups.contains(g) == false) { - unSeenGroups.add(g); - FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); - } + markGroupSeen(g, groupSeen); + }); } } From ce4ff627fb80f72e8e260ce8cf71d1febf2c7bc8 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 16:02:49 -0400 Subject: [PATCH 025/198] disable slidehsow mode toggle when there are no files in group --- .../src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java index c9220b174f..9ab2e8849e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java @@ -221,6 +221,7 @@ public class GroupPane extends BorderPane implements GroupView { final String header = getHeaderString(); final List fileIds = getGrouping().fileIds(); Platform.runLater(() -> { + slideShowToggle.setDisable(fileIds.isEmpty()); gridView.getItems().setAll(fileIds); groupLabel.setText(header); }); @@ -347,7 +348,6 @@ public class GroupPane extends BorderPane implements GroupView { HBox.setHgrow(spacer, Priority.ALWAYS); spacer.setMinWidth(Region.USE_PREF_SIZE); - try { grpTagSplitMenu.setText(TagUtils.getFollowUpTagName().getDisplayName()); grpTagSplitMenu.setOnAction(createGrpTagMenuItem(TagUtils.getFollowUpTagName()).getOnAction()); @@ -589,7 +589,6 @@ public class GroupPane extends BorderPane implements GroupView { gridView.getItems().setAll(Collections.emptyList()); Platform.runLater(() -> { setCenter(null); - groupLabel.setText(""); resetScrollBar(); if (false == Case.isCaseOpen()) { @@ -608,6 +607,7 @@ public class GroupPane extends BorderPane implements GroupView { gridView.getItems().setAll(getGrouping().fileIds()); Platform.runLater(() -> { + slideShowToggle.setDisable(gridView.getItems().isEmpty()); groupLabel.setText(header); resetScrollBar(); if (viewState.getMode() == GroupViewMode.TILE) { From 7212cdf951e387f84c97cf4b57b2b3c0bd860561 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 16:57:55 -0400 Subject: [PATCH 026/198] properly save group viewed state to db create category groups on initialization don't replace groups only insert read seen state at group construction --- .../imagegallery/datamodel/DrawableDB.java | 257 +++++++++--------- .../imagegallery/grouping/DrawableGroup.java | 5 +- .../imagegallery/grouping/GroupManager.java | 3 +- .../autopsy/imagegallery/gui/GroupPane.java | 4 +- 4 files changed, 137 insertions(+), 132 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 422ff028a9..cf09d620d2 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -71,51 +71,51 @@ import org.sqlite.SQLiteJDBCLoader; * the future. see also {@link EventsDB} in the timeline viewer. */ public final class DrawableDB { - + private static final java.util.logging.Logger LOGGER = Logger.getLogger(DrawableDB.class.getName()); //column name constants////////////////////// private static final String ANALYZED = "analyzed"; - + private static final String OBJ_ID = "obj_id"; - + private static final String HASH_SET_NAME = "hash_set_name"; - + private final PreparedStatement insertHashSetStmt; - + private final PreparedStatement groupSeenQueryStmt; - + private final PreparedStatement insertGroupStmt; - + private final List preparedStatements = new ArrayList<>(); - + private final PreparedStatement removeFileStmt; - + private final PreparedStatement updateGroupStmt; - + private final PreparedStatement selectHashSetStmt; - + private final PreparedStatement selectHashSetNamesStmt; - + private final PreparedStatement insertHashHitStmt; - + private final PreparedStatement updateFileStmt; private PreparedStatement insertFileStmt; - + private final PreparedStatement pathGroupStmt; - + private final PreparedStatement nameGroupStmt; - + private final PreparedStatement created_timeGroupStmt; - + private final PreparedStatement modified_timeGroupStmt; - + private final PreparedStatement makeGroupStmt; - + private final PreparedStatement modelGroupStmt; - + private final PreparedStatement analyzedGroupStmt; - + private final PreparedStatement hashSetGroupStmt; /** @@ -128,13 +128,13 @@ public final class DrawableDB { * list of observers to be notified if the database changes */ private final HashSet updateListeners = new HashSet<>(); - + private GroupManager groupManager; - + private final Path dbPath; - + volatile private Connection con; - + private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true); //use fairness policy private final Lock DBLock = rwLock.writeLock(); //using exclusing lock for all db ops for now @@ -206,9 +206,9 @@ public final class DrawableDB { insertFileStmt = prepareStatement( "INSERT OR IGNORE INTO drawable_files (obj_id , path, name, created_time, modified_time, make, model, analyzed) " + "VALUES (?,?,?,?,?,?,?,?)"); - + removeFileStmt = prepareStatement("delete from drawable_files where obj_id = ?"); - + pathGroupStmt = prepareStatement("select obj_id , analyzed from drawable_files where path = ? ", DrawableAttribute.PATH); nameGroupStmt = prepareStatement("select obj_id , analyzed from drawable_files where name = ? ", DrawableAttribute.NAME); created_timeGroupStmt = prepareStatement("select obj_id , analyzed from drawable_files where created_time = ? ", DrawableAttribute.CREATED_TIME); @@ -217,23 +217,26 @@ public final class DrawableDB { modelGroupStmt = prepareStatement("select obj_id , analyzed from drawable_files where model = ? ", DrawableAttribute.MODEL); analyzedGroupStmt = prepareStatement("Select obj_id , analyzed from drawable_files where analyzed = ?", DrawableAttribute.ANALYZED); hashSetGroupStmt = prepareStatement("select drawable_files.obj_id as obj_id, analyzed from drawable_files , hash_sets , hash_set_hits where drawable_files.obj_id = hash_set_hits.obj_id and hash_sets.hash_set_id = hash_set_hits.hash_set_id and hash_sets.hash_set_name = ?", DrawableAttribute.HASHSET); - + updateGroupStmt = prepareStatement("update groups set seen = ? where value = ? and attribute = ?"); - insertGroupStmt = prepareStatement("insert or replace into groups (value, attribute) values (?,?)"); - + insertGroupStmt = prepareStatement("insert or ignore into groups (value, attribute) values (?,?)"); + groupSeenQueryStmt = prepareStatement("select seen from groups where value = ? and attribute = ?"); - + selectHashSetNamesStmt = prepareStatement("SELECT DISTINCT hash_set_name FROM hash_sets"); insertHashSetStmt = prepareStatement("insert or ignore into hash_sets (hash_set_name) values (?)"); selectHashSetStmt = prepareStatement("select hash_set_id from hash_sets where hash_set_name = ?"); - + insertHashHitStmt = prepareStatement("insert or ignore into hash_set_hits (hash_set_id, obj_id) values (?,?)"); - + + for (Category cat : Category.values()) { + insertGroup(cat.getDisplayName(), DrawableAttribute.CATEGORY); + } initializeImageList(); } else { throw new ExceptionInInitializerError(); } - + } /** @@ -271,7 +274,7 @@ public final class DrawableDB { if (attr != null) { groupStatementMap.put(attr, prepareStatement); } - + return prepareStatement; } @@ -284,7 +287,7 @@ public final class DrawableDB { * @return */ public static DrawableDB getDrawableDB(Path dbPath, SleuthkitCase tskCase) { - + try { return new DrawableDB(dbPath.resolve("drawable.db"), tskCase); } catch (SQLException ex) { @@ -295,7 +298,7 @@ public final class DrawableDB { return null; } } - + private void setPragmas() throws SQLException { //this should match Sleuthkit db setupt @@ -321,7 +324,7 @@ public final class DrawableDB { //we never delete anything so... statement.execute("PRAGMA auto_vacuum = 0"); } - + try { LOGGER.log(Level.INFO, String.format("sqlite-jdbc version %s loaded in %s mode", SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode() @@ -329,7 +332,7 @@ public final class DrawableDB { } catch (Exception exception) { LOGGER.log(Level.WARNING, "exception while checking sqlite-jdbc version and mode", exception); } - + } /** @@ -344,7 +347,7 @@ public final class DrawableDB { openDBCon(); } setPragmas(); - + } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "problem accessing database", ex); return false; @@ -364,7 +367,7 @@ public final class DrawableDB { LOGGER.log(Level.SEVERE, "problem creating drawable_files table", ex); return false; } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE TABLE if not exists groups " + "(group_id INTEGER PRIMARY KEY, " @@ -377,7 +380,7 @@ public final class DrawableDB { LOGGER.log(Level.SEVERE, "problem creating groups table", ex); return false; } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE TABLE if not exists hash_sets " + "( hash_set_id INTEGER primary key," @@ -387,7 +390,7 @@ public final class DrawableDB { LOGGER.log(Level.SEVERE, "problem creating hash_sets table", ex); return false; } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE TABLE if not exists hash_set_hits " + "(hash_set_id INTEGER REFERENCES hash_sets(hash_set_id) not null, " @@ -398,45 +401,45 @@ public final class DrawableDB { LOGGER.log(Level.SEVERE, "problem creating hash_set_hits table", ex); return false; } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE INDEX if not exists path_idx ON drawable_files(path)"; stmt.execute(sql); } catch (SQLException ex) { LOGGER.log(Level.WARNING, "problem creating path_idx", ex); } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE INDEX if not exists name_idx ON drawable_files(name)"; stmt.execute(sql); } catch (SQLException ex) { LOGGER.log(Level.WARNING, "problem creating name_idx", ex); } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE INDEX if not exists make_idx ON drawable_files(make)"; stmt.execute(sql); } catch (SQLException ex) { LOGGER.log(Level.WARNING, "problem creating make_idx", ex); } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE INDEX if not exists model_idx ON drawable_files(model)"; stmt.execute(sql); } catch (SQLException ex) { LOGGER.log(Level.WARNING, "problem creating model_idx", ex); } - + try (Statement stmt = con.createStatement()) { String sql = "CREATE INDEX if not exists analyzed_idx ON drawable_files(analyzed)"; stmt.execute(sql); } catch (SQLException ex) { LOGGER.log(Level.WARNING, "problem creating analyzed_idx", ex); } - + return true; } - + @Override public void finalize() throws Throwable { try { @@ -445,7 +448,7 @@ public final class DrawableDB { super.finalize(); } } - + public void closeDBCon() { if (con != null) { try { @@ -457,7 +460,7 @@ public final class DrawableDB { } con = null; } - + public void openDBCon() { try { if (con == null || con.isClosed()) { @@ -467,7 +470,7 @@ public final class DrawableDB { LOGGER.log(Level.WARNING, "Failed to open connection to drawable.db", ex); } } - + public boolean isClosed() throws SQLException { if (con == null) { return true; @@ -495,7 +498,7 @@ public final class DrawableDB { } return names; } - + public boolean isGroupSeen(GroupKey groupKey) { dbReadLock(); try { @@ -514,7 +517,7 @@ public final class DrawableDB { } return false; } - + public void markGroupSeen(GroupKey gk, boolean seen) { dbWriteLock(); try { @@ -530,41 +533,41 @@ public final class DrawableDB { dbWriteUnlock(); } } - + public boolean removeFile(long id) { DrawableTransaction trans = beginTransaction(); boolean removeFile = removeFile(id, trans); commitTransaction(trans, true); return removeFile; } - + public void updateFile(DrawableFile f) { DrawableTransaction trans = beginTransaction(); updateFile(f, trans); commitTransaction(trans, true); } - + public void insertFile(DrawableFile f) { DrawableTransaction trans = beginTransaction(); insertFile(f, trans); commitTransaction(trans, true); } - + public void insertFile(DrawableFile f, DrawableTransaction tr) { insertOrUpdateFile(f, tr, insertFileStmt); } - + public void updateFile(DrawableFile f, DrawableTransaction tr) { insertOrUpdateFile(f, tr, updateFileStmt); } - + private void insertOrUpdateFile(DrawableFile f, DrawableTransaction tr, PreparedStatement stmt) { //TODO: implement batch version -jm if (tr.isClosed()) { throw new IllegalArgumentException("can't update database with closed transaction"); } - + dbWriteLock(); try { // Update the list of file IDs in memory @@ -580,9 +583,9 @@ public final class DrawableDB { stmt.setString(7, f.getModel()); stmt.setBoolean(8, f.isAnalyzed()); stmt.executeUpdate(); - + final Collection hashSetNames = DrawableAttribute.HASHSET.getValue(f); - + if (hashSetNames.isEmpty() == false) { for (String name : hashSetNames) { @@ -613,9 +616,9 @@ public final class DrawableDB { insertGroup(val.toString(), attr); } } - + tr.addUpdatedFile(f.getId()); - + } catch (SQLException | NullPointerException ex) { // This is one of the places where we get an error if the case is closed during processing, // which doesn't need to be reported here. @@ -626,38 +629,38 @@ public final class DrawableDB { dbWriteUnlock(); } } - + public DrawableTransaction beginTransaction() { return new DrawableTransaction(); } - + public void commitTransaction(DrawableTransaction tr, Boolean notify) { if (tr.isClosed()) { throw new IllegalArgumentException("can't close already closed transaction"); } tr.commit(notify); } - + public void addUpdatedFileListener(FileUpdateEvent.FileUpdateListener l) { updateListeners.add(l); } - + private void fireUpdatedFiles(Collection fileIDs) { for (FileUpdateEvent.FileUpdateListener listener : updateListeners) { listener.handleFileUpdate(FileUpdateEvent.newUpdateEvent(fileIDs, null)); } } - + private void fireRemovedFiles(Collection fileIDs) { for (FileUpdateEvent.FileUpdateListener listener : updateListeners) { listener.handleFileUpdate(FileUpdateEvent.newRemovedEvent(fileIDs)); } } - + public Boolean isFileAnalyzed(DrawableFile f) { return isFileAnalyzed(f.getId()); } - + public Boolean isFileAnalyzed(long fileId) { dbReadLock(); try (Statement stmt = con.createStatement(); @@ -670,12 +673,12 @@ public final class DrawableDB { } finally { dbReadUnlock(); } - + return false; } - + public Boolean areFilesAnalyzed(Collection fileIds) { - + dbReadLock(); try (Statement stmt = con.createStatement(); //Can't make this a preprared statement because of the IN ( ... ) @@ -688,15 +691,15 @@ public final class DrawableDB { } finally { dbReadUnlock(); } - + return false; } - + public Boolean isGroupAnalyzed(GroupKey gk) { dbReadLock(); try { List fileIDsInGroup = getFileIDsInGroup(gk); - + try { // In testing, this method appears to be a lot faster than doing one large select statement for (Long fileID : fileIDsInGroup) { @@ -709,7 +712,7 @@ public final class DrawableDB { } return true; } - + } catch (SQLException ex) { LOGGER.log(Level.WARNING, "problem counting analyzed files: ", ex); } @@ -863,9 +866,9 @@ public final class DrawableDB { * @return */ public > List findValuesForAttribute(DrawableAttribute groupBy, GroupSortBy sortBy, SortOrder sortOrder) { - + List vals = new ArrayList<>(); - + switch (groupBy.attrName) { case ANALYZED: case CATEGORY: @@ -877,7 +880,7 @@ public final class DrawableDB { dbReadLock(); //TODO: convert this to prepared statement StringBuilder query = new StringBuilder("select " + groupBy.attrName.toString() + ", count(*) from drawable_files group by " + groupBy.attrName.toString()); - + String orderByClause = ""; switch (sortBy) { case GROUP_BY_VALUE: @@ -890,12 +893,12 @@ public final class DrawableDB { // case PRIORITY: break; } - + query.append(orderByClause); - + if (orderByClause.equals("") == false) { String sortOrderClause = ""; - + switch (sortOrder) { case DESCENDING: sortOrderClause = " DESC"; @@ -908,7 +911,7 @@ public final class DrawableDB { } query.append(sortOrderClause); } - + try (Statement stmt = con.createStatement(); ResultSet valsResults = stmt.executeQuery(query.toString())) { while (valsResults.next()) { @@ -920,13 +923,13 @@ public final class DrawableDB { dbReadUnlock(); } } - + return vals; } - + public void insertGroup(final String value, DrawableAttribute groupBy) { dbWriteLock(); - + try { //PreparedStatement insertGroup = con.prepareStatement("insert or replace into groups (value, attribute, seen) values (?,?,0)"); insertGroupStmt.clearParameters(); @@ -980,9 +983,9 @@ public final class DrawableDB { return null; } } - + public List getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { - + if (groupKey.getAttribute().isDBColumn) { switch (groupKey.getAttribute().attrName) { case CATEGORY: @@ -996,7 +999,7 @@ public final class DrawableDB { try { PreparedStatement statement = getGroupStatment(groupKey.getAttribute()); statement.setObject(1, groupKey.getValue()); - + try (ResultSet valsResults = statement.executeQuery()) { while (valsResults.next()) { files.add(valsResults.getLong(OBJ_ID)); @@ -1007,10 +1010,10 @@ public final class DrawableDB { } finally { dbReadUnlock(); } - + return files; } - + public List> getFilesInGroup(GroupKey key) throws TskCoreException { List> files = new ArrayList<>(); dbReadLock(); @@ -1026,9 +1029,9 @@ public final class DrawableDB { default: statement = getGroupStatment(key.getAttribute()); } - + statement.setObject(1, key.getValue()); - + try (ResultSet valsResults = statement.executeQuery()) { while (valsResults.next()) { files.add(getFileFromID(valsResults.getLong(OBJ_ID), valsResults.getBoolean(ANALYZED))); @@ -1039,16 +1042,16 @@ public final class DrawableDB { } finally { dbReadUnlock(); } - + return files; } - + private void closeStatements() throws SQLException { for (PreparedStatement pStmt : preparedStatements) { pStmt.close(); } } - + public List> getFilesWithCategory(Category cat) throws TskCoreException, IllegalArgumentException { try { List> files = new ArrayList<>(); @@ -1065,18 +1068,18 @@ public final class DrawableDB { throw ex; } } - + private PreparedStatement getGroupStatment(DrawableAttribute groupBy) { return groupStatementMap.get(groupBy); - + } - + public int countAllFiles() { int result = -1; dbReadLock(); try (ResultSet rs = con.createStatement().executeQuery("select count(*) as COUNT from drawable_files")) { while (rs.next()) { - + result = rs.getInt("COUNT"); break; } @@ -1101,7 +1104,7 @@ public final class DrawableDB { } int valsResults = 0; dbWriteLock(); - + try { // Update the list of file IDs in memory removeImageFileFromList(id); @@ -1119,11 +1122,11 @@ public final class DrawableDB { //indicates succesfull removal of 1 file return valsResults == 1; } - + public class MultipleTransactionException extends IllegalStateException { - + private static final String CANNOT_HAVE_MORE_THAN_ONE_OPEN_TRANSACTIO = "cannot have more than one open transaction"; - + public MultipleTransactionException() { super(CANNOT_HAVE_MORE_THAN_ONE_OPEN_TRANSACTIO); } @@ -1169,31 +1172,31 @@ public final class DrawableDB { */ @GuardedBy("fileIDlist") private final Set fileIDsInDB = new HashSet<>(); - + public boolean isInDB(Long id) { synchronized (fileIDsInDB) { return fileIDsInDB.contains(id); } } - + private void addImageFileToList(Long id) { synchronized (fileIDsInDB) { fileIDsInDB.add(id); } } - + private void removeImageFileFromList(Long id) { synchronized (fileIDsInDB) { fileIDsInDB.remove(id); } } - + public int getNumberOfImageFilesInList() { synchronized (fileIDsInDB) { return fileIDsInDB.size(); } } - + private void initializeImageList() { synchronized (fileIDsInDB) { dbReadLock(); @@ -1215,7 +1218,7 @@ public final class DrawableDB { * For performance reasons, keep the file type in memory */ private final Map videoFileMap = new ConcurrentHashMap<>(); - + public boolean isVideoFile(AbstractFile f) { return videoFileMap.computeIfAbsent(f, ImageGalleryModule::isVideoFile); } @@ -1242,7 +1245,7 @@ public final class DrawableDB { .map(Content::getId) .filter(this::isInDB) .count(); - + } catch (IllegalStateException ex) { LOGGER.log(Level.WARNING, "Case closed while getting files"); } catch (TskCoreException ex1) { @@ -1255,11 +1258,11 @@ public final class DrawableDB { * inner class that can reference access database connection */ public class DrawableTransaction { - + private final Set updatedFiles; - + private final Set removedFiles; - + private boolean closed = false; /** @@ -1278,13 +1281,13 @@ public final class DrawableDB { dbWriteLock(); try { con.setAutoCommit(false); - + } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "failed to set auto-commit to to false", ex); } - + } - + synchronized public void rollback() { if (!closed) { try { @@ -1297,14 +1300,14 @@ public final class DrawableDB { } } } - + synchronized private void commit(Boolean notify) { if (!closed) { try { con.commit(); // make sure we close before we update, bc they'll need locks close(); - + if (notify) { fireUpdatedFiles(updatedFiles); fireRemovedFiles(removedFiles); @@ -1319,7 +1322,7 @@ public final class DrawableDB { } } } - + synchronized private void close() { if (!closed) { try { @@ -1336,15 +1339,15 @@ public final class DrawableDB { } } } - + synchronized public Boolean isClosed() { return closed; } - + synchronized private void addUpdatedFile(Long f) { updatedFiles.add(f); } - + synchronized private void addRemovedFile(long id) { removedFiles.add(id); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index 88aa65cb09..e6d1f3dad8 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -70,9 +70,10 @@ public class DrawableGroup implements Comparable { return groupKey.getValueDisplayName(); } - DrawableGroup(GroupKey groupKey, List filesInGroup) { + DrawableGroup(GroupKey groupKey, List filesInGroup, boolean seen) { this.groupKey = groupKey; - fileIDs.setAll(filesInGroup); + this.fileIDs.setAll(filesInGroup); + this.seen.set(seen); } synchronized public int getSize() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 9f90ab6fca..ec35f6bb60 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -243,8 +243,9 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { */ public DrawableGroup makeGroup(GroupKey groupKey, List files) { List newFiles = files == null ? new ArrayList<>() : files; + final boolean groupSeen = db.isGroupSeen(groupKey); + DrawableGroup g = new DrawableGroup(groupKey, newFiles, groupSeen); - DrawableGroup g = new DrawableGroup(groupKey, newFiles); g.seenProperty().addListener((observable, oldSeen, newSeen) -> { markGroupSeen(g, newSeen); }); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java index c9220b174f..e828c446d2 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java @@ -347,7 +347,6 @@ public class GroupPane extends BorderPane implements GroupView { HBox.setHgrow(spacer, Priority.ALWAYS); spacer.setMinWidth(Region.USE_PREF_SIZE); - try { grpTagSplitMenu.setText(TagUtils.getFollowUpTagName().getDisplayName()); grpTagSplitMenu.setOnAction(createGrpTagMenuItem(TagUtils.getFollowUpTagName()).getOnAction()); @@ -586,8 +585,9 @@ public class GroupPane extends BorderPane implements GroupView { if (isNull(viewState) || isNull(viewState.getGroup())) { this.grouping.set(null); - gridView.getItems().setAll(Collections.emptyList()); + Platform.runLater(() -> { + gridView.getItems().setAll(Collections.emptyList()); setCenter(null); groupLabel.setText(""); From 44e40a2a2ed99c6602c09a9fd620e2e3a1dd9a99 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 11 Jun 2015 17:00:52 -0400 Subject: [PATCH 027/198] create new groups as needed when marking seen --- .../sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index cf09d620d2..a5f91bb9d3 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -218,7 +218,7 @@ public final class DrawableDB { analyzedGroupStmt = prepareStatement("Select obj_id , analyzed from drawable_files where analyzed = ?", DrawableAttribute.ANALYZED); hashSetGroupStmt = prepareStatement("select drawable_files.obj_id as obj_id, analyzed from drawable_files , hash_sets , hash_set_hits where drawable_files.obj_id = hash_set_hits.obj_id and hash_sets.hash_set_id = hash_set_hits.hash_set_id and hash_sets.hash_set_name = ?", DrawableAttribute.HASHSET); - updateGroupStmt = prepareStatement("update groups set seen = ? where value = ? and attribute = ?"); + updateGroupStmt = prepareStatement("insert or replace into groups (seen, value, attribute) values( ?, ? , ?)"); insertGroupStmt = prepareStatement("insert or ignore into groups (value, attribute) values (?,?)"); groupSeenQueryStmt = prepareStatement("select seen from groups where value = ? and attribute = ?"); From c52b58a2305d19c59670e8f62040943f4177331d Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 11 Jun 2015 23:10:59 -0400 Subject: [PATCH 028/198] File type refreshes on events - prevents stale results --- .../autopsy/datamodel/FileTypeNode.java | 108 ++++++++++++++---- .../autopsy/datamodel/FileTypesNode.java | 90 +++++++++++++-- 2 files changed, 169 insertions(+), 29 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java index 03a2123466..586a9c9fb3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java @@ -19,6 +19,8 @@ package org.sleuthkit.autopsy.datamodel; import java.util.List; +import java.util.Observable; +import java.util.Observer; import java.util.logging.Level; import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; @@ -42,35 +44,58 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; /** - * Node for a specific file type / extension + * Node for a specific file type / extension. Children of it will be the files + * of that type. */ public class FileTypeNode extends DisplayableItemNode { FileTypeExtensionFilters.SearchFilterInterface filter; SleuthkitCase skCase; + // deprecated in favor of the version that takes an observable to provide refresh updates + @Deprecated FileTypeNode(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase) { super(Children.create(new FileTypeChildFactory(filter, skCase), true), Lookups.singleton(filter.getDisplayName())); this.filter = filter; this.skCase = skCase; + init(); + } + /** + * + * @param filter Extensions that will be shown for this node + * @param skCase + * @param o Observable that sends updates when the child factories should + * refresh + */ + FileTypeNode(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) { + super(Children.create(new FileTypeChildFactory(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName())); + this.filter = filter; + this.skCase = skCase; + init(); + o.addObserver(new FileTypeNodeObserver()); + } + + private void init() { super.setName(filter.getName()); - - /* There is a bug in the below code. The count becomes inaccurate when ZIP files - * blow up and when a 2nd data source is added. I think we need to change the overall - * design of this and have a singleton class (or some other place) that will store - * the results and each level can either ask it for the count or specific ids and - * it would be responsible for listening for case events and data events. - */ - //get count of children without preloading all children nodes - final long count = new FileTypeChildFactory(filter, skCase).calculateItems(); - //final long count = getChildren().getNodesCount(true); - - super.setDisplayName(filter.getDisplayName() + " (" + count + ")"); - + updateDisplayName(); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS } + // update the display name when new events are fired + private class FileTypeNodeObserver implements Observer { + + @Override + public void update(Observable o, Object arg) { + updateDisplayName(); + } + } + + private void updateDisplayName() { + final long count = FileTypeChildFactory.calculateItems(skCase, filter); + super.setDisplayName(filter.getDisplayName() + " (" + count + ")"); + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -110,24 +135,67 @@ public class FileTypeNode extends DisplayableItemNode { /** * Child node factory for a specific file type - does the database query. */ - public static class FileTypeChildFactory extends ChildFactory { + public static class FileTypeChildFactory extends ChildFactory.Detachable { + private final SleuthkitCase skCase; private final FileTypeExtensionFilters.SearchFilterInterface filter; - private final Logger logger = Logger.getLogger(FileTypeChildFactory.class.getName()); + private final static Logger logger = Logger.getLogger(FileTypeChildFactory.class.getName()); + private Observable notifier; + // use the constructor that gets an observable passed in for updates + @Deprecated FileTypeChildFactory(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase) { super(); this.filter = filter; this.skCase = skCase; + notifier = null; + } + + /** + * + * @param filter Extensions to display + * @param skCase + * @param o Observable that will notify when there could be new data to + * display + */ + FileTypeChildFactory(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) { + super(); + this.filter = filter; + this.skCase = skCase; + notifier = o; + } + + @Override + protected void addNotify() { + if (notifier != null) { + notifier.addObserver(new FileTypeChildFactoryObserver()); + } + } + + @Override + protected void removeNotify() { + if (notifier != null) { + notifier.deleteObserver(new FileTypeChildFactoryObserver()); + } + } + + // Cause refresh of children if there are changes + private class FileTypeChildFactoryObserver implements Observer { + + @Override + public void update(Observable o, Object arg) { + refresh(true); + } } /** * Get children count without actually loading all nodes + * * @return */ - long calculateItems() { + static long calculateItems(SleuthkitCase sleuthkitCase, FileTypeExtensionFilters.SearchFilterInterface filter) { try { - return skCase.countFilesWhere(createQuery()); + return sleuthkitCase.countFilesWhere(createQuery(filter)); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error getting file search view count", ex); //NON-NLS return 0; @@ -137,7 +205,7 @@ public class FileTypeNode extends DisplayableItemNode { @Override protected boolean createKeys(List list) { try { - List files = skCase.findAllFilesWhere(createQuery()); + List files = skCase.findAllFilesWhere(createQuery(filter)); list.addAll(files); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS @@ -145,7 +213,7 @@ public class FileTypeNode extends DisplayableItemNode { return true; } - private String createQuery() { + private static String createQuery(FileTypeExtensionFilters.SearchFilterInterface filter) { StringBuilder query = new StringBuilder(); query.append("(dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(")"); //NON-NLS if (UserPreferences.hideKnownFilesInViewsTree()) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java index 198119db84..169744298d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java @@ -18,18 +18,23 @@ */ package org.sleuthkit.autopsy.datamodel; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.Arrays; import java.util.List; +import java.util.Observable; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.SleuthkitCase; /** - * Node for extension/file type filter view + * Node for root of file types view. Children are nodes for specific types. */ public class FileTypesNode extends DisplayableItemNode { @@ -42,7 +47,23 @@ public class FileTypesNode extends DisplayableItemNode { * something to provide a sub-node. */ FileTypesNode(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter) { - super(Children.create(new FileTypesChildren(skCase, filter), true), Lookups.singleton(filter == null ? FNAME : filter.getName())); + super(Children.create(new FileTypesChildren(skCase, filter, null), true), Lookups.singleton(filter == null ? FNAME : filter.getName())); + init(filter); + } + + /** + * + * @param skCase + * @param filter + * @param o Observable that was created by a higher-level node that provides + * updates on events + */ + private FileTypesNode(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter, Observable o) { + super(Children.create(new FileTypesChildren(skCase, filter, o), true), Lookups.singleton(filter == null ? FNAME : filter.getName())); + init(filter); + } + + private void init(FileTypeExtensionFilters.RootFilter filter) { // root node of tree if (filter == null) { super.setName(FNAME); @@ -52,7 +73,7 @@ public class FileTypesNode extends DisplayableItemNode { super.setName(filter.getName()); super.setDisplayName(filter.getDisplayName()); } - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS } @Override @@ -88,16 +109,68 @@ public class FileTypesNode extends DisplayableItemNode { private SleuthkitCase skCase; private FileTypeExtensionFilters.RootFilter filter; + private Observable notifier; /** * * @param skCase * @param filter Is null for root node + * @param o Observable that provides updates based on events being fired + * (or null if one needs to be created) */ - public FileTypesChildren(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter) { + public FileTypesChildren(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter, Observable o) { super(); this.skCase = skCase; this.filter = filter; + if (o == null) { + this.notifier = new FileTypesChildrenObservable(); + } else { + this.notifier = o; + } + } + + /** + * Listens for case and ingest invest. Updates observers when events are + * fired. FileType and FileTypes nodes are all listening to this. + */ + private final class FileTypesChildrenObservable extends Observable { + + FileTypesChildrenObservable() { + IngestManager.getInstance().addIngestJobEventListener(pcl); + IngestManager.getInstance().addIngestModuleEventListener(pcl); + Case.addPropertyChangeListener(pcl); + } + + private void removeListeners() { + IngestManager.getInstance().removeIngestJobEventListener(pcl); + IngestManager.getInstance().removeIngestModuleEventListener(pcl); + Case.removePropertyChangeListener(pcl); + } + + private final PropertyChangeListener pcl = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + String eventType = evt.getPropertyName(); + + // new file was added + if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { + update(); + } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) + || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { + update(); + } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { + // case was closed. Remove listeners so that we don't get called with a stale case handle + if (evt.getNewValue() == null) { + removeListeners(); + } + } + } + }; + + private void update() { + setChanged(); + notifyObservers(); + } } @Override @@ -105,8 +178,7 @@ public class FileTypesNode extends DisplayableItemNode { // root node if (filter == null) { list.addAll(Arrays.asList(FileTypeExtensionFilters.RootFilter.values())); - } - // document and executable has another level of nodes + } // document and executable has another level of nodes else if (filter.equals(FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER)) { list.addAll(Arrays.asList(FileTypeExtensionFilters.DocumentFilter.values())); } else if (filter.equals(FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER)) { @@ -119,11 +191,11 @@ public class FileTypesNode extends DisplayableItemNode { protected Node createNodeForKey(FileTypeExtensionFilters.SearchFilterInterface key) { // make new nodes for the sub-nodes if (key.getName().equals(FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER.getName())) { - return new FileTypesNode(skCase, FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER); + return new FileTypesNode(skCase, FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER, notifier); } else if (key.getName().equals(FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER.getName())) { - return new FileTypesNode(skCase, FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER); + return new FileTypesNode(skCase, FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER, notifier); } else { - return new FileTypeNode(key, skCase); + return new FileTypeNode(key, skCase, notifier); } } } From f520af45b2ef9f65493eb6426af53759e6e1e025 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 11 Jun 2015 23:49:39 -0400 Subject: [PATCH 029/198] File size node refreshes based on updates --- .../sleuthkit/autopsy/datamodel/FileSize.java | 156 +++++++++++++++--- 1 file changed, 136 insertions(+), 20 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java index 035c4fb72a..0fb8db2b6d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java @@ -18,9 +18,13 @@ */ package org.sleuthkit.autopsy.datamodel; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Observable; +import java.util.Observer; import java.util.logging.Level; import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; @@ -29,7 +33,9 @@ import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; @@ -98,6 +104,7 @@ public class FileSize implements AutopsyVisitableItem { return this.skCase; } + /* Root node. Children are nodes for specific sizes. */ public static class FileSizeRootNode extends DisplayableItemNode { private static final String NAME = NbBundle.getMessage(FileSize.class, "FileSize.fileSizeRootNode.name"); @@ -136,14 +143,62 @@ public class FileSize implements AutopsyVisitableItem { } } + /* Makes the children for specific sizes */ public static class FileSizeRootChildren extends ChildFactory { private SleuthkitCase skCase; + private Observable notifier; public FileSizeRootChildren(SleuthkitCase skCase) { this.skCase = skCase; - + notifier = new FileSizeRootChildrenObservable(); } + + /** + * Listens for case and ingest invest. Updates observers when events are + * fired. FileType and FileTypes nodes are all listening to this. + */ + private final class FileSizeRootChildrenObservable extends Observable { + + FileSizeRootChildrenObservable() { + IngestManager.getInstance().addIngestJobEventListener(pcl); + IngestManager.getInstance().addIngestModuleEventListener(pcl); + Case.addPropertyChangeListener(pcl); + } + + private void removeListeners() { + IngestManager.getInstance().removeIngestJobEventListener(pcl); + IngestManager.getInstance().removeIngestModuleEventListener(pcl); + Case.removePropertyChangeListener(pcl); + } + + private final PropertyChangeListener pcl = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + String eventType = evt.getPropertyName(); + + // new file was added + if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { + // @@@ could check the minimum size here and only fire off updates if we know the file meets the min size criteria + update(); + } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) + || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { + update(); + } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { + // case was closed. Remove listeners so that we don't get called with a stale case handle + if (evt.getNewValue() == null) { + removeListeners(); + } + } + } + }; + + private void update() { + setChanged(); + notifyObservers(); + } + } + @Override protected boolean createKeys(List list) { @@ -153,26 +208,55 @@ public class FileSize implements AutopsyVisitableItem { @Override protected Node createNodeForKey(FileSizeFilter key) { - return new FileSizeNode(skCase, key); + return new FileSizeNode(skCase, key, notifier); } + /* Node for a specific size range. Children are files. */ public class FileSizeNode extends DisplayableItemNode { - private FileSizeFilter filter; - private final Logger logger = Logger.getLogger(FileSizeNode.class.getName()); - + + // use version with observer instead so that it updates + @Deprecated FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter) { - super(Children.create(new FileSizeChildren(filter, skCase), true), Lookups.singleton(filter.getDisplayName())); - super.setName(filter.getName()); + super(Children.create(new FileSizeChildren(filter, skCase, null), true), Lookups.singleton(filter.getDisplayName())); this.filter = filter; - + init(); + } + + /** + * + * @param skCase + * @param filter + * @param o Observable that provides updates when events are fired + */ + FileSizeNode(SleuthkitCase skCase, FileSizeFilter filter, Observable o) { + super(Children.create(new FileSizeChildren(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName())); + this.filter = filter; + init(); + o.addObserver(new FileSizeNodeObserver()); + } + + private void init() { + super.setName(filter.getName()); + String tooltip = filter.getDisplayName(); this.setShortDescription(tooltip); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-size-16.png"); //NON-NLS - //get count of children without preloading all children nodes - final long count = new FileSizeChildren(filter, skCase).calculateItems(); - //final long count = getChildren().getNodesCount(true); + updateDisplayName(); + } + + // update the display name when new events are fired + private class FileSizeNodeObserver implements Observer { + + @Override + public void update(Observable o, Object arg) { + updateDisplayName(); + } + } + + private void updateDisplayName() { + final long count = FileSizeChildren.calculateItems(skCase, filter); super.setDisplayName(filter.getDisplayName() + " (" + count + ")"); } @@ -204,15 +288,47 @@ public class FileSize implements AutopsyVisitableItem { } } - class FileSizeChildren extends ChildFactory { + /* Makes children, which are nodes for files of a given range */ + static class FileSizeChildren extends ChildFactory.Detachable { - private SleuthkitCase skCase; - private FileSizeFilter filter; - private final Logger logger = Logger.getLogger(FileSizeChildren.class.getName()); + private final SleuthkitCase skCase; + private final FileSizeFilter filter; + private final Observable notifier; + private static final Logger logger = Logger.getLogger(FileSizeChildren.class.getName()); - FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase) { + /** + * + * @param filter + * @param skCase + * @param o Observable that provides updates when new files are added to case + */ + FileSizeChildren(FileSizeFilter filter, SleuthkitCase skCase, Observable o) { this.skCase = skCase; this.filter = filter; + this.notifier = o; + } + + @Override + protected void addNotify() { + if (notifier != null) { + notifier.addObserver(new FileSizeChildrenObserver()); + } + } + + @Override + protected void removeNotify() { + if (notifier != null) { + notifier.deleteObserver(new FileSizeChildrenObserver()); + } + } + + // Cause refresh of children if there are changes + private class FileSizeChildrenObserver implements Observer { + + @Override + public void update(Observable o, Object arg) { + refresh(true); + } } @Override @@ -225,7 +341,7 @@ public class FileSize implements AutopsyVisitableItem { return true; } - private String makeQuery() { + private static String makeQuery(FileSizeFilter filter) { String query; switch (filter) { case SIZE_50_200: @@ -252,7 +368,7 @@ public class FileSize implements AutopsyVisitableItem { private List runFsQuery() { List ret = new ArrayList<>(); - String query = makeQuery(); + String query = makeQuery(filter); if (query == null) { return null; } @@ -272,9 +388,9 @@ public class FileSize implements AutopsyVisitableItem { * * @return */ - long calculateItems() { + static long calculateItems(SleuthkitCase sleuthkitCase, FileSizeFilter filter) { try { - return skCase.countFilesWhere(makeQuery()); + return sleuthkitCase.countFilesWhere(makeQuery(filter)); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error getting files by size search view count", ex); //NON-NLS return 0; From deb3fa3317ef7dac3600b5a248260dde843f18cf Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 11 Jun 2015 23:50:36 -0400 Subject: [PATCH 030/198] removed RecentFiles area of views --- Core/src/org/sleuthkit/autopsy/datamodel/RecentFiles.java | 2 ++ Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFiles.java b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFiles.java index 328bd71f0c..fbc63578bf 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFiles.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFiles.java @@ -23,6 +23,8 @@ import org.sleuthkit.datamodel.SleuthkitCase; /** * Recent files node support + * NOTE: As of june '15 we do not display this in the tree. + * It can be added back when we have filtering in the results area. */ class RecentFiles implements AutopsyVisitableItem { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java index 7431cf247f..45f9c0c6c5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java @@ -36,7 +36,9 @@ public class ViewsNode extends DisplayableItemNode { public ViewsNode(SleuthkitCase sleuthkitCase) { super(new RootContentChildren(Arrays.asList( new FileTypeExtensionFilters(sleuthkitCase), - new RecentFiles(sleuthkitCase), + // June '15: Recent Files was removed because it was not useful w/out filtering + // add it back in if we can filter the results to a more managable size. + // new RecentFiles(sleuthkitCase), new DeletedContent(sleuthkitCase), new FileSize(sleuthkitCase))), Lookups.singleton(NAME)); From 8852689726f0f4b983b3f84ba34c50b91d3be409 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Fri, 12 Jun 2015 09:31:50 -0400 Subject: [PATCH 031/198] Finished update to views area to refresh - listen to new data sources --- .../autopsy/datamodel/DeletedContent.java | 133 ++++++++++++++++-- .../sleuthkit/autopsy/datamodel/FileSize.java | 10 +- .../autopsy/datamodel/FileTypeNode.java | 5 +- .../autopsy/datamodel/FileTypesNode.java | 2 + 4 files changed, 131 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index 5e5ac5ffd5..b112cdcbe8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -18,9 +18,13 @@ */ package org.sleuthkit.autopsy.datamodel; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Observable; +import java.util.Observer; import java.util.logging.Level; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; @@ -31,7 +35,9 @@ import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; @@ -144,11 +150,60 @@ public class DeletedContent implements AutopsyVisitableItem { public static class DeletedContentsChildren extends ChildFactory { private SleuthkitCase skCase; + private Observable notifier; public DeletedContentsChildren(SleuthkitCase skCase) { this.skCase = skCase; - + this.notifier = new DeletedContentsChildrenObservable(); } + + /** + * Listens for case and ingest invest. Updates observers when events are + * fired. FileType and FileTypes nodes are all listening to this. + */ + private final class DeletedContentsChildrenObservable extends Observable { + + DeletedContentsChildrenObservable() { + IngestManager.getInstance().addIngestJobEventListener(pcl); + IngestManager.getInstance().addIngestModuleEventListener(pcl); + Case.addPropertyChangeListener(pcl); + } + + private void removeListeners() { + IngestManager.getInstance().removeIngestJobEventListener(pcl); + IngestManager.getInstance().removeIngestModuleEventListener(pcl); + Case.removePropertyChangeListener(pcl); + } + + private final PropertyChangeListener pcl = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + String eventType = evt.getPropertyName(); + + // new file was added + if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { + // @@@ COULD CHECK If the new file is deleted before notifying... + update(); + } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) + || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { + update(); + } else if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { + update(); + } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { + // case was closed. Remove listeners so that we don't get called with a stale case handle + if (evt.getNewValue() == null) { + removeListeners(); + } + } + } + }; + + private void update() { + setChanged(); + notifyObservers(); + } + } + @Override protected boolean createKeys(List list) { @@ -158,7 +213,7 @@ public class DeletedContent implements AutopsyVisitableItem { @Override protected Node createNodeForKey(DeletedContent.DeletedContentFilter key) { - return new DeletedContentNode(skCase, key); + return new DeletedContentNode(skCase, key, notifier); } public class DeletedContentNode extends DisplayableItemNode { @@ -166,17 +221,41 @@ public class DeletedContent implements AutopsyVisitableItem { private DeletedContent.DeletedContentFilter filter; private final Logger logger = Logger.getLogger(DeletedContentNode.class.getName()); + // Use version that has observer for updates + @Deprecated DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter) { - super(Children.create(new DeletedContentChildren(filter, skCase), true), Lookups.singleton(filter.getDisplayName())); - super.setName(filter.getName()); + super(Children.create(new DeletedContentChildren(filter, skCase, null), true), Lookups.singleton(filter.getDisplayName())); this.filter = filter; - + init(); + } + + DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, Observable o) { + super(Children.create(new DeletedContentChildren(filter, skCase, o), true), Lookups.singleton(filter.getDisplayName())); + this.filter = filter; + init(); + o.addObserver(new DeletedContentNodeObserver()); + } + + private void init() { + super.setName(filter.getName()); + String tooltip = filter.getDisplayName(); this.setShortDescription(tooltip); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS - + updateDisplayName(); + } + + // update the display name when new events are fired + private class DeletedContentNodeObserver implements Observer { + @Override + public void update(Observable o, Object arg) { + updateDisplayName(); + } + } + + private void updateDisplayName() { //get count of children without preloading all children nodes - final long count = new DeletedContentChildren(filter, skCase).calculateItems(); + final long count = DeletedContentChildren.calculateItems(skCase, filter); //final long count = getChildren().getNodesCount(true); super.setDisplayName(filter.getDisplayName() + " (" + count + ")"); } @@ -210,17 +289,43 @@ public class DeletedContent implements AutopsyVisitableItem { } } - class DeletedContentChildren extends ChildFactory { + static class DeletedContentChildren extends ChildFactory.Detachable { private SleuthkitCase skCase; private DeletedContent.DeletedContentFilter filter; - private final Logger logger = Logger.getLogger(DeletedContentChildren.class.getName()); + private static final Logger logger = Logger.getLogger(DeletedContentChildren.class.getName()); private static final int MAX_OBJECTS = 10001; + private final Observable notifier; - DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase) { + DeletedContentChildren(DeletedContent.DeletedContentFilter filter, SleuthkitCase skCase, Observable o) { this.skCase = skCase; this.filter = filter; + this.notifier = o; } + + private final Observer observer = new DeletedContentChildrenObserver(); + // Cause refresh of children if there are changes + private class DeletedContentChildrenObserver implements Observer { + @Override + public void update(Observable o, Object arg) { + refresh(true); + } + } + + @Override + protected void addNotify() { + if (notifier != null) { + notifier.addObserver(observer); + } + } + + @Override + protected void removeNotify() { + if (notifier != null) { + notifier.deleteObserver(observer); + } + } + @Override protected boolean createKeys(List list) { @@ -240,7 +345,7 @@ public class DeletedContent implements AutopsyVisitableItem { return true; } - private String makeQuery() { + static private String makeQuery(DeletedContent.DeletedContentFilter filter) { String query = ""; switch (filter) { case FS_DELETED_FILTER: @@ -280,7 +385,7 @@ public class DeletedContent implements AutopsyVisitableItem { private List runFsQuery() { List ret = new ArrayList<>(); - String query = makeQuery(); + String query = makeQuery(filter); try { ret = skCase.findAllFilesWhere(query); } catch (TskCoreException e) { @@ -296,9 +401,9 @@ public class DeletedContent implements AutopsyVisitableItem { * * @return */ - long calculateItems() { + static long calculateItems(SleuthkitCase sleuthkitCase, DeletedContent.DeletedContentFilter filter) { try { - return skCase.countFilesWhere(makeQuery()); + return sleuthkitCase.countFilesWhere(makeQuery(filter)); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error getting deleted files search view count", ex); //NON-NLS return 0; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java index 0fb8db2b6d..f87de544f4 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java @@ -179,11 +179,13 @@ public class FileSize implements AutopsyVisitableItem { // new file was added if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { - // @@@ could check the minimum size here and only fire off updates if we know the file meets the min size criteria + // @@@ could check the size here and only fire off updates if we know the file meets the min size criteria update(); } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { update(); + } else if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { + update(); } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { // case was closed. Remove listeners so that we don't get called with a stale case handle if (evt.getNewValue() == null) { @@ -311,17 +313,19 @@ public class FileSize implements AutopsyVisitableItem { @Override protected void addNotify() { if (notifier != null) { - notifier.addObserver(new FileSizeChildrenObserver()); + notifier.addObserver(observer); } } @Override protected void removeNotify() { if (notifier != null) { - notifier.deleteObserver(new FileSizeChildrenObserver()); + notifier.deleteObserver(observer); } } + private final Observer observer = new FileSizeChildrenObserver(); + // Cause refresh of children if there are changes private class FileSizeChildrenObserver implements Observer { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java index 586a9c9fb3..ba2d00a0da 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java @@ -168,16 +168,17 @@ public class FileTypeNode extends DisplayableItemNode { @Override protected void addNotify() { if (notifier != null) { - notifier.addObserver(new FileTypeChildFactoryObserver()); + notifier.addObserver(observer); } } @Override protected void removeNotify() { if (notifier != null) { - notifier.deleteObserver(new FileTypeChildFactoryObserver()); + notifier.deleteObserver(observer); } } + private final Observer observer = new FileTypeChildFactoryObserver(); // Cause refresh of children if there are changes private class FileTypeChildFactoryObserver implements Observer { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java index 169744298d..190bc6a352 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java @@ -158,6 +158,8 @@ public class FileTypesNode extends DisplayableItemNode { } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { update(); + } else if (eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { + update(); } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { // case was closed. Remove listeners so that we don't get called with a stale case handle if (evt.getNewValue() == null) { From c9c6170447806471d0d55cd5729f6c280de7299a Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Fri, 12 Jun 2015 09:34:42 -0400 Subject: [PATCH 032/198] remove observers when case is closed --- Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java | 1 + Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java | 1 + Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java | 1 + 3 files changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index b112cdcbe8..f15c182a98 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -170,6 +170,7 @@ public class DeletedContent implements AutopsyVisitableItem { } private void removeListeners() { + deleteObservers(); IngestManager.getInstance().removeIngestJobEventListener(pcl); IngestManager.getInstance().removeIngestModuleEventListener(pcl); Case.removePropertyChangeListener(pcl); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java index f87de544f4..9f9d53e3eb 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java @@ -167,6 +167,7 @@ public class FileSize implements AutopsyVisitableItem { } private void removeListeners() { + deleteObservers(); IngestManager.getInstance().removeIngestJobEventListener(pcl); IngestManager.getInstance().removeIngestModuleEventListener(pcl); Case.removePropertyChangeListener(pcl); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java index 190bc6a352..f9e583d45a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java @@ -142,6 +142,7 @@ public class FileTypesNode extends DisplayableItemNode { } private void removeListeners() { + deleteObservers(); IngestManager.getInstance().removeIngestJobEventListener(pcl); IngestManager.getInstance().removeIngestModuleEventListener(pcl); Case.removePropertyChangeListener(pcl); From bd79dbe85046a5f5864741be1a3c7a89535c396d Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Fri, 12 Jun 2015 09:38:14 -0400 Subject: [PATCH 033/198] updated comment --- Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java | 2 +- Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index f15c182a98..37f7140d37 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -159,7 +159,7 @@ public class DeletedContent implements AutopsyVisitableItem { /** * Listens for case and ingest invest. Updates observers when events are - * fired. FileType and FileTypes nodes are all listening to this. + * fired. Other nodes are listening to this for changes. */ private final class DeletedContentsChildrenObservable extends Observable { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java index 9f9d53e3eb..e6f32e1ef2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java @@ -156,7 +156,7 @@ public class FileSize implements AutopsyVisitableItem { /** * Listens for case and ingest invest. Updates observers when events are - * fired. FileType and FileTypes nodes are all listening to this. + * fired. Size-based nodes are listening to this for changes. */ private final class FileSizeRootChildrenObservable extends Observable { From f4480a77abb5cb1e482077e9d02803ba1461dfb1 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Fri, 12 Jun 2015 11:40:10 -0400 Subject: [PATCH 034/198] module output dir change with change in current case --- .../EmbeddedFileExtractorIngestModule.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java index 90da2dca79..e2e9bd6a62 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java @@ -45,17 +45,12 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule private final IngestServices services = IngestServices.getInstance(); static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // "iso"}; NON-NLS - //buffer for checking file headers and signatures - private static final int readHeaderSize = 4; - private static final byte[] fileHeaderBuffer = new byte[readHeaderSize]; - private static final int ZIP_SIGNATURE_BE = 0x504B0304; private IngestJobContext context; private long jobId; private final static IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); - private static final Case currentCase = Case.getCurrentCase(); - protected static final String moduleDirRelative = Case.getModulesOutputDirRelPath() + File.separator + EmbeddedFileExtractorModuleFactory.getModuleName(); //relative to the case, to store in db - protected static final String moduleDirAbsolute = currentCase.getModulesOutputDirAbsPath() + File.separator + EmbeddedFileExtractorModuleFactory.getModuleName(); //absolute, to extract to + protected static String moduleDirRelative; + protected static String moduleDirAbsolute; private boolean archivextraction; private boolean imageExtraction; @@ -72,6 +67,11 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule this.context = context; jobId = context.getJobId(); + final Case currentCase = Case.getCurrentCase(); + + moduleDirRelative = Case.getModulesOutputDirRelPath() + File.separator + EmbeddedFileExtractorModuleFactory.getModuleName(); //relative to the case, to store in db + moduleDirAbsolute = currentCase.getModulesOutputDirAbsPath() + File.separator + EmbeddedFileExtractorModuleFactory.getModuleName(); //absolute, to extract to + // initialize the folder where the embedded files are extracted. File extractionDirectory = new File(EmbeddedFileExtractorIngestModule.moduleDirAbsolute); if (!extractionDirectory.exists()) { From 5876bdb19bb3c6f12a1abc37ba1db2bbfe65cb9e Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Fri, 12 Jun 2015 12:50:53 -0400 Subject: [PATCH 035/198] module output dir variables non-static --- .../EmbeddedFileExtractorIngestModule.java | 16 ++++++++-------- .../embeddedfileextractor/ImageExtractor.java | 11 ++++++++--- .../SevenZipExtractor.java | 19 ++++++++++++++----- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java index e2e9bd6a62..0f5f4ccd72 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java @@ -49,8 +49,8 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule private long jobId; private final static IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); - protected static String moduleDirRelative; - protected static String moduleDirAbsolute; + String moduleDirRelative; + String moduleDirAbsolute; private boolean archivextraction; private boolean imageExtraction; @@ -73,13 +73,13 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule moduleDirAbsolute = currentCase.getModulesOutputDirAbsPath() + File.separator + EmbeddedFileExtractorModuleFactory.getModuleName(); //absolute, to extract to // initialize the folder where the embedded files are extracted. - File extractionDirectory = new File(EmbeddedFileExtractorIngestModule.moduleDirAbsolute); + File extractionDirectory = new File(moduleDirAbsolute); if (!extractionDirectory.exists()) { try { extractionDirectory.mkdirs(); } catch (SecurityException ex) { - logger.log(Level.SEVERE, "Error initializing output dir: " + EmbeddedFileExtractorIngestModule.moduleDirAbsolute, ex); //NON-NLS - services.postMessage(IngestMessage.createErrorMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), "Error initializing", "Error initializing output dir: " + EmbeddedFileExtractorIngestModule.moduleDirAbsolute)); //NON-NLS + logger.log(Level.SEVERE, "Error initializing output dir: " + moduleDirAbsolute, ex); //NON-NLS + services.postMessage(IngestMessage.createErrorMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), "Error initializing", "Error initializing output dir: " + moduleDirAbsolute)); //NON-NLS throw new IngestModuleException(ex.getMessage()); } } @@ -92,8 +92,8 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule } // initialize the extraction modules. - this.archiveExtractor = new SevenZipExtractor(context, fileTypeDetector); - this.imageExtractor = new ImageExtractor(context, fileTypeDetector); + this.archiveExtractor = new SevenZipExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute); + this.imageExtractor = new ImageExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute); } @Override @@ -167,7 +167,7 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule * @param localRootRelPath relative path to archive, from getUniqueName() * @return */ - protected static String getLocalRootAbsPath(String localRootRelPath) { + String getLocalRootAbsPath(String localRootRelPath) { return moduleDirAbsolute + File.separator + localRootRelPath; } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java index 4b12269490..62b0a5f76a 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java @@ -58,6 +58,9 @@ class ImageExtractor { private String parentFileName; private final String UNKNOWN_NAME_PREFIX = "image_"; private final FileTypeDetector fileTypeDetector; + + String moduleDirRelative; + String moduleDirAbsolute; /** * Enum of mimetypes which support image extraction */ @@ -84,12 +87,14 @@ class ImageExtractor { } private SupportedImageExtractionFormats abstractFileExtractionFormat; - ImageExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector) { + ImageExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute) { this.fileManager = Case.getCurrentCase().getServices().getFileManager(); this.services = IngestServices.getInstance(); this.context = context; this.fileTypeDetector = fileTypeDetector; + this.moduleDirRelative = moduleDirRelative; + this.moduleDirAbsolute = moduleDirAbsolute; } /** @@ -481,7 +486,7 @@ class ImageExtractor { * @return path to the image extraction folder for a given abstract file. */ private String getOutputFolderPath(String parentFileName) { - String outputFolderPath = EmbeddedFileExtractorIngestModule.moduleDirAbsolute + File.separator + parentFileName; + String outputFolderPath = moduleDirAbsolute + File.separator + parentFileName; File outputFilePath = new File(outputFolderPath); if (!outputFilePath.exists()) { try { @@ -504,7 +509,7 @@ class ImageExtractor { */ private String getFileRelativePath(String fileName) { // Used explicit FWD slashes to maintain DB consistency across operating systems. - return "/" + EmbeddedFileExtractorIngestModule.moduleDirRelative + "/" + this.parentFileName + "/" + fileName; //NON-NLS + return "/" + moduleDirRelative + "/" + this.parentFileName + "/" + fileName; //NON-NLS } /** diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index fd17a65d98..7b3e65c1d8 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -79,6 +79,13 @@ class SevenZipExtractor { private static final long MIN_FREE_DISK_SPACE = 1 * 1000 * 1000000L; //1GB //counts archive depth private ArchiveDepthCountTree archiveDepthCountTree; + + String moduleDirRelative; + String moduleDirAbsolute; + + private String getLocalRootAbsPath(String uniqueArchiveFileName) { + return moduleDirAbsolute + File.separator + uniqueArchiveFileName; + } /** * Enum of mimetypes which support archive extraction */ @@ -103,7 +110,7 @@ class SevenZipExtractor { // TODO Expand to support more formats after upgrading Tika } - SevenZipExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector) throws IngestModuleException { + SevenZipExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute) throws IngestModuleException { if (!SevenZip.isInitializedSuccessfully() && (SevenZip.getLastInitializationException() == null)) { try { SevenZip.initSevenZipFromPlatformJAR(); @@ -121,6 +128,8 @@ class SevenZipExtractor { } this.context = context; this.fileTypeDetector = fileTypeDetector; + this.moduleDirRelative = moduleDirRelative; + this.moduleDirAbsolute = moduleDirAbsolute; this.archiveDepthCountTree = new ArchiveDepthCountTree(); } @@ -308,7 +317,7 @@ class SevenZipExtractor { //setup the archive local root folder final String uniqueArchiveFileName = EmbeddedFileExtractorIngestModule.getUniqueName(archiveFile); - final String localRootAbsPath = EmbeddedFileExtractorIngestModule.getLocalRootAbsPath(uniqueArchiveFileName); + final String localRootAbsPath = getLocalRootAbsPath(uniqueArchiveFileName); final File localRoot = new File(localRootAbsPath); if (!localRoot.exists()) { try { @@ -321,7 +330,7 @@ class SevenZipExtractor { } //initialize tree hierarchy to keep track of unpacked file structure - SevenZipExtractor.UnpackedTree unpackedTree = new SevenZipExtractor.UnpackedTree(EmbeddedFileExtractorIngestModule.moduleDirRelative + "/" + uniqueArchiveFileName, archiveFile); + SevenZipExtractor.UnpackedTree unpackedTree = new SevenZipExtractor.UnpackedTree(moduleDirRelative + "/" + uniqueArchiveFileName, archiveFile); long freeDiskSpace = services.getFreeDiskSpace(); @@ -420,8 +429,8 @@ class SevenZipExtractor { final String uniqueExtractedName = uniqueArchiveFileName + File.separator + (item.getItemIndex() / 1000) + File.separator + item.getItemIndex() + new File(pathInArchive).getName(); //final String localRelPath = unpackDir + File.separator + localFileRelPath; - final String localRelPath = EmbeddedFileExtractorIngestModule.moduleDirRelative + File.separator + uniqueExtractedName; - final String localAbsPath = EmbeddedFileExtractorIngestModule.moduleDirAbsolute + File.separator + uniqueExtractedName; + final String localRelPath = moduleDirRelative + File.separator + uniqueExtractedName; + final String localAbsPath = moduleDirAbsolute + File.separator + uniqueExtractedName; //create local dirs and empty files before extracted File localFile = new java.io.File(localAbsPath); From 50394e659ddb91ea69f13960a0cfcd749e694bf4 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Fri, 12 Jun 2015 13:26:19 -0400 Subject: [PATCH 036/198] null check for value returned by fileTypeDetector.getFileType(AbstractFile) --- .../autopsy/modules/exif/ExifParserFileIngestModule.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java index 013247c086..992de4c228 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java @@ -204,7 +204,12 @@ public final class ExifParserFileIngestModule implements FileIngestModule { */ private boolean parsableFormat(AbstractFile f) { try { - return fileTypeDetector.getFileType(f).equals("image/jpeg"); + String mimeType = fileTypeDetector.getFileType(f); + if (mimeType != null) { + return fileTypeDetector.getFileType(f).equals("image/jpeg"); + } else { + return false; + } } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Failed to detect file type", ex); //NON-NLS return false; From ed321d23020c96494378c4959641140c87b9cd8f Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Fri, 12 Jun 2015 15:34:17 -0400 Subject: [PATCH 037/198] null check before comparison with primitive long --- .../modules/embeddedfileextractor/SevenZipExtractor.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 7b3e65c1d8..1da0949508 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -180,16 +180,16 @@ class SevenZipExtractor { */ private boolean isZipBombArchiveItemCheck(String archiveName, ISimpleInArchiveItem archiveFileItem) { try { - final long archiveItemSize = archiveFileItem.getSize(); + final Long archiveItemSize = archiveFileItem.getSize(); //skip the check for small files - if (archiveItemSize < MIN_COMPRESSION_RATIO_SIZE) { + if (archiveItemSize == null || archiveItemSize < MIN_COMPRESSION_RATIO_SIZE) { return false; } - final long archiveItemPackedSize = archiveFileItem.getPackedSize(); + final Long archiveItemPackedSize = archiveFileItem.getPackedSize(); - if (archiveItemPackedSize <= 0) { + if (archiveItemPackedSize == null || archiveItemPackedSize <= 0) { logger.log(Level.WARNING, "Cannot getting compression ratio, cannot detect if zipbomb: {0}, item: {1}", new Object[]{archiveName, archiveFileItem.getPath()}); //NON-NLS return false; } From 754982d05c68577e60ad52f283baf5cff5b8fcc1 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Fri, 12 Jun 2015 15:37:05 -0400 Subject: [PATCH 038/198] catching uncaught OldFileFormatExceptions --- .../embeddedfileextractor/ImageExtractor.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java index 62b0a5f76a..419c438968 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java @@ -25,6 +25,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; +import org.apache.poi.OldFileFormatException; import org.apache.poi.hslf.model.Picture; import org.apache.poi.hslf.usermodel.PictureData; import org.apache.poi.hslf.usermodel.SlideShow; @@ -194,7 +195,7 @@ class ImageExtractor { HWPFDocument doc = null; try { doc = new HWPFDocument(new ReadContentInputStream(af)); - } catch (IOException ex) { + } catch (IOException | OldFileFormatException ex) { logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName()), ex); //NON-NLS return null; } @@ -232,7 +233,7 @@ class ImageExtractor { XWPFDocument docx = null; try { docx = new XWPFDocument(new ReadContentInputStream(af)); - } catch (IOException ex) { + } catch (IOException | OldFileFormatException ex) { logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docxContainer.init.err", af.getName()), ex); //NON-NLS return null; } @@ -271,7 +272,7 @@ class ImageExtractor { SlideShow ppt = null; try { ppt = new SlideShow(new ReadContentInputStream(af)); - } catch (IOException ex) { + } catch (IOException | OldFileFormatException ex) { logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName()), ex); //NON-NLS return null; } @@ -341,7 +342,7 @@ class ImageExtractor { XMLSlideShow pptx; try { pptx = new XMLSlideShow(new ReadContentInputStream(af)); - } catch (IOException ex) { + } catch (IOException | OldFileFormatException ex) { logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptxContainer.init.err", af.getName()), ex); //NON-NLS return null; } @@ -388,7 +389,7 @@ class ImageExtractor { Workbook xls; try { xls = new HSSFWorkbook(new ReadContentInputStream(af)); - } catch (IOException ex) { + } catch (IOException | OldFileFormatException ex) { logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err", af.getName()) + af.getName(), ex); //NON-NLS return null; } @@ -431,7 +432,7 @@ class ImageExtractor { Workbook xlsx; try { xlsx = new XSSFWorkbook(new ReadContentInputStream(af)); - } catch (IOException ex) { + } catch (IOException | OldFileFormatException ex) { logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsxContainer.init.err", af.getName()), ex); //NON-NLS return null; } From aeb05bf3cd816873bf163f7c0d2210cba9882064 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Mon, 15 Jun 2015 12:31:08 -0400 Subject: [PATCH 039/198] jump to hex offset implemented --- .../autopsy/corecomponents/Bundle.properties | 4 + .../corecomponents/Bundle_ja.properties | 219 +++++++++--------- .../corecomponents/DataContentViewerHex.form | 31 ++- .../corecomponents/DataContentViewerHex.java | 131 +++++++++-- 4 files changed, 255 insertions(+), 130 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index fce437a96f..2365f7440c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -147,3 +147,7 @@ AutopsyOptionsPanel.jLabelNumThreads.text=Number of threads to use for file inge FXVideoPanel.progress.bufferingCancelled=media buffering was canceled FXVideoPanel.progress.bufferingInterrupted=media buffering was interrupted FXVideoPanel.progress.errorWritingVideoToDisk=Error writing video to disk +DataContentViewerHex.goToPageLabel1.text=Jump to Offset +DataContentViewerHex.goToOffsetLabel.text=Jump to Offset +DataContentViewerHex.goToOffsetTextField.text= +DataContentViewerHex.goToOffsetTextField.msgDlg=Invalid Offset: {0} diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties index db6e5b5ecc..d31943019a 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties @@ -1,128 +1,129 @@ -CTL_DataContentAction=\u30C7\u30FC\u30BF\u30B3\u30F3\u30C6\u30F3\u30C4 +CTL_DataContentAction=\u30c7\u30fc\u30bf\u30b3\u30f3\u30c6\u30f3\u30c4 OptionsCategory_Name_General=Autopsy -OptionsCategory_Keywords_General=Autopsy\u30AA\u30D7\u30B7\u30E7\u30F3 -CTL_CustomAboutAction=Autopsy\u306B\u3064\u3044\u3066 -CTL_DataContentTopComponent=\u30C7\u30FC\u30BF\u30B3\u30F3\u30C6\u30F3\u30C4 -HINT_DataContentTopComponent=\u3053\u308C\u306F\u30C7\u30FC\u30BF\u30B3\u30F3\u30C6\u30F3\u30C4\u306E\u30A6\u30A3\u30F3\u30C9\u30A6\u3067\u3059 -HINT_NodeTableTopComponent=\u3053\u308C\u306F\u30C7\u30FC\u30BF\u7D50\u679C\u306E\u30A6\u30A3\u30F3\u30C9\u30A6\u3067\u3059 -OpenIDE-Module-Name=\u4E3B\u8981\u30B3\u30F3\u30DD\u30FC\u30CD\u30F3\u30C8 -DataContentViewerHex.pageLabel.text_1=\u30DA\u30FC\u30B8\uFF1A +OptionsCategory_Keywords_General=Autopsy\u30aa\u30d7\u30b7\u30e7\u30f3 +CTL_CustomAboutAction=Autopsy\u306b\u3064\u3044\u3066 +CTL_DataContentTopComponent=\u30c7\u30fc\u30bf\u30b3\u30f3\u30c6\u30f3\u30c4 +HINT_DataContentTopComponent=\u3053\u308c\u306f\u30c7\u30fc\u30bf\u30b3\u30f3\u30c6\u30f3\u30c4\u306e\u30a6\u30a3\u30f3\u30c9\u30a6\u3067\u3059 +HINT_NodeTableTopComponent=\u3053\u308c\u306f\u30c7\u30fc\u30bf\u7d50\u679c\u306e\u30a6\u30a3\u30f3\u30c9\u30a6\u3067\u3059 +OpenIDE-Module-Name=\u4e3b\u8981\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8 +DataContentViewerHex.pageLabel.text_1=\u30da\u30fc\u30b8\uff1a DataContentViewerHex.currentPageLabel.text_1=1 DataContentViewerHex.totalPageLabel.text_1=100 -DataContentViewerString.pageLabel.text_1=\u30DA\u30FC\u30B8\uFF1A +DataContentViewerString.pageLabel.text_1=\u30da\u30fc\u30b8\uff1a DataContentViewerString.currentPageLabel.text_1=1 DataContentViewerString.totalPageLabel.text_1=100 -DataContentViewerHex.pageLabel2.text=\u30DA\u30FC\u30B8 -DataContentViewerString.pageLabel2.text=\u30DA\u30FC\u30B8 -Format_OperatingSystem_Value={0} \u30D0\u30FC\u30B8\u30E7\u30F3 {1} \u30A2\u30FC\u30AD\u30C6\u30AF\u30C1\u30E3 {2} +DataContentViewerHex.pageLabel2.text=\u30da\u30fc\u30b8 +DataContentViewerString.pageLabel2.text=\u30da\u30fc\u30b8 +Format_OperatingSystem_Value={0} \u30d0\u30fc\u30b8\u30e7\u30f3 {1} \u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3 {2} URL_ON_IMG=http\://www.sleuthkit.org/ -LBL_Close=\u9589\u3058\u308B -DataContentViewerString.copyMenuItem.text=\u30B3\u30D4\u30FC -DataContentViewerHex.copyMenuItem.text=\u30B3\u30D4\u30FC -DataContentViewerString.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629E -DataContentViewerHex.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629E +LBL_Close=\u9589\u3058\u308b +DataContentViewerString.copyMenuItem.text=\u30b3\u30d4\u30fc +DataContentViewerHex.copyMenuItem.text=\u30b3\u30d4\u30fc +DataContentViewerString.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629e +DataContentViewerHex.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629e DataContentViewerArtifact.totalPageLabel.text=100 -DataContentViewerArtifact.pageLabel2.text=\u7D50\u679C +DataContentViewerArtifact.pageLabel2.text=\u7d50\u679c DataContentViewerArtifact.currentPageLabel.text=1 -DataContentViewerArtifact.copyMenuItem.text=\u30B3\u30D4\u30FC -DataContentViewerArtifact.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629E -DataContentViewerArtifact.pageLabel.text=\u7D50\u679C\uFF1A +DataContentViewerArtifact.copyMenuItem.text=\u30b3\u30d4\u30fc +DataContentViewerArtifact.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629e +DataContentViewerArtifact.pageLabel.text=\u7d50\u679c\uff1a AdvancedConfigurationDialog.applyButton.text=OK -DataContentViewerString.goToPageLabel.text=\u4E0B\u8A18\u306E\u30DA\u30FC\u30B8\u3078\u79FB\u52D5\uFF1A -DataContentViewerHex.goToPageLabel.text=\u4E0B\u8A18\u306E\u30DA\u30FC\u30B8\u3078\u79FB\u52D5\uFF1A -DataContentViewerString.languageLabel.text=\u30B9\u30AF\u30EA\u30D7\u30C8\uFF1A -DataContentViewerString.languageCombo.toolTipText=\u30D0\u30A4\u30CA\u30EA\u30B9\u30C8\u30EA\u30F3\u30B0\u306E\u51E6\u7406\uFF08\u62BD\u51FA\u304A\u3088\u3073\u30C7\u30B3\u30FC\u30C9\uFF09\u306B\u4F7F\u7528\u3059\u308B\u8A00\u8A9E -DataResultViewerThumbnail.pageLabel.text=\u30DA\u30FC\u30B8\uFF1A -DataResultViewerThumbnail.pagesLabel.text=\u30DA\u30FC\u30B8\uFF1A -DataResultViewerThumbnail.imagesLabel.text=\u30A4\u30E1\u30FC\u30B8\uFF1A +DataContentViewerString.goToPageLabel.text=\u4e0b\u8a18\u306e\u30da\u30fc\u30b8\u3078\u79fb\u52d5\uff1a +DataContentViewerHex.goToPageLabel.text=\u4e0b\u8a18\u306e\u30da\u30fc\u30b8\u3078\u79fb\u52d5\uff1a +DataContentViewerString.languageLabel.text=\u30b9\u30af\u30ea\u30d7\u30c8\uff1a +DataContentViewerString.languageCombo.toolTipText=\u30d0\u30a4\u30ca\u30ea\u30b9\u30c8\u30ea\u30f3\u30b0\u306e\u51e6\u7406\uff08\u62bd\u51fa\u304a\u3088\u3073\u30c7\u30b3\u30fc\u30c9\uff09\u306b\u4f7f\u7528\u3059\u308b\u8a00\u8a9e +DataResultViewerThumbnail.pageLabel.text=\u30da\u30fc\u30b8\uff1a +DataResultViewerThumbnail.pagesLabel.text=\u30da\u30fc\u30b8\uff1a +DataResultViewerThumbnail.imagesLabel.text=\u30a4\u30e1\u30fc\u30b8\uff1a DataResultViewerThumbnail.imagesRangeLabel.text=- DataResultViewerThumbnail.pageNumLabel.text=- -DataResultViewerThumbnail.goToPageLabel.text=\u4E0B\u8A18\u306E\u30DA\u30FC\u30B8\u306B\u79FB\u52D5\uFF1A -AdvancedConfigurationDialog.cancelButton.text=\u30AD\u30E3\u30F3\u30BB\u30EB -DataResultPanel.directoryTablePath.text=\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u30D1\u30B9 +DataResultViewerThumbnail.goToPageLabel.text=\u4e0b\u8a18\u306e\u30da\u30fc\u30b8\u306b\u79fb\u52d5\uff1a +AdvancedConfigurationDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb +DataResultPanel.directoryTablePath.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30d1\u30b9 DataResultPanel.numberMatchLabel.text=0 -DataResultPanel.matchLabel.text=\u7D50\u679C -MediaViewVideoPanel.pauseButton.text=\u25BA +DataResultPanel.matchLabel.text=\u7d50\u679c +MediaViewVideoPanel.pauseButton.text=\u25ba MediaViewVideoPanel.progressLabel.text=00\:00 -MediaViewVideoPanel.infoLabel.text=\u60C5\u5831 -DataContentViewerArtifact.waitText=\u30C7\u30FC\u30BF\u3092\u53D6\u8FBC\u307F\u304A\u3088\u3073\u6E96\u5099\u4E2D\u3002\u3057\u3070\u3089\u304F\u304A\u5F85\u3061\u4E0B\u3055\u3044\u2026 -DataContentViewerArtifact.errorText=\u7D50\u679C\u306E\u53D6\u8FBC\u307F\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F -DataContentViewerArtifact.title=\u7D50\u679C -DataContentViewerArtifact.toolTip=\u30D5\u30A1\u30A4\u30EB\u306B\u95A2\u9023\u3059\u308B\u7D50\u679C\u3092\u8868\u793A\u3057\u307E\u3059 -DataContentViewerHex.goToPageTextField.msgDlg=\uFF11\u304B\u3089 {0}\u306E\u9593\u306E\u6709\u52B9\u306A\u30DA\u30FC\u30B8\u6570\u3092\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044 -DataContentViewerHex.goToPageTextField.err=\u7121\u52B9\u306A\u30DA\u30FC\u30B8\u6570 -DataContentViewerHex.setDataView.errorText=\uFF08\u30AA\u30D5\u30BB\u30C3\u30C8{0}-{1}\u306F\u8AAD\u307F\u53D6\u308C\u307E\u305B\u3093\u3067\u3057\u305F\uFF09 +MediaViewVideoPanel.infoLabel.text=\u60c5\u5831 +DataContentViewerArtifact.waitText=\u30c7\u30fc\u30bf\u3092\u53d6\u8fbc\u307f\u304a\u3088\u3073\u6e96\u5099\u4e2d\u3002\u3057\u3070\u3089\u304f\u304a\u5f85\u3061\u4e0b\u3055\u3044\u2026 +DataContentViewerArtifact.errorText=\u7d50\u679c\u306e\u53d6\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +DataContentViewerArtifact.title=\u7d50\u679c +DataContentViewerArtifact.toolTip=\u30d5\u30a1\u30a4\u30eb\u306b\u95a2\u9023\u3059\u308b\u7d50\u679c\u3092\u8868\u793a\u3057\u307e\u3059 +DataContentViewerHex.goToPageTextField.msgDlg=\uff11\u304b\u3089 {0}\u306e\u9593\u306e\u6709\u52b9\u306a\u30da\u30fc\u30b8\u6570\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044 +DataContentViewerHex.goToPageTextField.err=\u7121\u52b9\u306a\u30da\u30fc\u30b8\u6570 +DataContentViewerHex.setDataView.errorText=\uff08\u30aa\u30d5\u30bb\u30c3\u30c8{0}-{1}\u306f\u8aad\u307f\u53d6\u308c\u307e\u305b\u3093\u3067\u3057\u305f\uff09 DataContentViewerHex.title=HEX -DataContentViewerHex.toolTip=\u30D0\u30A4\u30CA\u30EA\u30B3\u30F3\u30C6\u30F3\u30C4\u3092HEX\u30D5\u30A1\u30A4\u30EB\u3068\u3057\u3066\u8868\u793A\u3057\u3001ASCII\u3068\u3057\u3066\u8868\u793A\u3067\u304D\u308B\u30D0\u30A4\u30C8\u306F\u53F3\u5074\u306B\u8868\u793A\u3057\u307E\u3059\u3002 -DataContentViewerMedia.title=\u30E1\u30C7\u30A3\u30A2 -DataContentViewerMedia.toolTip=\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u308B\u30DE\u30EB\u30C1\u30E1\u30C7\u30A3\u30A2\u30D5\u30A1\u30A4\u30EB\uFF08\u30A4\u30E1\u30FC\u30B8\u3001\u30D3\u30C7\u30AA\u3001\u30AA\u30FC\u30C7\u30A3\u30AA\uFF09\u3092\u8868\u793A\u3057\u307E\u3059\u3002 -DataContentViewerString.goToPageTextField.msgDlg=\uFF11\u304B\u3089{0}\u306E\u9593\u306E\u6709\u52B9\u306A\u30DA\u30FC\u30B8\u6570\u3092\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044 -DataContentViewerString.goToPageTextField.err=\u7121\u52B9\u306A\u30DA\u30FC\u30B8\u6570 -DataContentViewerString.setDataView.errorText=\uFF08\u30AA\u30D5\u30BB\u30C3\u30C8{0}-{1}\u306F\u8AAD\u307F\u53D6\u308C\u307E\u305B\u3093\u3067\u3057\u305F\uFF09 -DataContentViewerString.title=\u30B9\u30C8\u30EA\u30F3\u30B0 -DataContentViewerString.toolTip=\u30D5\u30A1\u30A4\u30EB\u304B\u3089\u62BD\u51FA\u3055\u308C\u305FASCII\u304A\u3088\u3073\u30E6\u30CB\u30B3\u30FC\u30C9\u306E\u30B9\u30C8\u30EA\u30F3\u30B0\u304C\u8868\u793A\u3055\u308C\u307E\u3059\u3002 -DataResultPanel.dummyNodeDisplayName=\u3057\u3070\u3089\u304F\u304A\u5F85\u3061\u304F\u3060\u3055\u3044\u2026 -DataResultViewerTable.firstColLbl=\u540D\u524D -DataResultViewerTable.illegalArgExc.noChildFromParent=\u6307\u5B9A\u3055\u308C\u305F\u30DA\u30A2\u30EC\u30F3\u30C8\u304B\u3089\u30C1\u30E3\u30A4\u30EB\u30C9\u30CE\u30FC\u30C9\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -DataResultViewerTable.illegalArgExc.childWithoutPropertySet=\u30C1\u30E3\u30A4\u30EB\u30C9\u30CE\u30FC\u30C9\u306F\u901A\u5E38\u306EPropertySet\u3092\u6301\u3063\u3066\u3044\u307E\u305B\u3093\u3002 -DataResultViewerTable.title=\u30C6\u30FC\u30D6\u30EB -DataResultViewerTable.dummyNodeDisplayName=\u3057\u3070\u3089\u304F\u304A\u5F85\u3061\u304F\u3060\u3055\u3044\u2026 -DataResultViewerThumbnail.title=\u30B5\u30E0\u30CD\u30A4\u30EB -DataResultViewerThumbnail.goToPageTextField.msgDlg=\uFF11\u304B\u3089{0}\u306E\u9593\u306E\u6709\u52B9\u306A\u30DA\u30FC\u30B8\u6570\u3092\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044 -DataResultViewerThumbnail.goToPageTextField.err=\u7121\u52B9\u306A\u30DA\u30FC\u30B8\u6570 -DataResultViewerThumbnail.genThumbs=\u30B5\u30E0\u30CD\u30A4\u30EB\u3092\u4F5C\u6210\u4E2D\u2026 -DataResultViewerThumbnail.pageNumbers.curOfTotal={0}\uFF0F{1}\u76EE -FXVideoPanel.mediaPane.infoLabel=\u524A\u9664\u3055\u308C\u305F\u30D3\u30C7\u30AA\u306E\u518D\u751F\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002\u5916\u90E8\u30D7\u30EC\u30FC\u30E4\u30FC\u3092\u4F7F\u7528\u3057\u3066\u4E0B\u3055\u3044\u3002 -FXVideoPanel.progress.bufferingFile={0}\u3092\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0 -FXVideoPanel.progressLabel.buffering=\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0\u4E2D\u2026 -FXVideoPanel.media.unsupportedFormat=\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u306A\u3044\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u3067\u3059\u3002 -GeneralOptionsPanelController.moduleErr=\u30E2\u30B8\u30E5\u30FC\u30EB\u30A8\u30E9\u30FC -GeneralOptionsPanelController.moduleErr.msg=GeneralOptionsPanelController\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u3092\u78BA\u8A8D\u4E2D\u306B\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u30A8\u30E9\u30FC\u3092\u8D77\u3053\u3057\u307E\u3057\u305F\u3002\u3069\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u304B\u30ED\u30B0\u3067\u78BA\u8A8D\u3057\u3066\u4E0B\u3055\u3044\u3002\u4E00\u90E8\u306E\u30C7\u30FC\u30BF\u304C\u4E0D\u5B8C\u5168\u304B\u3082\u3057\u308C\u307E\u305B\u3093\u3002 -GstVideoPanel.cannotProcFile.err=\u30E1\u30C7\u30A4\u30A2\u30D7\u30EC\u30FC\u30E4\u30FC\u304C\u3053\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u51E6\u7406\u3067\u304D\u307E\u305B\u3093\u3002 -GstVideoPanel.initGst.gstException.msg=\u30AA\u30FC\u30C7\u30A3\u30AA\uFF0F\u30D3\u30C7\u30AA\u306E\u518D\u751F\u304A\u3088\u3073\u30D5\u30EC\u30FC\u30E0\u306E\u62BD\u51FA\u306B\u4F7F\u7528\u3059\u308BGStreamer\u306E\u521D\u671F\u5316\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u30D3\u30C7\u30AA\u304A\u3088\u3073\u30AA\u30FC\u30C7\u30A3\u30AA\u518D\u751F\u304C\u7121\u52B9\u5316\u3055\u308C\u307E\u3059\u3002 -GstVideoPanel.initGst.otherException.msg=\u30AA\u30FC\u30C7\u30A3\u30AA\uFF0F\u30D3\u30C7\u30AA\u306E\u518D\u751F\u304A\u3088\u3073\u30D5\u30EC\u30FC\u30E0\u306E\u62BD\u51FA\u306B\u4F7F\u7528\u3059\u308BGStreamer\u306E\u521D\u671F\u5316\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u30D3\u30C7\u30AA\u304A\u3088\u3073\u30AA\u30FC\u30C7\u30A3\u30AA\u518D\u751F\u304C\u7121\u52B9\u5316\u3055\u308C\u307E\u3059\u3002 -GstVideoPanel.setupVideo.infoLabel.text=\u524A\u9664\u3055\u308C\u305F\u30D3\u30C7\u30AA\u306E\u518D\u751F\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002\u5916\u90E8\u30D7\u30EC\u30FC\u30E4\u30FC\u3092\u4F7F\u7528\u3057\u3066\u4E0B\u3055\u3044\u3002 -GstVideoPanel.exception.problemFile.msg=\u30D5\u30A1\u30A4\u30EB({0})\u304B\u3089\u306F\u30D5\u30EC\u30FC\u30E0\u3092\u62BD\u51FA\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -GstVideoPanel.exception.problemPlay.msg=\u30D3\u30C7\u30AA\u30D5\u30A1\u30A4\u30EB\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u9577\u3055\u3092\u78BA\u8A8D\u4E2D\u306B\u518D\u751F\u3092\u3057\u3088\u3046\u3068\u3057\u305F\u969B\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 -LBL_Description=
\n \u88FD\u54C1\u30D0\u30FC\u30B8\u30E7\u30F3\uFF1A {0} ({9})
Sleuth Kit\u30D0\u30FC\u30B8\u30E7\u30F3\uFF1A {7}
Netbeans RCP\u30D3\u30EB\u30C9\: {8}
Java\: {1}; {2}
\u30B7\u30B9\u30C6\u30E0\uFF1A {3}; {4}; {5}
\u30E6\u30FC\u30B6\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u540D {6}
-LBL_Copyright=
-GstVideoPanel.exception.problemPause.msg=\u30D3\u30C7\u30AA\u30D5\u30A1\u30A4\u30EB\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u9577\u3055\u3092\u78BA\u8A8D\u4E2D\u306B\u4E00\u6642\u505C\u6B62\u3092\u3057\u3088\u3046\u3068\u3057\u305F\u969B\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 -GstVideoPanel.exception.problemPauseCaptFrame.msg=\u30D3\u30C7\u30AA\u30D5\u30A1\u30A4\u30EB\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u30D5\u30EC\u30FC\u30E0\u306E\u62BD\u51FA\u4E2D\u306B\u4E00\u6642\u505C\u6B62\u3092\u3057\u3088\u3046\u3068\u3057\u305F\u969B\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 -GstVideoPanel.exception.problemPlayCaptFrame.msg=\u30D3\u30C7\u30AA\u30D5\u30A1\u30A4\u30EB\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u30D5\u30EC\u30FC\u30E0\u306E\u62BD\u51FA\u4E2D\u306B\u518D\u751F\u3057\u3088\u3046\u3068\u3057\u305F\u969B\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 -GstVideoPanel.exception.problemStopCaptFrame.msg=\u30D3\u30C7\u30AA\u30D5\u30A1\u30A4\u30EB\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u30D5\u30EC\u30FC\u30E0\u306E\u62BD\u51FA\u4E2D\u306B\u505C\u6B62\u3057\u3088\u3046\u3068\u3057\u305F\u969B\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 -GstVideoPanel.progress.buffering=\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0\u4E2D\u2026 -GstVideoPanel.progressLabel.bufferingErr=\u30D5\u30A1\u30A4\u30EB\u306E\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0\u30A8\u30E9\u30FC -MediaViewImagePanel.imgFileTooLarge.msg=\u30A4\u30E1\u30FC\u30B8\u30D5\u30A1\u30A4\u30EB\u3092\u8AAD\u307F\u8FBC\u3081\u307E\u305B\u3093\u3067\u3057\u305F\uFF08\u5927\u304D\u3059\u304E\u3067\u3059\uFF09\uFF1A {0} -ProductInformationPanel.verbLoggingEnabled.text=Verbose\u30ED\u30B0\u304C\u6709\u52B9\u3067\u3059 -ProductInformationPanel.propertyUnknown.text=\u4E0D\u660E +DataContentViewerHex.toolTip=\u30d0\u30a4\u30ca\u30ea\u30b3\u30f3\u30c6\u30f3\u30c4\u3092HEX\u30d5\u30a1\u30a4\u30eb\u3068\u3057\u3066\u8868\u793a\u3057\u3001ASCII\u3068\u3057\u3066\u8868\u793a\u3067\u304d\u308b\u30d0\u30a4\u30c8\u306f\u53f3\u5074\u306b\u8868\u793a\u3057\u307e\u3059\u3002 +DataContentViewerMedia.title=\u30e1\u30c7\u30a3\u30a2 +DataContentViewerMedia.toolTip=\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u308b\u30de\u30eb\u30c1\u30e1\u30c7\u30a3\u30a2\u30d5\u30a1\u30a4\u30eb\uff08\u30a4\u30e1\u30fc\u30b8\u3001\u30d3\u30c7\u30aa\u3001\u30aa\u30fc\u30c7\u30a3\u30aa\uff09\u3092\u8868\u793a\u3057\u307e\u3059\u3002 +DataContentViewerString.goToPageTextField.msgDlg=\uff11\u304b\u3089{0}\u306e\u9593\u306e\u6709\u52b9\u306a\u30da\u30fc\u30b8\u6570\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044 +DataContentViewerString.goToPageTextField.err=\u7121\u52b9\u306a\u30da\u30fc\u30b8\u6570 +DataContentViewerString.setDataView.errorText=\uff08\u30aa\u30d5\u30bb\u30c3\u30c8{0}-{1}\u306f\u8aad\u307f\u53d6\u308c\u307e\u305b\u3093\u3067\u3057\u305f\uff09 +DataContentViewerString.title=\u30b9\u30c8\u30ea\u30f3\u30b0 +DataContentViewerString.toolTip=\u30d5\u30a1\u30a4\u30eb\u304b\u3089\u62bd\u51fa\u3055\u308c\u305fASCII\u304a\u3088\u3073\u30e6\u30cb\u30b3\u30fc\u30c9\u306e\u30b9\u30c8\u30ea\u30f3\u30b0\u304c\u8868\u793a\u3055\u308c\u307e\u3059\u3002 +DataResultPanel.dummyNodeDisplayName=\u3057\u3070\u3089\u304f\u304a\u5f85\u3061\u304f\u3060\u3055\u3044\u2026 +DataResultViewerTable.firstColLbl=\u540d\u524d +DataResultViewerTable.illegalArgExc.noChildFromParent=\u6307\u5b9a\u3055\u308c\u305f\u30da\u30a2\u30ec\u30f3\u30c8\u304b\u3089\u30c1\u30e3\u30a4\u30eb\u30c9\u30ce\u30fc\u30c9\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 +DataResultViewerTable.illegalArgExc.childWithoutPropertySet=\u30c1\u30e3\u30a4\u30eb\u30c9\u30ce\u30fc\u30c9\u306f\u901a\u5e38\u306ePropertySet\u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093\u3002 +DataResultViewerTable.title=\u30c6\u30fc\u30d6\u30eb +DataResultViewerTable.dummyNodeDisplayName=\u3057\u3070\u3089\u304f\u304a\u5f85\u3061\u304f\u3060\u3055\u3044\u2026 +DataResultViewerThumbnail.title=\u30b5\u30e0\u30cd\u30a4\u30eb +DataResultViewerThumbnail.goToPageTextField.msgDlg=\uff11\u304b\u3089{0}\u306e\u9593\u306e\u6709\u52b9\u306a\u30da\u30fc\u30b8\u6570\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044 +DataResultViewerThumbnail.goToPageTextField.err=\u7121\u52b9\u306a\u30da\u30fc\u30b8\u6570 +DataResultViewerThumbnail.genThumbs=\u30b5\u30e0\u30cd\u30a4\u30eb\u3092\u4f5c\u6210\u4e2d\u2026 +DataResultViewerThumbnail.pageNumbers.curOfTotal={0}\uff0f{1}\u76ee +FXVideoPanel.mediaPane.infoLabel=\u524a\u9664\u3055\u308c\u305f\u30d3\u30c7\u30aa\u306e\u518d\u751f\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u5916\u90e8\u30d7\u30ec\u30fc\u30e4\u30fc\u3092\u4f7f\u7528\u3057\u3066\u4e0b\u3055\u3044\u3002 +FXVideoPanel.progress.bufferingFile={0}\u3092\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0 +FXVideoPanel.progressLabel.buffering=\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u4e2d\u2026 +FXVideoPanel.media.unsupportedFormat=\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u306a\u3044\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u3067\u3059\u3002 +GeneralOptionsPanelController.moduleErr=\u30e2\u30b8\u30e5\u30fc\u30eb\u30a8\u30e9\u30fc +GeneralOptionsPanelController.moduleErr.msg=GeneralOptionsPanelController\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3092\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304b\u30ed\u30b0\u3067\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u4e0d\u5b8c\u5168\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 +GstVideoPanel.cannotProcFile.err=\u30e1\u30c7\u30a4\u30a2\u30d7\u30ec\u30fc\u30e4\u30fc\u304c\u3053\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u51e6\u7406\u3067\u304d\u307e\u305b\u3093\u3002 +GstVideoPanel.initGst.gstException.msg=\u30aa\u30fc\u30c7\u30a3\u30aa\uff0f\u30d3\u30c7\u30aa\u306e\u518d\u751f\u304a\u3088\u3073\u30d5\u30ec\u30fc\u30e0\u306e\u62bd\u51fa\u306b\u4f7f\u7528\u3059\u308bGStreamer\u306e\u521d\u671f\u5316\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30d3\u30c7\u30aa\u304a\u3088\u3073\u30aa\u30fc\u30c7\u30a3\u30aa\u518d\u751f\u304c\u7121\u52b9\u5316\u3055\u308c\u307e\u3059\u3002 +GstVideoPanel.initGst.otherException.msg=\u30aa\u30fc\u30c7\u30a3\u30aa\uff0f\u30d3\u30c7\u30aa\u306e\u518d\u751f\u304a\u3088\u3073\u30d5\u30ec\u30fc\u30e0\u306e\u62bd\u51fa\u306b\u4f7f\u7528\u3059\u308bGStreamer\u306e\u521d\u671f\u5316\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30d3\u30c7\u30aa\u304a\u3088\u3073\u30aa\u30fc\u30c7\u30a3\u30aa\u518d\u751f\u304c\u7121\u52b9\u5316\u3055\u308c\u307e\u3059\u3002 +GstVideoPanel.setupVideo.infoLabel.text=\u524a\u9664\u3055\u308c\u305f\u30d3\u30c7\u30aa\u306e\u518d\u751f\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u5916\u90e8\u30d7\u30ec\u30fc\u30e4\u30fc\u3092\u4f7f\u7528\u3057\u3066\u4e0b\u3055\u3044\u3002 +GstVideoPanel.exception.problemFile.msg=\u30d5\u30a1\u30a4\u30eb({0})\u304b\u3089\u306f\u30d5\u30ec\u30fc\u30e0\u3092\u62bd\u51fa\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 +GstVideoPanel.exception.problemPlay.msg=\u30d3\u30c7\u30aa\u30d5\u30a1\u30a4\u30eb\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u9577\u3055\u3092\u78ba\u8a8d\u4e2d\u306b\u518d\u751f\u3092\u3057\u3088\u3046\u3068\u3057\u305f\u969b\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +LBL_Description=
\n \u88fd\u54c1\u30d0\u30fc\u30b8\u30e7\u30f3\uff1a {0} ({9})
Sleuth Kit\u30d0\u30fc\u30b8\u30e7\u30f3\uff1a {7}
Netbeans RCP\u30d3\u30eb\u30c9\: {8}
Java\: {1}; {2}
\u30b7\u30b9\u30c6\u30e0\uff1a {3}; {4}; {5}
\u30e6\u30fc\u30b6\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u540d {6}
+LBL_Copyright=
Autopsy™\u306fSleuth Kit™\u3084\u305d\u306e\u4ed6\u30c4\u30fc\u30eb\u3092\u57fa\u306b\u3057\u305f\u30c7\u30b8\u30bf\u30eb\u30fb\u30d5\u30a9\u30ec\u30f3\u30b8\u30c3\u30af\u30fb\u30d7\u30e9\u30c3\u30c8\u30d5\u30a9\u30fc\u30e0\u3067\u3059\u3002

Copyright © 2003-2013. \u8a73\u7d30\u306f\u4e0b\u8a18\u3092\u3054\u89a7\u4e0b\u3055\u3044\u3002 http\://www.sleuthkit.org.
+GstVideoPanel.exception.problemPause.msg=\u30d3\u30c7\u30aa\u30d5\u30a1\u30a4\u30eb\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u9577\u3055\u3092\u78ba\u8a8d\u4e2d\u306b\u4e00\u6642\u505c\u6b62\u3092\u3057\u3088\u3046\u3068\u3057\u305f\u969b\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +GstVideoPanel.exception.problemPauseCaptFrame.msg=\u30d3\u30c7\u30aa\u30d5\u30a1\u30a4\u30eb\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30d5\u30ec\u30fc\u30e0\u306e\u62bd\u51fa\u4e2d\u306b\u4e00\u6642\u505c\u6b62\u3092\u3057\u3088\u3046\u3068\u3057\u305f\u969b\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +GstVideoPanel.exception.problemPlayCaptFrame.msg=\u30d3\u30c7\u30aa\u30d5\u30a1\u30a4\u30eb\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30d5\u30ec\u30fc\u30e0\u306e\u62bd\u51fa\u4e2d\u306b\u518d\u751f\u3057\u3088\u3046\u3068\u3057\u305f\u969b\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +GstVideoPanel.exception.problemStopCaptFrame.msg=\u30d3\u30c7\u30aa\u30d5\u30a1\u30a4\u30eb\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30d5\u30ec\u30fc\u30e0\u306e\u62bd\u51fa\u4e2d\u306b\u505c\u6b62\u3057\u3088\u3046\u3068\u3057\u305f\u969b\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +GstVideoPanel.progress.buffering=\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u4e2d\u2026 +GstVideoPanel.progressLabel.bufferingErr=\u30d5\u30a1\u30a4\u30eb\u306e\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u30a8\u30e9\u30fc +MediaViewImagePanel.imgFileTooLarge.msg=\u30a4\u30e1\u30fc\u30b8\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u3081\u307e\u305b\u3093\u3067\u3057\u305f\uff08\u5927\u304d\u3059\u304e\u3067\u3059\uff09\uff1a {0} +ProductInformationPanel.verbLoggingEnabled.text=Verbose\u30ed\u30b0\u304c\u6709\u52b9\u3067\u3059 +ProductInformationPanel.propertyUnknown.text=\u4e0d\u660e ProductInformationPanel.getVMValue.text={0} {1} -TableFilterNode.displayName.text=\u540D\u524D +TableFilterNode.displayName.text=\u540d\u524d DataContentViewerHex.ofLabel.text_1=of DataContentViewerString.ofLabel.text_1=of DataContentViewerArtifact.ofLabel.text=of -DataContentViewerString.setDataView.errorNoText=\uFF08\u30AA\u30D5\u30BB\u30C3\u30C8{0}-{1}\u306B\u306F\u30C6\u30AD\u30B9\u30C8\u304C\u3042\u308A\u307E\u305B\u3093\uFF09 -DataResultViewerThumbnail.comboBox.smallThumbnails=\u30B5\u30E0\u30CD\u30A4\u30EB\uFF08\u5C0F\uFF09 -DataResultViewerThumbnail.comboBox.mediumThumbnails=\u30B5\u30E0\u30CD\u30A4\u30EB\uFF08\u4E2D\uFF09 -DataResultViewerThumbnail.comboBox.largeThumbnails=\u30B5\u30E0\u30CD\u30A4\u30EB\uFF08\u5927\uFF09 -DataResultViewerThumbnail.switchPage.done.errMsg=\u30B5\u30E0\u30CD\u30A4\u30EB\u4F5C\u6210\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\uFF1A {0} -FXVideoPanel.pauseButton.infoLabel.playbackErr=\u30D3\u30C7\u30AA\u3092\u518D\u751F\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -GstVideoPanel.progress.infoLabel.updateErr=\u30D3\u30C7\u30AA\u30D7\u30ED\u30B0\u30EC\u30B9\u306E\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\uFF1A {0} -GstVideoPanel.ExtractMedia.progress.buffering={0}\u3092\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0\u4E2D -AboutWindowPanel.actVerboseLogging.text=Verbose\u30ED\u30B0\u3092\u30A2\u30AF\u30C6\u30A3\u30D9\u30FC\u30C8 -AutopsyOptionsPanel.viewsHideKnownCB.text=\u30D3\u30E5\u30FC\u30A8\u30EA\u30A2 -AutopsyOptionsPanel.dataSourcesHideKnownCB.text=\u30C7\u30FC\u30BF\u30BD\u30FC\u30B9\u30A8\u30EA\u30A2\uFF08\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u968E\u5C64\uFF09 -AutopsyOptionsPanel.useBestViewerRB.toolTipText=\u4F8B\u3048\u3070\u3001JPEG\u304C\u9078\u629E\u3055\u308C\u305F\u5834\u5408\u306B\u306FHEX\u304B\u3089\u30E1\u30C7\u30A3\u30A2\u306B\u5909\u66F4\u3059\u308B\u3002 -AutopsyOptionsPanel.useBestViewerRB.text=\u6700\u3082\u5C02\u9580\u7684\u306A\u30D5\u30A1\u30A4\u30EB\u30D3\u30E5\u30FC\u30A2\u306B\u5909\u66F4 -AutopsyOptionsPanel.useGMTTimeRB.text=GMT\u3092\u4F7F\u7528 -AutopsyOptionsPanel.useLocalTimeRB.text=\u30ED\u30FC\u30AB\u30EB\u30BF\u30A4\u30E0\u30BE\u30FC\u30F3\u3092\u4F7F\u7528 -AutopsyOptionsPanel.keepCurrentViewerRB.toolTipText=\u4F8B\u3048\u3070\u3001JPEG\u304C\u9078\u629E\u3055\u308C\u305F\u5834\u5408\u306B\u305D\u306E\u307E\u307EHEX\u30D3\u30E5\u30FC\u3092\u4F7F\u7528\u3002 -AutopsyOptionsPanel.keepCurrentViewerRB.text=\u305D\u306E\u307E\u307E\u540C\u3058\u30D5\u30A1\u30A4\u30EB\u30D3\u30E5\u30FC\u30A2\u3092\u4F7F\u7528 -AutopsyOptionsPanel.restartRequiredLabel.text=\u3053\u306E\u30B3\u30F3\u30D4\u30E5\u30FC\u30BF\u30FC\u3067\u306F\u6700\u5927{0}\u306E\u30D5\u30A1\u30A4\u30EB\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30B9\u30EC\u30C3\u30C9\u3092\u4F7F\u7528\u3059\u3079\u304D\u3067\u3059\u3002\u6709\u52B9\u306B\u3059\u308B\u306B\u306F\u518D\u8D77\u52D5\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 -AutopsyOptionsPanel.jLabelSelectFile.text=\u30D5\u30A1\u30A4\u30EB\u3092\u9078\u629E\u3059\u308B\u5834\u5408\uFF1A -AutopsyOptionsPanel.jLabelHideKnownFiles.text=\u65E2\u77E5\u30D5\u30A1\u30A4\u30EB\uFF08NIST NSRL\u5185\u306E\uFF09\u3092\u4E0B\u8A18\u306B\u96A0\u3059\uFF1A -AutopsyOptionsPanel.jLabelTimeDisplay.text=\u30A2\u30A4\u30C6\u30E0\u3092\u8868\u793A\u3059\u308B\u5834\u5408\uFF1A -AutopsyOptionsPanel.jLabelNumThreads.text=\u30D5\u30A1\u30A4\u30EB\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u306B\u4F7F\u7528\u3059\u308B\u30B9\u30EC\u30C3\u30C9\u6570\uFF1A -FXVideoPanel.progress.bufferingCancelled=\u30E1\u30C7\u30A3\u30A2\u306E\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F -FXVideoPanel.progress.bufferingInterrupted=\u30E1\u30C7\u30A3\u30A2\u306E\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0\u304C\u4E2D\u65AD\u3055\u308C\u307E\u3057\u305F -FXVideoPanel.progress.errorWritingVideoToDisk=\u30D3\u30C7\u30AA\u3092\u30C7\u30A3\u30B9\u30AF\u3078\u66F8\u304D\u8FBC\u307F\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F +DataContentViewerString.setDataView.errorNoText=\uff08\u30aa\u30d5\u30bb\u30c3\u30c8{0}-{1}\u306b\u306f\u30c6\u30ad\u30b9\u30c8\u304c\u3042\u308a\u307e\u305b\u3093\uff09 +DataResultViewerThumbnail.comboBox.smallThumbnails=\u30b5\u30e0\u30cd\u30a4\u30eb\uff08\u5c0f\uff09 +DataResultViewerThumbnail.comboBox.mediumThumbnails=\u30b5\u30e0\u30cd\u30a4\u30eb\uff08\u4e2d\uff09 +DataResultViewerThumbnail.comboBox.largeThumbnails=\u30b5\u30e0\u30cd\u30a4\u30eb\uff08\u5927\uff09 +DataResultViewerThumbnail.switchPage.done.errMsg=\u30b5\u30e0\u30cd\u30a4\u30eb\u4f5c\u6210\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a {0} +FXVideoPanel.pauseButton.infoLabel.playbackErr=\u30d3\u30c7\u30aa\u3092\u518d\u751f\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 +GstVideoPanel.progress.infoLabel.updateErr=\u30d3\u30c7\u30aa\u30d7\u30ed\u30b0\u30ec\u30b9\u306e\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a {0} +GstVideoPanel.ExtractMedia.progress.buffering={0}\u3092\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u4e2d +AboutWindowPanel.actVerboseLogging.text=Verbose\u30ed\u30b0\u3092\u30a2\u30af\u30c6\u30a3\u30d9\u30fc\u30c8 +AutopsyOptionsPanel.viewsHideKnownCB.text=\u30d3\u30e5\u30fc\u30a8\u30ea\u30a2 +AutopsyOptionsPanel.dataSourcesHideKnownCB.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u30a8\u30ea\u30a2\uff08\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u968e\u5c64\uff09 +AutopsyOptionsPanel.useBestViewerRB.toolTipText=\u4f8b\u3048\u3070\u3001JPEG\u304c\u9078\u629e\u3055\u308c\u305f\u5834\u5408\u306b\u306fHEX\u304b\u3089\u30e1\u30c7\u30a3\u30a2\u306b\u5909\u66f4\u3059\u308b\u3002 +AutopsyOptionsPanel.useBestViewerRB.text=\u6700\u3082\u5c02\u9580\u7684\u306a\u30d5\u30a1\u30a4\u30eb\u30d3\u30e5\u30fc\u30a2\u306b\u5909\u66f4 +AutopsyOptionsPanel.useGMTTimeRB.text=GMT\u3092\u4f7f\u7528 +AutopsyOptionsPanel.useLocalTimeRB.text=\u30ed\u30fc\u30ab\u30eb\u30bf\u30a4\u30e0\u30be\u30fc\u30f3\u3092\u4f7f\u7528 +AutopsyOptionsPanel.keepCurrentViewerRB.toolTipText=\u4f8b\u3048\u3070\u3001JPEG\u304c\u9078\u629e\u3055\u308c\u305f\u5834\u5408\u306b\u305d\u306e\u307e\u307eHEX\u30d3\u30e5\u30fc\u3092\u4f7f\u7528\u3002 +AutopsyOptionsPanel.keepCurrentViewerRB.text=\u305d\u306e\u307e\u307e\u540c\u3058\u30d5\u30a1\u30a4\u30eb\u30d3\u30e5\u30fc\u30a2\u3092\u4f7f\u7528 +AutopsyOptionsPanel.restartRequiredLabel.text=\u3053\u306e\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u30fc\u3067\u306f\u6700\u5927{0}\u306e\u30d5\u30a1\u30a4\u30eb\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b9\u30ec\u30c3\u30c9\u3092\u4f7f\u7528\u3059\u3079\u304d\u3067\u3059\u3002\u6709\u52b9\u306b\u3059\u308b\u306b\u306f\u518d\u8d77\u52d5\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 +AutopsyOptionsPanel.jLabelSelectFile.text=\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u3059\u308b\u5834\u5408\uff1a +AutopsyOptionsPanel.jLabelHideKnownFiles.text=\u65e2\u77e5\u30d5\u30a1\u30a4\u30eb\uff08NIST NSRL\u5185\u306e\uff09\u3092\u4e0b\u8a18\u306b\u96a0\u3059\uff1a +AutopsyOptionsPanel.jLabelTimeDisplay.text=\u30a2\u30a4\u30c6\u30e0\u3092\u8868\u793a\u3059\u308b\u5834\u5408\uff1a +AutopsyOptionsPanel.jLabelNumThreads.text=\u30d5\u30a1\u30a4\u30eb\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u306b\u4f7f\u7528\u3059\u308b\u30b9\u30ec\u30c3\u30c9\u6570\uff1a +FXVideoPanel.progress.bufferingCancelled=\u30e1\u30c7\u30a3\u30a2\u306e\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u304c\u30ad\u30e3\u30f3\u30bb\u30eb\u3055\u308c\u307e\u3057\u305f +FXVideoPanel.progress.bufferingInterrupted=\u30e1\u30c7\u30a3\u30a2\u306e\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u304c\u4e2d\u65ad\u3055\u308c\u307e\u3057\u305f +FXVideoPanel.progress.errorWritingVideoToDisk=\u30d3\u30c7\u30aa\u3092\u30c7\u30a3\u30b9\u30af\u3078\u66f8\u304d\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f URL_ON_HELP=http\://sleuthkit.org/autopsy/docs/user-docs/3.1/ +DataContentViewerHex.goToOffsetLabel.text=\u4e0b\u8a18\u306e\u30da\u30fc\u30b8\u3078\u79fb\u52d5\uff1a diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form index a5663b4644..e764f8ee56 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form @@ -88,9 +88,13 @@ - + + + + + - + @@ -108,9 +112,11 @@ + + - - + + @@ -278,6 +284,23 @@ + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index c7eb83ebd0..1f6e604ea1 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -103,6 +103,8 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont pageLabel2 = new javax.swing.JLabel(); goToPageTextField = new javax.swing.JTextField(); goToPageLabel = new javax.swing.JLabel(); + goToOffsetLabel = new javax.swing.JLabel(); + goToOffsetTextField = new javax.swing.JTextField(); copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.copyMenuItem.text")); // NOI18N rightClickMenu.add(copyMenuItem); @@ -113,7 +115,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont jScrollPane1.setBackground(new java.awt.Color(255, 255, 255)); outputViewPane.setEditable(false); - outputViewPane.setFont(new Font("Courier New", Font.PLAIN, 11)); // NOI18N NON-NLS + outputViewPane.setFont(new java.awt.Font("Courier New", 0, 11)); // NOI18N outputViewPane.setMinimumSize(new java.awt.Dimension(700, 20)); outputViewPane.setPreferredSize(new java.awt.Dimension(700, 400)); jScrollPane1.setViewportView(outputViewPane); @@ -132,28 +134,28 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont pageLabel.setMinimumSize(new java.awt.Dimension(33, 14)); pageLabel.setPreferredSize(new java.awt.Dimension(33, 14)); - prevPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N NON-NLS + prevPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back.png"))); // NOI18N prevPageButton.setText(org.openide.util.NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.prevPageButton.text")); // NOI18N prevPageButton.setBorderPainted(false); prevPageButton.setContentAreaFilled(false); - prevPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N NON-NLS + prevPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png"))); // NOI18N prevPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0)); prevPageButton.setPreferredSize(new java.awt.Dimension(23, 23)); - prevPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N NON-NLS + prevPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_back_hover.png"))); // NOI18N prevPageButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { prevPageButtonActionPerformed(evt); } }); - nextPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N NON-NLS + nextPageButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png"))); // NOI18N nextPageButton.setText(org.openide.util.NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.nextPageButton.text")); // NOI18N nextPageButton.setBorderPainted(false); nextPageButton.setContentAreaFilled(false); - nextPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N NON-NLS + nextPageButton.setDisabledIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png"))); // NOI18N nextPageButton.setMargin(new java.awt.Insets(2, 0, 2, 0)); nextPageButton.setPreferredSize(new java.awt.Dimension(23, 23)); - nextPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N NON-NLS + nextPageButton.setRolloverIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/btn_step_forward_hover.png"))); // NOI18N nextPageButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { nextPageButtonActionPerformed(evt); @@ -174,6 +176,15 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont goToPageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.goToPageLabel.text")); // NOI18N + goToOffsetLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.goToOffsetLabel.text")); // NOI18N + + goToOffsetTextField.setText(org.openide.util.NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.goToOffsetTextField.text")); // NOI18N + goToOffsetTextField.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + goToOffsetTextFieldActionPerformed(evt); + } + }); + javax.swing.GroupLayout hexViewerPanelLayout = new javax.swing.GroupLayout(hexViewerPanel); hexViewerPanel.setLayout(hexViewerPanelLayout); hexViewerPanelLayout.setHorizontalGroup( @@ -197,8 +208,12 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont .addComponent(goToPageLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(205, Short.MAX_VALUE)) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 622, Short.MAX_VALUE) + .addGap(18, 18, 18) + .addComponent(goToOffsetLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(jScrollPane1) ); hexViewerPanelLayout.setVerticalGroup( hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -213,9 +228,11 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(goToPageLabel) - .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(0, 0, 0) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 388, Short.MAX_VALUE)) + .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(goToOffsetLabel) + .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 382, Short.MAX_VALUE)) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); @@ -241,11 +258,13 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont }// //GEN-END:initComponents private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed - setDataView(currentPage - 1); + setDataViewByPageNumber(currentPage - 1); + goToPageTextField.setText(Integer.toString(currentPage)); }//GEN-LAST:event_prevPageButtonActionPerformed private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed - setDataView(currentPage + 1); + setDataViewByPageNumber(currentPage + 1); + goToPageTextField.setText(Integer.toString(currentPage)); }//GEN-LAST:event_nextPageButtonActionPerformed private void goToPageTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToPageTextFieldActionPerformed @@ -267,11 +286,24 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont JOptionPane.WARNING_MESSAGE); return; } - setDataView(pageNumber); + setDataViewByPageNumber(pageNumber); }//GEN-LAST:event_goToPageTextFieldActionPerformed + + private void goToOffsetTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToOffsetTextFieldActionPerformed + String hexOffsetStr = goToOffsetTextField.getText(); + try { + long offset = Long.decode(hexOffsetStr); + setDataViewByOffset(offset); + } catch (NumberFormatException ex) { + JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(), "DataContentViewerHex.goToOffsetTextField.msgDlg", hexOffsetStr)); + } + }//GEN-LAST:event_goToOffsetTextFieldActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JMenuItem copyMenuItem; private javax.swing.JLabel currentPageLabel; + private javax.swing.JLabel goToOffsetLabel; + private javax.swing.JTextField goToOffsetTextField; private javax.swing.JLabel goToPageLabel; private javax.swing.JTextField goToPageTextField; private javax.swing.JPanel hexViewerPanel; @@ -293,7 +325,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont * * @param page Page to display (1-based counting) */ - private void setDataView(int page) { + private void setDataViewByPageNumber(int page) { if (this.dataSource == null) { return; } @@ -357,6 +389,69 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont outputViewPane.setCaretPosition(0); this.setCursor(null); + goToOffsetTextField.setText(Long.toString(offset)); + } + + private void setDataViewByOffset(long offset) { + if (this.dataSource == null) { + return; + } + + if (offset == 0) { + return; + } + + currentPage = (int)(offset / pageLength) + 1; + + // change the cursor to "waiting cursor" for this operation + this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + String errorText = null; + + int bytesRead = 0; + if (dataSource.getSize() > 0) { + try { + bytesRead = dataSource.read(data, offset, pageLength); // read the data + } catch (TskException ex) { + errorText = NbBundle.getMessage(this.getClass(), "DataContentViewerHex.setDataView.errorText", offset, + offset + pageLength); + logger.log(Level.WARNING, "Error while trying to show the hex content.", ex); //NON-NLS + } + } + + // set the data on the bottom and show it + if (bytesRead <= 0) { + errorText = NbBundle.getMessage(this.getClass(), "DataContentViewerHex.setDataView.errorText", offset, + offset + pageLength); + } + + // disable or enable the next button + if ((errorText == null) && (currentPage < totalPages)) { + nextPageButton.setEnabled(true); + } else { + nextPageButton.setEnabled(false); + } + + if ((errorText == null) && (currentPage > 1)) { + prevPageButton.setEnabled(true); + } else { + prevPageButton.setEnabled(false); + } + + currentPageLabel.setText(Integer.toString(currentPage)); + setComponentsVisibility(true); // shows the components that not needed + + // set the output view + if (errorText == null) { + int showLength = bytesRead < pageLength ? bytesRead : (int) pageLength; + outputViewPane.setText(DataConversion.byteArrayToHex(data, showLength, offset)); + } else { + outputViewPane.setText(errorText); + } + + outputViewPane.setCaretPosition(0); + this.setCursor(null); + goToPageTextField.setText(Integer.toString(currentPage)); } @Override @@ -379,7 +474,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont } totalPageLabel.setText(Integer.toString(totalPages)); - this.setDataView(1); + this.setDataViewByPageNumber(1); } @Override @@ -423,6 +518,8 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont pageLabel2.setVisible(isVisible); goToPageTextField.setVisible(isVisible); goToPageLabel.setVisible(isVisible); + goToOffsetTextField.setVisible(isVisible); + goToOffsetLabel.setVisible(isVisible); } @Override From 8fd4ae66acb591c78b703a9ac30d94393a08646e Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Mon, 15 Jun 2015 12:44:12 -0400 Subject: [PATCH 040/198] Reverted unnecessary modifications to bundle(_ja).properties --- .../autopsy/corecomponents/Bundle.properties | 1 - .../corecomponents/Bundle_ja.properties | 219 +++++++++--------- 2 files changed, 109 insertions(+), 111 deletions(-) mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 2365f7440c..7c085de590 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -147,7 +147,6 @@ AutopsyOptionsPanel.jLabelNumThreads.text=Number of threads to use for file inge FXVideoPanel.progress.bufferingCancelled=media buffering was canceled FXVideoPanel.progress.bufferingInterrupted=media buffering was interrupted FXVideoPanel.progress.errorWritingVideoToDisk=Error writing video to disk -DataContentViewerHex.goToPageLabel1.text=Jump to Offset DataContentViewerHex.goToOffsetLabel.text=Jump to Offset DataContentViewerHex.goToOffsetTextField.text= DataContentViewerHex.goToOffsetTextField.msgDlg=Invalid Offset: {0} diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties old mode 100644 new mode 100755 index d31943019a..db6e5b5ecc --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle_ja.properties @@ -1,129 +1,128 @@ -CTL_DataContentAction=\u30c7\u30fc\u30bf\u30b3\u30f3\u30c6\u30f3\u30c4 +CTL_DataContentAction=\u30C7\u30FC\u30BF\u30B3\u30F3\u30C6\u30F3\u30C4 OptionsCategory_Name_General=Autopsy -OptionsCategory_Keywords_General=Autopsy\u30aa\u30d7\u30b7\u30e7\u30f3 -CTL_CustomAboutAction=Autopsy\u306b\u3064\u3044\u3066 -CTL_DataContentTopComponent=\u30c7\u30fc\u30bf\u30b3\u30f3\u30c6\u30f3\u30c4 -HINT_DataContentTopComponent=\u3053\u308c\u306f\u30c7\u30fc\u30bf\u30b3\u30f3\u30c6\u30f3\u30c4\u306e\u30a6\u30a3\u30f3\u30c9\u30a6\u3067\u3059 -HINT_NodeTableTopComponent=\u3053\u308c\u306f\u30c7\u30fc\u30bf\u7d50\u679c\u306e\u30a6\u30a3\u30f3\u30c9\u30a6\u3067\u3059 -OpenIDE-Module-Name=\u4e3b\u8981\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8 -DataContentViewerHex.pageLabel.text_1=\u30da\u30fc\u30b8\uff1a +OptionsCategory_Keywords_General=Autopsy\u30AA\u30D7\u30B7\u30E7\u30F3 +CTL_CustomAboutAction=Autopsy\u306B\u3064\u3044\u3066 +CTL_DataContentTopComponent=\u30C7\u30FC\u30BF\u30B3\u30F3\u30C6\u30F3\u30C4 +HINT_DataContentTopComponent=\u3053\u308C\u306F\u30C7\u30FC\u30BF\u30B3\u30F3\u30C6\u30F3\u30C4\u306E\u30A6\u30A3\u30F3\u30C9\u30A6\u3067\u3059 +HINT_NodeTableTopComponent=\u3053\u308C\u306F\u30C7\u30FC\u30BF\u7D50\u679C\u306E\u30A6\u30A3\u30F3\u30C9\u30A6\u3067\u3059 +OpenIDE-Module-Name=\u4E3B\u8981\u30B3\u30F3\u30DD\u30FC\u30CD\u30F3\u30C8 +DataContentViewerHex.pageLabel.text_1=\u30DA\u30FC\u30B8\uFF1A DataContentViewerHex.currentPageLabel.text_1=1 DataContentViewerHex.totalPageLabel.text_1=100 -DataContentViewerString.pageLabel.text_1=\u30da\u30fc\u30b8\uff1a +DataContentViewerString.pageLabel.text_1=\u30DA\u30FC\u30B8\uFF1A DataContentViewerString.currentPageLabel.text_1=1 DataContentViewerString.totalPageLabel.text_1=100 -DataContentViewerHex.pageLabel2.text=\u30da\u30fc\u30b8 -DataContentViewerString.pageLabel2.text=\u30da\u30fc\u30b8 -Format_OperatingSystem_Value={0} \u30d0\u30fc\u30b8\u30e7\u30f3 {1} \u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3 {2} +DataContentViewerHex.pageLabel2.text=\u30DA\u30FC\u30B8 +DataContentViewerString.pageLabel2.text=\u30DA\u30FC\u30B8 +Format_OperatingSystem_Value={0} \u30D0\u30FC\u30B8\u30E7\u30F3 {1} \u30A2\u30FC\u30AD\u30C6\u30AF\u30C1\u30E3 {2} URL_ON_IMG=http\://www.sleuthkit.org/ -LBL_Close=\u9589\u3058\u308b -DataContentViewerString.copyMenuItem.text=\u30b3\u30d4\u30fc -DataContentViewerHex.copyMenuItem.text=\u30b3\u30d4\u30fc -DataContentViewerString.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629e -DataContentViewerHex.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629e +LBL_Close=\u9589\u3058\u308B +DataContentViewerString.copyMenuItem.text=\u30B3\u30D4\u30FC +DataContentViewerHex.copyMenuItem.text=\u30B3\u30D4\u30FC +DataContentViewerString.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629E +DataContentViewerHex.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629E DataContentViewerArtifact.totalPageLabel.text=100 -DataContentViewerArtifact.pageLabel2.text=\u7d50\u679c +DataContentViewerArtifact.pageLabel2.text=\u7D50\u679C DataContentViewerArtifact.currentPageLabel.text=1 -DataContentViewerArtifact.copyMenuItem.text=\u30b3\u30d4\u30fc -DataContentViewerArtifact.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629e -DataContentViewerArtifact.pageLabel.text=\u7d50\u679c\uff1a +DataContentViewerArtifact.copyMenuItem.text=\u30B3\u30D4\u30FC +DataContentViewerArtifact.selectAllMenuItem.text=\u3059\u3079\u3066\u9078\u629E +DataContentViewerArtifact.pageLabel.text=\u7D50\u679C\uFF1A AdvancedConfigurationDialog.applyButton.text=OK -DataContentViewerString.goToPageLabel.text=\u4e0b\u8a18\u306e\u30da\u30fc\u30b8\u3078\u79fb\u52d5\uff1a -DataContentViewerHex.goToPageLabel.text=\u4e0b\u8a18\u306e\u30da\u30fc\u30b8\u3078\u79fb\u52d5\uff1a -DataContentViewerString.languageLabel.text=\u30b9\u30af\u30ea\u30d7\u30c8\uff1a -DataContentViewerString.languageCombo.toolTipText=\u30d0\u30a4\u30ca\u30ea\u30b9\u30c8\u30ea\u30f3\u30b0\u306e\u51e6\u7406\uff08\u62bd\u51fa\u304a\u3088\u3073\u30c7\u30b3\u30fc\u30c9\uff09\u306b\u4f7f\u7528\u3059\u308b\u8a00\u8a9e -DataResultViewerThumbnail.pageLabel.text=\u30da\u30fc\u30b8\uff1a -DataResultViewerThumbnail.pagesLabel.text=\u30da\u30fc\u30b8\uff1a -DataResultViewerThumbnail.imagesLabel.text=\u30a4\u30e1\u30fc\u30b8\uff1a +DataContentViewerString.goToPageLabel.text=\u4E0B\u8A18\u306E\u30DA\u30FC\u30B8\u3078\u79FB\u52D5\uFF1A +DataContentViewerHex.goToPageLabel.text=\u4E0B\u8A18\u306E\u30DA\u30FC\u30B8\u3078\u79FB\u52D5\uFF1A +DataContentViewerString.languageLabel.text=\u30B9\u30AF\u30EA\u30D7\u30C8\uFF1A +DataContentViewerString.languageCombo.toolTipText=\u30D0\u30A4\u30CA\u30EA\u30B9\u30C8\u30EA\u30F3\u30B0\u306E\u51E6\u7406\uFF08\u62BD\u51FA\u304A\u3088\u3073\u30C7\u30B3\u30FC\u30C9\uFF09\u306B\u4F7F\u7528\u3059\u308B\u8A00\u8A9E +DataResultViewerThumbnail.pageLabel.text=\u30DA\u30FC\u30B8\uFF1A +DataResultViewerThumbnail.pagesLabel.text=\u30DA\u30FC\u30B8\uFF1A +DataResultViewerThumbnail.imagesLabel.text=\u30A4\u30E1\u30FC\u30B8\uFF1A DataResultViewerThumbnail.imagesRangeLabel.text=- DataResultViewerThumbnail.pageNumLabel.text=- -DataResultViewerThumbnail.goToPageLabel.text=\u4e0b\u8a18\u306e\u30da\u30fc\u30b8\u306b\u79fb\u52d5\uff1a -AdvancedConfigurationDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb -DataResultPanel.directoryTablePath.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30d1\u30b9 +DataResultViewerThumbnail.goToPageLabel.text=\u4E0B\u8A18\u306E\u30DA\u30FC\u30B8\u306B\u79FB\u52D5\uFF1A +AdvancedConfigurationDialog.cancelButton.text=\u30AD\u30E3\u30F3\u30BB\u30EB +DataResultPanel.directoryTablePath.text=\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u30D1\u30B9 DataResultPanel.numberMatchLabel.text=0 -DataResultPanel.matchLabel.text=\u7d50\u679c -MediaViewVideoPanel.pauseButton.text=\u25ba +DataResultPanel.matchLabel.text=\u7D50\u679C +MediaViewVideoPanel.pauseButton.text=\u25BA MediaViewVideoPanel.progressLabel.text=00\:00 -MediaViewVideoPanel.infoLabel.text=\u60c5\u5831 -DataContentViewerArtifact.waitText=\u30c7\u30fc\u30bf\u3092\u53d6\u8fbc\u307f\u304a\u3088\u3073\u6e96\u5099\u4e2d\u3002\u3057\u3070\u3089\u304f\u304a\u5f85\u3061\u4e0b\u3055\u3044\u2026 -DataContentViewerArtifact.errorText=\u7d50\u679c\u306e\u53d6\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f -DataContentViewerArtifact.title=\u7d50\u679c -DataContentViewerArtifact.toolTip=\u30d5\u30a1\u30a4\u30eb\u306b\u95a2\u9023\u3059\u308b\u7d50\u679c\u3092\u8868\u793a\u3057\u307e\u3059 -DataContentViewerHex.goToPageTextField.msgDlg=\uff11\u304b\u3089 {0}\u306e\u9593\u306e\u6709\u52b9\u306a\u30da\u30fc\u30b8\u6570\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044 -DataContentViewerHex.goToPageTextField.err=\u7121\u52b9\u306a\u30da\u30fc\u30b8\u6570 -DataContentViewerHex.setDataView.errorText=\uff08\u30aa\u30d5\u30bb\u30c3\u30c8{0}-{1}\u306f\u8aad\u307f\u53d6\u308c\u307e\u305b\u3093\u3067\u3057\u305f\uff09 +MediaViewVideoPanel.infoLabel.text=\u60C5\u5831 +DataContentViewerArtifact.waitText=\u30C7\u30FC\u30BF\u3092\u53D6\u8FBC\u307F\u304A\u3088\u3073\u6E96\u5099\u4E2D\u3002\u3057\u3070\u3089\u304F\u304A\u5F85\u3061\u4E0B\u3055\u3044\u2026 +DataContentViewerArtifact.errorText=\u7D50\u679C\u306E\u53D6\u8FBC\u307F\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F +DataContentViewerArtifact.title=\u7D50\u679C +DataContentViewerArtifact.toolTip=\u30D5\u30A1\u30A4\u30EB\u306B\u95A2\u9023\u3059\u308B\u7D50\u679C\u3092\u8868\u793A\u3057\u307E\u3059 +DataContentViewerHex.goToPageTextField.msgDlg=\uFF11\u304B\u3089 {0}\u306E\u9593\u306E\u6709\u52B9\u306A\u30DA\u30FC\u30B8\u6570\u3092\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044 +DataContentViewerHex.goToPageTextField.err=\u7121\u52B9\u306A\u30DA\u30FC\u30B8\u6570 +DataContentViewerHex.setDataView.errorText=\uFF08\u30AA\u30D5\u30BB\u30C3\u30C8{0}-{1}\u306F\u8AAD\u307F\u53D6\u308C\u307E\u305B\u3093\u3067\u3057\u305F\uFF09 DataContentViewerHex.title=HEX -DataContentViewerHex.toolTip=\u30d0\u30a4\u30ca\u30ea\u30b3\u30f3\u30c6\u30f3\u30c4\u3092HEX\u30d5\u30a1\u30a4\u30eb\u3068\u3057\u3066\u8868\u793a\u3057\u3001ASCII\u3068\u3057\u3066\u8868\u793a\u3067\u304d\u308b\u30d0\u30a4\u30c8\u306f\u53f3\u5074\u306b\u8868\u793a\u3057\u307e\u3059\u3002 -DataContentViewerMedia.title=\u30e1\u30c7\u30a3\u30a2 -DataContentViewerMedia.toolTip=\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u308b\u30de\u30eb\u30c1\u30e1\u30c7\u30a3\u30a2\u30d5\u30a1\u30a4\u30eb\uff08\u30a4\u30e1\u30fc\u30b8\u3001\u30d3\u30c7\u30aa\u3001\u30aa\u30fc\u30c7\u30a3\u30aa\uff09\u3092\u8868\u793a\u3057\u307e\u3059\u3002 -DataContentViewerString.goToPageTextField.msgDlg=\uff11\u304b\u3089{0}\u306e\u9593\u306e\u6709\u52b9\u306a\u30da\u30fc\u30b8\u6570\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044 -DataContentViewerString.goToPageTextField.err=\u7121\u52b9\u306a\u30da\u30fc\u30b8\u6570 -DataContentViewerString.setDataView.errorText=\uff08\u30aa\u30d5\u30bb\u30c3\u30c8{0}-{1}\u306f\u8aad\u307f\u53d6\u308c\u307e\u305b\u3093\u3067\u3057\u305f\uff09 -DataContentViewerString.title=\u30b9\u30c8\u30ea\u30f3\u30b0 -DataContentViewerString.toolTip=\u30d5\u30a1\u30a4\u30eb\u304b\u3089\u62bd\u51fa\u3055\u308c\u305fASCII\u304a\u3088\u3073\u30e6\u30cb\u30b3\u30fc\u30c9\u306e\u30b9\u30c8\u30ea\u30f3\u30b0\u304c\u8868\u793a\u3055\u308c\u307e\u3059\u3002 -DataResultPanel.dummyNodeDisplayName=\u3057\u3070\u3089\u304f\u304a\u5f85\u3061\u304f\u3060\u3055\u3044\u2026 -DataResultViewerTable.firstColLbl=\u540d\u524d -DataResultViewerTable.illegalArgExc.noChildFromParent=\u6307\u5b9a\u3055\u308c\u305f\u30da\u30a2\u30ec\u30f3\u30c8\u304b\u3089\u30c1\u30e3\u30a4\u30eb\u30c9\u30ce\u30fc\u30c9\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 -DataResultViewerTable.illegalArgExc.childWithoutPropertySet=\u30c1\u30e3\u30a4\u30eb\u30c9\u30ce\u30fc\u30c9\u306f\u901a\u5e38\u306ePropertySet\u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093\u3002 -DataResultViewerTable.title=\u30c6\u30fc\u30d6\u30eb -DataResultViewerTable.dummyNodeDisplayName=\u3057\u3070\u3089\u304f\u304a\u5f85\u3061\u304f\u3060\u3055\u3044\u2026 -DataResultViewerThumbnail.title=\u30b5\u30e0\u30cd\u30a4\u30eb -DataResultViewerThumbnail.goToPageTextField.msgDlg=\uff11\u304b\u3089{0}\u306e\u9593\u306e\u6709\u52b9\u306a\u30da\u30fc\u30b8\u6570\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044 -DataResultViewerThumbnail.goToPageTextField.err=\u7121\u52b9\u306a\u30da\u30fc\u30b8\u6570 -DataResultViewerThumbnail.genThumbs=\u30b5\u30e0\u30cd\u30a4\u30eb\u3092\u4f5c\u6210\u4e2d\u2026 -DataResultViewerThumbnail.pageNumbers.curOfTotal={0}\uff0f{1}\u76ee -FXVideoPanel.mediaPane.infoLabel=\u524a\u9664\u3055\u308c\u305f\u30d3\u30c7\u30aa\u306e\u518d\u751f\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u5916\u90e8\u30d7\u30ec\u30fc\u30e4\u30fc\u3092\u4f7f\u7528\u3057\u3066\u4e0b\u3055\u3044\u3002 -FXVideoPanel.progress.bufferingFile={0}\u3092\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0 -FXVideoPanel.progressLabel.buffering=\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u4e2d\u2026 -FXVideoPanel.media.unsupportedFormat=\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u306a\u3044\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u3067\u3059\u3002 -GeneralOptionsPanelController.moduleErr=\u30e2\u30b8\u30e5\u30fc\u30eb\u30a8\u30e9\u30fc -GeneralOptionsPanelController.moduleErr.msg=GeneralOptionsPanelController\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3092\u78ba\u8a8d\u4e2d\u306b\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u30a8\u30e9\u30fc\u3092\u8d77\u3053\u3057\u307e\u3057\u305f\u3002\u3069\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u304b\u30ed\u30b0\u3067\u78ba\u8a8d\u3057\u3066\u4e0b\u3055\u3044\u3002\u4e00\u90e8\u306e\u30c7\u30fc\u30bf\u304c\u4e0d\u5b8c\u5168\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 -GstVideoPanel.cannotProcFile.err=\u30e1\u30c7\u30a4\u30a2\u30d7\u30ec\u30fc\u30e4\u30fc\u304c\u3053\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u51e6\u7406\u3067\u304d\u307e\u305b\u3093\u3002 -GstVideoPanel.initGst.gstException.msg=\u30aa\u30fc\u30c7\u30a3\u30aa\uff0f\u30d3\u30c7\u30aa\u306e\u518d\u751f\u304a\u3088\u3073\u30d5\u30ec\u30fc\u30e0\u306e\u62bd\u51fa\u306b\u4f7f\u7528\u3059\u308bGStreamer\u306e\u521d\u671f\u5316\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30d3\u30c7\u30aa\u304a\u3088\u3073\u30aa\u30fc\u30c7\u30a3\u30aa\u518d\u751f\u304c\u7121\u52b9\u5316\u3055\u308c\u307e\u3059\u3002 -GstVideoPanel.initGst.otherException.msg=\u30aa\u30fc\u30c7\u30a3\u30aa\uff0f\u30d3\u30c7\u30aa\u306e\u518d\u751f\u304a\u3088\u3073\u30d5\u30ec\u30fc\u30e0\u306e\u62bd\u51fa\u306b\u4f7f\u7528\u3059\u308bGStreamer\u306e\u521d\u671f\u5316\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30d3\u30c7\u30aa\u304a\u3088\u3073\u30aa\u30fc\u30c7\u30a3\u30aa\u518d\u751f\u304c\u7121\u52b9\u5316\u3055\u308c\u307e\u3059\u3002 -GstVideoPanel.setupVideo.infoLabel.text=\u524a\u9664\u3055\u308c\u305f\u30d3\u30c7\u30aa\u306e\u518d\u751f\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u5916\u90e8\u30d7\u30ec\u30fc\u30e4\u30fc\u3092\u4f7f\u7528\u3057\u3066\u4e0b\u3055\u3044\u3002 -GstVideoPanel.exception.problemFile.msg=\u30d5\u30a1\u30a4\u30eb({0})\u304b\u3089\u306f\u30d5\u30ec\u30fc\u30e0\u3092\u62bd\u51fa\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 -GstVideoPanel.exception.problemPlay.msg=\u30d3\u30c7\u30aa\u30d5\u30a1\u30a4\u30eb\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u9577\u3055\u3092\u78ba\u8a8d\u4e2d\u306b\u518d\u751f\u3092\u3057\u3088\u3046\u3068\u3057\u305f\u969b\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 -LBL_Description=
\n \u88fd\u54c1\u30d0\u30fc\u30b8\u30e7\u30f3\uff1a {0} ({9})
Sleuth Kit\u30d0\u30fc\u30b8\u30e7\u30f3\uff1a {7}
Netbeans RCP\u30d3\u30eb\u30c9\: {8}
Java\: {1}; {2}
\u30b7\u30b9\u30c6\u30e0\uff1a {3}; {4}; {5}
\u30e6\u30fc\u30b6\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u540d {6}
-LBL_Copyright=
Autopsy™\u306fSleuth Kit™\u3084\u305d\u306e\u4ed6\u30c4\u30fc\u30eb\u3092\u57fa\u306b\u3057\u305f\u30c7\u30b8\u30bf\u30eb\u30fb\u30d5\u30a9\u30ec\u30f3\u30b8\u30c3\u30af\u30fb\u30d7\u30e9\u30c3\u30c8\u30d5\u30a9\u30fc\u30e0\u3067\u3059\u3002

Copyright © 2003-2013. \u8a73\u7d30\u306f\u4e0b\u8a18\u3092\u3054\u89a7\u4e0b\u3055\u3044\u3002 http\://www.sleuthkit.org.
-GstVideoPanel.exception.problemPause.msg=\u30d3\u30c7\u30aa\u30d5\u30a1\u30a4\u30eb\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u9577\u3055\u3092\u78ba\u8a8d\u4e2d\u306b\u4e00\u6642\u505c\u6b62\u3092\u3057\u3088\u3046\u3068\u3057\u305f\u969b\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 -GstVideoPanel.exception.problemPauseCaptFrame.msg=\u30d3\u30c7\u30aa\u30d5\u30a1\u30a4\u30eb\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30d5\u30ec\u30fc\u30e0\u306e\u62bd\u51fa\u4e2d\u306b\u4e00\u6642\u505c\u6b62\u3092\u3057\u3088\u3046\u3068\u3057\u305f\u969b\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 -GstVideoPanel.exception.problemPlayCaptFrame.msg=\u30d3\u30c7\u30aa\u30d5\u30a1\u30a4\u30eb\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30d5\u30ec\u30fc\u30e0\u306e\u62bd\u51fa\u4e2d\u306b\u518d\u751f\u3057\u3088\u3046\u3068\u3057\u305f\u969b\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 -GstVideoPanel.exception.problemStopCaptFrame.msg=\u30d3\u30c7\u30aa\u30d5\u30a1\u30a4\u30eb\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30d5\u30ec\u30fc\u30e0\u306e\u62bd\u51fa\u4e2d\u306b\u505c\u6b62\u3057\u3088\u3046\u3068\u3057\u305f\u969b\u306b\u554f\u984c\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 -GstVideoPanel.progress.buffering=\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u4e2d\u2026 -GstVideoPanel.progressLabel.bufferingErr=\u30d5\u30a1\u30a4\u30eb\u306e\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u30a8\u30e9\u30fc -MediaViewImagePanel.imgFileTooLarge.msg=\u30a4\u30e1\u30fc\u30b8\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u3081\u307e\u305b\u3093\u3067\u3057\u305f\uff08\u5927\u304d\u3059\u304e\u3067\u3059\uff09\uff1a {0} -ProductInformationPanel.verbLoggingEnabled.text=Verbose\u30ed\u30b0\u304c\u6709\u52b9\u3067\u3059 -ProductInformationPanel.propertyUnknown.text=\u4e0d\u660e +DataContentViewerHex.toolTip=\u30D0\u30A4\u30CA\u30EA\u30B3\u30F3\u30C6\u30F3\u30C4\u3092HEX\u30D5\u30A1\u30A4\u30EB\u3068\u3057\u3066\u8868\u793A\u3057\u3001ASCII\u3068\u3057\u3066\u8868\u793A\u3067\u304D\u308B\u30D0\u30A4\u30C8\u306F\u53F3\u5074\u306B\u8868\u793A\u3057\u307E\u3059\u3002 +DataContentViewerMedia.title=\u30E1\u30C7\u30A3\u30A2 +DataContentViewerMedia.toolTip=\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u308B\u30DE\u30EB\u30C1\u30E1\u30C7\u30A3\u30A2\u30D5\u30A1\u30A4\u30EB\uFF08\u30A4\u30E1\u30FC\u30B8\u3001\u30D3\u30C7\u30AA\u3001\u30AA\u30FC\u30C7\u30A3\u30AA\uFF09\u3092\u8868\u793A\u3057\u307E\u3059\u3002 +DataContentViewerString.goToPageTextField.msgDlg=\uFF11\u304B\u3089{0}\u306E\u9593\u306E\u6709\u52B9\u306A\u30DA\u30FC\u30B8\u6570\u3092\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044 +DataContentViewerString.goToPageTextField.err=\u7121\u52B9\u306A\u30DA\u30FC\u30B8\u6570 +DataContentViewerString.setDataView.errorText=\uFF08\u30AA\u30D5\u30BB\u30C3\u30C8{0}-{1}\u306F\u8AAD\u307F\u53D6\u308C\u307E\u305B\u3093\u3067\u3057\u305F\uFF09 +DataContentViewerString.title=\u30B9\u30C8\u30EA\u30F3\u30B0 +DataContentViewerString.toolTip=\u30D5\u30A1\u30A4\u30EB\u304B\u3089\u62BD\u51FA\u3055\u308C\u305FASCII\u304A\u3088\u3073\u30E6\u30CB\u30B3\u30FC\u30C9\u306E\u30B9\u30C8\u30EA\u30F3\u30B0\u304C\u8868\u793A\u3055\u308C\u307E\u3059\u3002 +DataResultPanel.dummyNodeDisplayName=\u3057\u3070\u3089\u304F\u304A\u5F85\u3061\u304F\u3060\u3055\u3044\u2026 +DataResultViewerTable.firstColLbl=\u540D\u524D +DataResultViewerTable.illegalArgExc.noChildFromParent=\u6307\u5B9A\u3055\u308C\u305F\u30DA\u30A2\u30EC\u30F3\u30C8\u304B\u3089\u30C1\u30E3\u30A4\u30EB\u30C9\u30CE\u30FC\u30C9\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 +DataResultViewerTable.illegalArgExc.childWithoutPropertySet=\u30C1\u30E3\u30A4\u30EB\u30C9\u30CE\u30FC\u30C9\u306F\u901A\u5E38\u306EPropertySet\u3092\u6301\u3063\u3066\u3044\u307E\u305B\u3093\u3002 +DataResultViewerTable.title=\u30C6\u30FC\u30D6\u30EB +DataResultViewerTable.dummyNodeDisplayName=\u3057\u3070\u3089\u304F\u304A\u5F85\u3061\u304F\u3060\u3055\u3044\u2026 +DataResultViewerThumbnail.title=\u30B5\u30E0\u30CD\u30A4\u30EB +DataResultViewerThumbnail.goToPageTextField.msgDlg=\uFF11\u304B\u3089{0}\u306E\u9593\u306E\u6709\u52B9\u306A\u30DA\u30FC\u30B8\u6570\u3092\u5165\u529B\u3057\u3066\u4E0B\u3055\u3044 +DataResultViewerThumbnail.goToPageTextField.err=\u7121\u52B9\u306A\u30DA\u30FC\u30B8\u6570 +DataResultViewerThumbnail.genThumbs=\u30B5\u30E0\u30CD\u30A4\u30EB\u3092\u4F5C\u6210\u4E2D\u2026 +DataResultViewerThumbnail.pageNumbers.curOfTotal={0}\uFF0F{1}\u76EE +FXVideoPanel.mediaPane.infoLabel=\u524A\u9664\u3055\u308C\u305F\u30D3\u30C7\u30AA\u306E\u518D\u751F\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002\u5916\u90E8\u30D7\u30EC\u30FC\u30E4\u30FC\u3092\u4F7F\u7528\u3057\u3066\u4E0B\u3055\u3044\u3002 +FXVideoPanel.progress.bufferingFile={0}\u3092\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0 +FXVideoPanel.progressLabel.buffering=\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0\u4E2D\u2026 +FXVideoPanel.media.unsupportedFormat=\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u306A\u3044\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u3067\u3059\u3002 +GeneralOptionsPanelController.moduleErr=\u30E2\u30B8\u30E5\u30FC\u30EB\u30A8\u30E9\u30FC +GeneralOptionsPanelController.moduleErr.msg=GeneralOptionsPanelController\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u3092\u78BA\u8A8D\u4E2D\u306B\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u30A8\u30E9\u30FC\u3092\u8D77\u3053\u3057\u307E\u3057\u305F\u3002\u3069\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u304B\u30ED\u30B0\u3067\u78BA\u8A8D\u3057\u3066\u4E0B\u3055\u3044\u3002\u4E00\u90E8\u306E\u30C7\u30FC\u30BF\u304C\u4E0D\u5B8C\u5168\u304B\u3082\u3057\u308C\u307E\u305B\u3093\u3002 +GstVideoPanel.cannotProcFile.err=\u30E1\u30C7\u30A4\u30A2\u30D7\u30EC\u30FC\u30E4\u30FC\u304C\u3053\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u51E6\u7406\u3067\u304D\u307E\u305B\u3093\u3002 +GstVideoPanel.initGst.gstException.msg=\u30AA\u30FC\u30C7\u30A3\u30AA\uFF0F\u30D3\u30C7\u30AA\u306E\u518D\u751F\u304A\u3088\u3073\u30D5\u30EC\u30FC\u30E0\u306E\u62BD\u51FA\u306B\u4F7F\u7528\u3059\u308BGStreamer\u306E\u521D\u671F\u5316\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u30D3\u30C7\u30AA\u304A\u3088\u3073\u30AA\u30FC\u30C7\u30A3\u30AA\u518D\u751F\u304C\u7121\u52B9\u5316\u3055\u308C\u307E\u3059\u3002 +GstVideoPanel.initGst.otherException.msg=\u30AA\u30FC\u30C7\u30A3\u30AA\uFF0F\u30D3\u30C7\u30AA\u306E\u518D\u751F\u304A\u3088\u3073\u30D5\u30EC\u30FC\u30E0\u306E\u62BD\u51FA\u306B\u4F7F\u7528\u3059\u308BGStreamer\u306E\u521D\u671F\u5316\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u30D3\u30C7\u30AA\u304A\u3088\u3073\u30AA\u30FC\u30C7\u30A3\u30AA\u518D\u751F\u304C\u7121\u52B9\u5316\u3055\u308C\u307E\u3059\u3002 +GstVideoPanel.setupVideo.infoLabel.text=\u524A\u9664\u3055\u308C\u305F\u30D3\u30C7\u30AA\u306E\u518D\u751F\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002\u5916\u90E8\u30D7\u30EC\u30FC\u30E4\u30FC\u3092\u4F7F\u7528\u3057\u3066\u4E0B\u3055\u3044\u3002 +GstVideoPanel.exception.problemFile.msg=\u30D5\u30A1\u30A4\u30EB({0})\u304B\u3089\u306F\u30D5\u30EC\u30FC\u30E0\u3092\u62BD\u51FA\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 +GstVideoPanel.exception.problemPlay.msg=\u30D3\u30C7\u30AA\u30D5\u30A1\u30A4\u30EB\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u9577\u3055\u3092\u78BA\u8A8D\u4E2D\u306B\u518D\u751F\u3092\u3057\u3088\u3046\u3068\u3057\u305F\u969B\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 +LBL_Description=
\n \u88FD\u54C1\u30D0\u30FC\u30B8\u30E7\u30F3\uFF1A {0} ({9})
Sleuth Kit\u30D0\u30FC\u30B8\u30E7\u30F3\uFF1A {7}
Netbeans RCP\u30D3\u30EB\u30C9\: {8}
Java\: {1}; {2}
\u30B7\u30B9\u30C6\u30E0\uFF1A {3}; {4}; {5}
\u30E6\u30FC\u30B6\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u540D {6}
+LBL_Copyright=
Autopsy™\u306FSleuth Kit™\u3084\u305D\u306E\u4ED6\u30C4\u30FC\u30EB\u3092\u57FA\u306B\u3057\u305F\u30C7\u30B8\u30BF\u30EB\u30FB\u30D5\u30A9\u30EC\u30F3\u30B8\u30C3\u30AF\u30FB\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0\u3067\u3059\u3002

Copyright © 2003-2013. \u8A73\u7D30\u306F\u4E0B\u8A18\u3092\u3054\u89A7\u4E0B\u3055\u3044\u3002 http\://www.sleuthkit.org.
+GstVideoPanel.exception.problemPause.msg=\u30D3\u30C7\u30AA\u30D5\u30A1\u30A4\u30EB\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u9577\u3055\u3092\u78BA\u8A8D\u4E2D\u306B\u4E00\u6642\u505C\u6B62\u3092\u3057\u3088\u3046\u3068\u3057\u305F\u969B\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 +GstVideoPanel.exception.problemPauseCaptFrame.msg=\u30D3\u30C7\u30AA\u30D5\u30A1\u30A4\u30EB\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u30D5\u30EC\u30FC\u30E0\u306E\u62BD\u51FA\u4E2D\u306B\u4E00\u6642\u505C\u6B62\u3092\u3057\u3088\u3046\u3068\u3057\u305F\u969B\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 +GstVideoPanel.exception.problemPlayCaptFrame.msg=\u30D3\u30C7\u30AA\u30D5\u30A1\u30A4\u30EB\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u30D5\u30EC\u30FC\u30E0\u306E\u62BD\u51FA\u4E2D\u306B\u518D\u751F\u3057\u3088\u3046\u3068\u3057\u305F\u969B\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 +GstVideoPanel.exception.problemStopCaptFrame.msg=\u30D3\u30C7\u30AA\u30D5\u30A1\u30A4\u30EB\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002\u30D5\u30EC\u30FC\u30E0\u306E\u62BD\u51FA\u4E2D\u306B\u505C\u6B62\u3057\u3088\u3046\u3068\u3057\u305F\u969B\u306B\u554F\u984C\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 +GstVideoPanel.progress.buffering=\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0\u4E2D\u2026 +GstVideoPanel.progressLabel.bufferingErr=\u30D5\u30A1\u30A4\u30EB\u306E\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0\u30A8\u30E9\u30FC +MediaViewImagePanel.imgFileTooLarge.msg=\u30A4\u30E1\u30FC\u30B8\u30D5\u30A1\u30A4\u30EB\u3092\u8AAD\u307F\u8FBC\u3081\u307E\u305B\u3093\u3067\u3057\u305F\uFF08\u5927\u304D\u3059\u304E\u3067\u3059\uFF09\uFF1A {0} +ProductInformationPanel.verbLoggingEnabled.text=Verbose\u30ED\u30B0\u304C\u6709\u52B9\u3067\u3059 +ProductInformationPanel.propertyUnknown.text=\u4E0D\u660E ProductInformationPanel.getVMValue.text={0} {1} -TableFilterNode.displayName.text=\u540d\u524d +TableFilterNode.displayName.text=\u540D\u524D DataContentViewerHex.ofLabel.text_1=of DataContentViewerString.ofLabel.text_1=of DataContentViewerArtifact.ofLabel.text=of -DataContentViewerString.setDataView.errorNoText=\uff08\u30aa\u30d5\u30bb\u30c3\u30c8{0}-{1}\u306b\u306f\u30c6\u30ad\u30b9\u30c8\u304c\u3042\u308a\u307e\u305b\u3093\uff09 -DataResultViewerThumbnail.comboBox.smallThumbnails=\u30b5\u30e0\u30cd\u30a4\u30eb\uff08\u5c0f\uff09 -DataResultViewerThumbnail.comboBox.mediumThumbnails=\u30b5\u30e0\u30cd\u30a4\u30eb\uff08\u4e2d\uff09 -DataResultViewerThumbnail.comboBox.largeThumbnails=\u30b5\u30e0\u30cd\u30a4\u30eb\uff08\u5927\uff09 -DataResultViewerThumbnail.switchPage.done.errMsg=\u30b5\u30e0\u30cd\u30a4\u30eb\u4f5c\u6210\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a {0} -FXVideoPanel.pauseButton.infoLabel.playbackErr=\u30d3\u30c7\u30aa\u3092\u518d\u751f\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 -GstVideoPanel.progress.infoLabel.updateErr=\u30d3\u30c7\u30aa\u30d7\u30ed\u30b0\u30ec\u30b9\u306e\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a {0} -GstVideoPanel.ExtractMedia.progress.buffering={0}\u3092\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u4e2d -AboutWindowPanel.actVerboseLogging.text=Verbose\u30ed\u30b0\u3092\u30a2\u30af\u30c6\u30a3\u30d9\u30fc\u30c8 -AutopsyOptionsPanel.viewsHideKnownCB.text=\u30d3\u30e5\u30fc\u30a8\u30ea\u30a2 -AutopsyOptionsPanel.dataSourcesHideKnownCB.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u30a8\u30ea\u30a2\uff08\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u968e\u5c64\uff09 -AutopsyOptionsPanel.useBestViewerRB.toolTipText=\u4f8b\u3048\u3070\u3001JPEG\u304c\u9078\u629e\u3055\u308c\u305f\u5834\u5408\u306b\u306fHEX\u304b\u3089\u30e1\u30c7\u30a3\u30a2\u306b\u5909\u66f4\u3059\u308b\u3002 -AutopsyOptionsPanel.useBestViewerRB.text=\u6700\u3082\u5c02\u9580\u7684\u306a\u30d5\u30a1\u30a4\u30eb\u30d3\u30e5\u30fc\u30a2\u306b\u5909\u66f4 -AutopsyOptionsPanel.useGMTTimeRB.text=GMT\u3092\u4f7f\u7528 -AutopsyOptionsPanel.useLocalTimeRB.text=\u30ed\u30fc\u30ab\u30eb\u30bf\u30a4\u30e0\u30be\u30fc\u30f3\u3092\u4f7f\u7528 -AutopsyOptionsPanel.keepCurrentViewerRB.toolTipText=\u4f8b\u3048\u3070\u3001JPEG\u304c\u9078\u629e\u3055\u308c\u305f\u5834\u5408\u306b\u305d\u306e\u307e\u307eHEX\u30d3\u30e5\u30fc\u3092\u4f7f\u7528\u3002 -AutopsyOptionsPanel.keepCurrentViewerRB.text=\u305d\u306e\u307e\u307e\u540c\u3058\u30d5\u30a1\u30a4\u30eb\u30d3\u30e5\u30fc\u30a2\u3092\u4f7f\u7528 -AutopsyOptionsPanel.restartRequiredLabel.text=\u3053\u306e\u30b3\u30f3\u30d4\u30e5\u30fc\u30bf\u30fc\u3067\u306f\u6700\u5927{0}\u306e\u30d5\u30a1\u30a4\u30eb\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b9\u30ec\u30c3\u30c9\u3092\u4f7f\u7528\u3059\u3079\u304d\u3067\u3059\u3002\u6709\u52b9\u306b\u3059\u308b\u306b\u306f\u518d\u8d77\u52d5\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002 -AutopsyOptionsPanel.jLabelSelectFile.text=\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u3059\u308b\u5834\u5408\uff1a -AutopsyOptionsPanel.jLabelHideKnownFiles.text=\u65e2\u77e5\u30d5\u30a1\u30a4\u30eb\uff08NIST NSRL\u5185\u306e\uff09\u3092\u4e0b\u8a18\u306b\u96a0\u3059\uff1a -AutopsyOptionsPanel.jLabelTimeDisplay.text=\u30a2\u30a4\u30c6\u30e0\u3092\u8868\u793a\u3059\u308b\u5834\u5408\uff1a -AutopsyOptionsPanel.jLabelNumThreads.text=\u30d5\u30a1\u30a4\u30eb\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u306b\u4f7f\u7528\u3059\u308b\u30b9\u30ec\u30c3\u30c9\u6570\uff1a -FXVideoPanel.progress.bufferingCancelled=\u30e1\u30c7\u30a3\u30a2\u306e\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u304c\u30ad\u30e3\u30f3\u30bb\u30eb\u3055\u308c\u307e\u3057\u305f -FXVideoPanel.progress.bufferingInterrupted=\u30e1\u30c7\u30a3\u30a2\u306e\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u304c\u4e2d\u65ad\u3055\u308c\u307e\u3057\u305f -FXVideoPanel.progress.errorWritingVideoToDisk=\u30d3\u30c7\u30aa\u3092\u30c7\u30a3\u30b9\u30af\u3078\u66f8\u304d\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +DataContentViewerString.setDataView.errorNoText=\uFF08\u30AA\u30D5\u30BB\u30C3\u30C8{0}-{1}\u306B\u306F\u30C6\u30AD\u30B9\u30C8\u304C\u3042\u308A\u307E\u305B\u3093\uFF09 +DataResultViewerThumbnail.comboBox.smallThumbnails=\u30B5\u30E0\u30CD\u30A4\u30EB\uFF08\u5C0F\uFF09 +DataResultViewerThumbnail.comboBox.mediumThumbnails=\u30B5\u30E0\u30CD\u30A4\u30EB\uFF08\u4E2D\uFF09 +DataResultViewerThumbnail.comboBox.largeThumbnails=\u30B5\u30E0\u30CD\u30A4\u30EB\uFF08\u5927\uFF09 +DataResultViewerThumbnail.switchPage.done.errMsg=\u30B5\u30E0\u30CD\u30A4\u30EB\u4F5C\u6210\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\uFF1A {0} +FXVideoPanel.pauseButton.infoLabel.playbackErr=\u30D3\u30C7\u30AA\u3092\u518D\u751F\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 +GstVideoPanel.progress.infoLabel.updateErr=\u30D3\u30C7\u30AA\u30D7\u30ED\u30B0\u30EC\u30B9\u306E\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\uFF1A {0} +GstVideoPanel.ExtractMedia.progress.buffering={0}\u3092\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0\u4E2D +AboutWindowPanel.actVerboseLogging.text=Verbose\u30ED\u30B0\u3092\u30A2\u30AF\u30C6\u30A3\u30D9\u30FC\u30C8 +AutopsyOptionsPanel.viewsHideKnownCB.text=\u30D3\u30E5\u30FC\u30A8\u30EA\u30A2 +AutopsyOptionsPanel.dataSourcesHideKnownCB.text=\u30C7\u30FC\u30BF\u30BD\u30FC\u30B9\u30A8\u30EA\u30A2\uFF08\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u968E\u5C64\uFF09 +AutopsyOptionsPanel.useBestViewerRB.toolTipText=\u4F8B\u3048\u3070\u3001JPEG\u304C\u9078\u629E\u3055\u308C\u305F\u5834\u5408\u306B\u306FHEX\u304B\u3089\u30E1\u30C7\u30A3\u30A2\u306B\u5909\u66F4\u3059\u308B\u3002 +AutopsyOptionsPanel.useBestViewerRB.text=\u6700\u3082\u5C02\u9580\u7684\u306A\u30D5\u30A1\u30A4\u30EB\u30D3\u30E5\u30FC\u30A2\u306B\u5909\u66F4 +AutopsyOptionsPanel.useGMTTimeRB.text=GMT\u3092\u4F7F\u7528 +AutopsyOptionsPanel.useLocalTimeRB.text=\u30ED\u30FC\u30AB\u30EB\u30BF\u30A4\u30E0\u30BE\u30FC\u30F3\u3092\u4F7F\u7528 +AutopsyOptionsPanel.keepCurrentViewerRB.toolTipText=\u4F8B\u3048\u3070\u3001JPEG\u304C\u9078\u629E\u3055\u308C\u305F\u5834\u5408\u306B\u305D\u306E\u307E\u307EHEX\u30D3\u30E5\u30FC\u3092\u4F7F\u7528\u3002 +AutopsyOptionsPanel.keepCurrentViewerRB.text=\u305D\u306E\u307E\u307E\u540C\u3058\u30D5\u30A1\u30A4\u30EB\u30D3\u30E5\u30FC\u30A2\u3092\u4F7F\u7528 +AutopsyOptionsPanel.restartRequiredLabel.text=\u3053\u306E\u30B3\u30F3\u30D4\u30E5\u30FC\u30BF\u30FC\u3067\u306F\u6700\u5927{0}\u306E\u30D5\u30A1\u30A4\u30EB\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30B9\u30EC\u30C3\u30C9\u3092\u4F7F\u7528\u3059\u3079\u304D\u3067\u3059\u3002\u6709\u52B9\u306B\u3059\u308B\u306B\u306F\u518D\u8D77\u52D5\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002 +AutopsyOptionsPanel.jLabelSelectFile.text=\u30D5\u30A1\u30A4\u30EB\u3092\u9078\u629E\u3059\u308B\u5834\u5408\uFF1A +AutopsyOptionsPanel.jLabelHideKnownFiles.text=\u65E2\u77E5\u30D5\u30A1\u30A4\u30EB\uFF08NIST NSRL\u5185\u306E\uFF09\u3092\u4E0B\u8A18\u306B\u96A0\u3059\uFF1A +AutopsyOptionsPanel.jLabelTimeDisplay.text=\u30A2\u30A4\u30C6\u30E0\u3092\u8868\u793A\u3059\u308B\u5834\u5408\uFF1A +AutopsyOptionsPanel.jLabelNumThreads.text=\u30D5\u30A1\u30A4\u30EB\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u306B\u4F7F\u7528\u3059\u308B\u30B9\u30EC\u30C3\u30C9\u6570\uFF1A +FXVideoPanel.progress.bufferingCancelled=\u30E1\u30C7\u30A3\u30A2\u306E\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0\u304C\u30AD\u30E3\u30F3\u30BB\u30EB\u3055\u308C\u307E\u3057\u305F +FXVideoPanel.progress.bufferingInterrupted=\u30E1\u30C7\u30A3\u30A2\u306E\u30D0\u30C3\u30D5\u30A1\u30EA\u30F3\u30B0\u304C\u4E2D\u65AD\u3055\u308C\u307E\u3057\u305F +FXVideoPanel.progress.errorWritingVideoToDisk=\u30D3\u30C7\u30AA\u3092\u30C7\u30A3\u30B9\u30AF\u3078\u66F8\u304D\u8FBC\u307F\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F URL_ON_HELP=http\://sleuthkit.org/autopsy/docs/user-docs/3.1/ -DataContentViewerHex.goToOffsetLabel.text=\u4e0b\u8a18\u306e\u30da\u30fc\u30b8\u3078\u79fb\u52d5\uff1a From 1c9cef7915d94d14625a832282e9754e4ad81e08 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Tue, 16 Jun 2015 10:23:41 -0400 Subject: [PATCH 041/198] jump relative to the current position in hexview pane --- .../corecomponents/DataContentViewerHex.form | 5 +- .../corecomponents/DataContentViewerHex.java | 52 +++++++++++++++++-- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form index e764f8ee56..0939f572fc 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form @@ -137,6 +137,9 @@ + + + @@ -146,7 +149,7 @@ - +
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index 1f6e604ea1..c60d1abe62 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -28,7 +28,10 @@ import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JTextPane; +import javax.swing.text.BadLocationException; +import javax.swing.text.Utilities; import org.openide.nodes.Node; +import org.openide.util.Exceptions; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.datamodel.DataConversion; @@ -94,6 +97,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont return (getSize().width < 400); }}; this.outputViewPane.setBackground(new java.awt.Color(255, 255, 255)); // to make sure the background color is white + this.outputViewPane.requestFocusInWindow(); totalPageLabel = new javax.swing.JLabel(); ofLabel = new javax.swing.JLabel(); currentPageLabel = new javax.swing.JLabel(); @@ -116,6 +120,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont outputViewPane.setEditable(false); outputViewPane.setFont(new java.awt.Font("Courier New", 0, 11)); // NOI18N + outputViewPane.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); outputViewPane.setMinimumSize(new java.awt.Dimension(700, 20)); outputViewPane.setPreferredSize(new java.awt.Dimension(700, 400)); jScrollPane1.setViewportView(outputViewPane); @@ -289,13 +294,54 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont setDataViewByPageNumber(pageNumber); }//GEN-LAST:event_goToPageTextFieldActionPerformed - private void goToOffsetTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToOffsetTextFieldActionPerformed + /*** + * Calculates the offset relative to the current caret position. + * @param add Pass true if the user provided offset is to be added with the offset of the caret position. Else false. + * @return + */ + private long getOffset(boolean add) { String hexOffsetStr = goToOffsetTextField.getText(); + String userProvidedRelativeOffsetStr; + String userSelectedLine; + userProvidedRelativeOffsetStr = hexOffsetStr.substring(hexOffsetStr.indexOf("+")); // NON-NLS + try { + // get the selected line. Extract the current hex offset location. + userSelectedLine = outputViewPane.getText().subSequence( + Utilities.getRowStart(outputViewPane, outputViewPane.getCaretPosition()), + Utilities.getRowEnd(outputViewPane, outputViewPane.getCaretPosition())) + .toString(); + // NOTE: This needs to change if the outputFormat of outputViewPane changes. + String hexForUserSelectedLine = userSelectedLine.substring(0, userSelectedLine.indexOf(":")); + if (add) { + return Long.decode(hexForUserSelectedLine) + Long.decode(userProvidedRelativeOffsetStr); + } else { + return Long.decode(hexForUserSelectedLine) - Long.decode(userProvidedRelativeOffsetStr); + } + } catch (BadLocationException ex) { + // thrown in case the caret location is out of the range of the outputViewPane. + // Log it? + } + return 0L; + } + + private void goToOffsetTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToOffsetTextFieldActionPerformed + long offset; + // jump forward relative to the current location. + if (goToOffsetTextField.getText().startsWith("+")) { + offset = getOffset(true); + } else + // jump backward relative to the current location. + if (goToOffsetTextField.getText().startsWith("-")) { + offset = getOffset(false); + } else { + // jump to an absolute location. + offset = Long.decode(goToOffsetTextField.getText()); + } + try { - long offset = Long.decode(hexOffsetStr); setDataViewByOffset(offset); } catch (NumberFormatException ex) { - JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(), "DataContentViewerHex.goToOffsetTextField.msgDlg", hexOffsetStr)); + JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(), "DataContentViewerHex.goToOffsetTextField.msgDlg", goToOffsetTextField.getText())); } }//GEN-LAST:event_goToOffsetTextFieldActionPerformed From 86e1ca1886e571604645189abb1674592fe7f900 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 16 Jun 2015 11:14:44 -0400 Subject: [PATCH 042/198] make new DeleteFollowUpTag action; use Set instead of List to prevent duplicate files in groups --- .../actions/DeleteFollowUpTag.java | 86 +++++++++++++++++++ .../imagegallery/datamodel/DrawableDB.java | 10 +-- .../imagegallery/grouping/DrawableGroup.java | 4 +- .../imagegallery/grouping/GroupManager.java | 30 ++++--- .../imagegallery/gui/DrawableViewBase.java | 55 ++++++------ 5 files changed, 138 insertions(+), 47 deletions(-) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java new file mode 100644 index 0000000000..0399b545ed --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java @@ -0,0 +1,86 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery.actions; + +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import javafx.event.ActionEvent; +import org.controlsfx.control.action.Action; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; +import org.sleuthkit.autopsy.ingest.IngestServices; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * + */ +public class DeleteFollowUpTag extends Action { + + private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTag.class.getName()); + private final long fileID; + private final DrawableFile file; + + public DeleteFollowUpTag(DrawableFile file) { + super("Delete Follow Up Tag"); + this.file = file; + this.fileID = file.getId(); + + setEventHandler((ActionEvent t) -> { + deleteFollowupTag(); + }); + } + + /** + * + * @param fileID1 the value of fileID1 + * + * @throws IllegalStateException + */ + private void deleteFollowupTag() throws IllegalStateException { + + final ImageGalleryController controller = ImageGalleryController.getDefault(); + final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + try { + // remove file from old category group + controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); + + List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); + for (ContentTag ct : contentTagsByContent) { + if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { + sleuthKitCase.deleteContentTag(ct); + } + } + IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); + } + } +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index a5f91bb9d3..ac1f6c99eb 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -698,7 +698,7 @@ public final class DrawableDB { public Boolean isGroupAnalyzed(GroupKey gk) { dbReadLock(); try { - List fileIDsInGroup = getFileIDsInGroup(gk); + Set fileIDsInGroup = getFileIDsInGroup(gk); try { // In testing, this method appears to be a lot faster than doing one large select statement @@ -747,10 +747,10 @@ public final class DrawableDB { * * @throws TskCoreException */ - public List findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException { + public Set findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException { Statement statement = null; ResultSet rs = null; - List ret = new ArrayList<>(); + Set ret = new HashSet<>(); dbReadLock(); try { statement = con.createStatement(); @@ -984,7 +984,7 @@ public final class DrawableDB { } } - public List getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { + public Set getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { if (groupKey.getAttribute().isDBColumn) { switch (groupKey.getAttribute().attrName) { @@ -994,7 +994,7 @@ public final class DrawableDB { return groupManager.getFileIDsWithTag((TagName) groupKey.getValue()); } } - List files = new ArrayList<>(); + Set files = new HashSet<>(); dbReadLock(); try { PreparedStatement statement = getGroupStatment(groupKey.getAttribute()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index e6d1f3dad8..b59a1b8edd 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -18,8 +18,8 @@ */ package org.sleuthkit.autopsy.imagegallery.grouping; -import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.logging.Level; import javafx.beans.property.ReadOnlyBooleanWrapper; import javafx.collections.FXCollections; @@ -70,7 +70,7 @@ public class DrawableGroup implements Comparable { return groupKey.getValueDisplayName(); } - DrawableGroup(GroupKey groupKey, List filesInGroup, boolean seen) { + DrawableGroup(GroupKey groupKey, Set filesInGroup, boolean seen) { this.groupKey = groupKey; this.fileIDs.setAll(filesInGroup); this.seen.set(seen); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index ec35f6bb60..68e1044dbc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -40,6 +40,7 @@ import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javax.swing.SortOrder; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.netbeans.api.progress.ProgressHandle; @@ -241,8 +242,9 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * * @return the new DrawableGroup for the given key */ - public DrawableGroup makeGroup(GroupKey groupKey, List files) { - List newFiles = files == null ? new ArrayList<>() : files; + public DrawableGroup makeGroup(GroupKey groupKey, Set files) { + + Set newFiles = ObjectUtils.defaultIfNull(files, new HashSet()); final boolean groupSeen = db.isGroupSeen(groupKey); DrawableGroup g = new DrawableGroup(groupKey, newFiles, groupSeen); @@ -303,7 +305,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } - public synchronized void populateAnalyzedGroup(final GroupKey groupKey, List filesInGroup) { + public synchronized void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup) { populateAnalyzedGroup(groupKey, filesInGroup, null); } @@ -314,7 +316,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @param groupKey * @param filesInGroup */ - private synchronized > void populateAnalyzedGroup(final GroupKey groupKey, List filesInGroup, ReGroupTask task) { + private synchronized > void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup, ReGroupTask task) { /* if this is not part of a regroup task or it is but the task is not * cancelled... @@ -352,7 +354,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * this * group if they are all analyzed */ - public List checkAnalyzed(final GroupKey groupKey) { + public Set checkAnalyzed(final GroupKey groupKey) { try { /* for attributes other than path we can't be sure a group is fully * analyzed because we don't know all the files that will be a part @@ -464,7 +466,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } - public List getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { + public Set getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { switch (groupKey.getAttribute().attrName) { //these cases get special treatment case CATEGORY: @@ -481,12 +483,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { // @@@ This was kind of slow in the profiler. Maybe we should cache it. // Unless the list of file IDs is necessary, use countFilesWithCategory() to get the counts. - public List getFileIDsWithCategory(Category category) throws TskCoreException { + public Set getFileIDsWithCategory(Category category) throws TskCoreException { try { if (category == Category.ZERO) { - List files = new ArrayList<>(); + Set files = new HashSet<>(); TagName[] tns = {Category.FOUR.getTagName(), Category.THREE.getTagName(), Category.TWO.getTagName(), Category.ONE.getTagName(), Category.FIVE.getTagName()}; for (TagName tn : tns) { List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tn); @@ -500,7 +502,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { return db.findAllFileIdsWhere("obj_id NOT IN (" + StringUtils.join(files, ',') + ")"); } else { - List files = new ArrayList<>(); + Set files = new HashSet<>(); List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(category.getTagName()); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { @@ -516,9 +518,9 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } - public List getFileIDsWithTag(TagName tagName) throws TskCoreException { + public Set getFileIDsWithTag(TagName tagName) throws TskCoreException { try { - List files = new ArrayList<>(); + Set files = new HashSet<>(); List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { @@ -636,7 +638,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { // It may be that this was the last unanalyzed file in the group, so test // whether the group is now fully analyzed. //TODO: use method in groupmanager ? - List checkAnalyzed = checkAnalyzed(gk); + Set checkAnalyzed = checkAnalyzed(gk); if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui populateAnalyzedGroup(gk, checkAnalyzed); } @@ -674,7 +676,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } else { //if there wasn't already a group check if there should be one now //TODO: use method in groupmanager ? - List checkAnalyzed = checkAnalyzed(gk); + Set checkAnalyzed = checkAnalyzed(gk); if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui populateAnalyzedGroup(gk, checkAnalyzed); } @@ -759,7 +761,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { //check if this group is analyzed final GroupKey groupKey = new GroupKey<>(groupBy, val); - List checkAnalyzed = checkAnalyzed(groupKey); + Set checkAnalyzed = checkAnalyzed(groupKey); if (checkAnalyzed != null) { // != null => the group is analyzed, so add it to the ui // makeGroup will create the group and add it to the map groupMap, but does not diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 23164f41fb..e866742505 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -22,8 +22,6 @@ package org.sleuthkit.autopsy.imagegallery.gui; import com.google.common.eventbus.Subscribe; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.List; import java.util.Objects; import java.util.logging.Level; import javafx.application.Platform; @@ -64,21 +62,16 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; +import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTag; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -272,28 +265,38 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie LOGGER.log(Level.SEVERE, "Failed to add follow up tag. Could not load TagName.", ex); } } else { - //TODO: convert this to an action! - final ImageGalleryController controller = ImageGalleryController.getDefault(); - try { - // remove file from old category group - controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); - - List contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(file); - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { - Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(ct); - } - } - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); - } + new DeleteFollowUpTag(file).handle(t); +// deleteFollowupTag(fileID); } - }); } +// /** +// * +// * @param fileID1 the value of fileID1 +// * +// * @throws IllegalStateException +// */ +// private void deleteFollowupTag(final Long fileID1) throws IllegalStateException { +// //TODO: convert this to an action! +// final ImageGalleryController controller = ImageGalleryController.getDefault(); +// try { +// // remove file from old category group +// controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID1); +// +// List contentTagsByContent = controller.getSleuthKitCase().getContentTagsByContent(file); +// for (ContentTag ct : contentTagsByContent) { +// if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { +// controller.getSleuthKitCase().deleteContentTag(ct); +// } +// } +// IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS +// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID1), DrawableAttribute.TAGS)); +// } catch (TskCoreException ex) { +// LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); +// } +// } + @Override public DrawableFile getFile() { if (fileID != null) { From a6c825996f4162d703c08523e6f584d8ed70cc53 Mon Sep 17 00:00:00 2001 From: APriestman Date: Tue, 16 Jun 2015 12:14:33 -0400 Subject: [PATCH 043/198] Switching to a different version of controlsfx --- CoreLibs/ivy.xml | 3 ++- CoreLibs/nbproject/project.properties | 6 +++--- CoreLibs/nbproject/project.xml | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CoreLibs/ivy.xml b/CoreLibs/ivy.xml index 99c18a955b..a4cc0075e7 100644 --- a/CoreLibs/ivy.xml +++ b/CoreLibs/ivy.xml @@ -1,4 +1,5 @@ + @@ -36,7 +37,7 @@ - + diff --git a/CoreLibs/nbproject/project.properties b/CoreLibs/nbproject/project.properties index e1ebd74bb7..53bd6cf9e0 100644 --- a/CoreLibs/nbproject/project.properties +++ b/CoreLibs/nbproject/project.properties @@ -12,7 +12,7 @@ file.reference.commons-lang3-3.0.jar=release/modules/ext/commons-lang3-3.0.jar file.reference.commons-logging-1.1.2-javadoc.jar=release/modules/ext/commons-logging-1.1.2-javadoc.jar file.reference.commons-logging-1.1.2-sources.jar=release/modules/ext/commons-logging-1.1.2-sources.jar file.reference.commons-logging-1.1.2.jar=release/modules/ext/commons-logging-1.1.2.jar -file.reference.controlsfx-8.20.9.jar=release/modules/ext/controlsfx-8.20.9.jar +file.reference.controlsfx-8.40.9.jar=release/modules/ext/controlsfx-8.40.9.jar file.reference.dom4j-1.6.1.jar=release/modules/ext/dom4j-1.6.1.jar file.reference.geronimo-jms_1.1_spec-1.0.jar=release/modules/ext/geronimo-jms_1.1_spec-1.0.jar file.reference.gson-1.4.jar=release/modules/ext/gson-1.4.jar @@ -59,6 +59,6 @@ file.reference.xml-apis-1.0.b2.jar=release/modules/ext/xml-apis-1.0.b2.jar file.reference.xmlbeans-2.3.0.jar=release/modules/ext/xmlbeans-2.3.0.jar javac.source=1.7 javac.compilerargs=-Xlint -Xlint:-serial -javadoc.reference.controlsfx-8.20.9.jar=release/modules/ext/controlsfx-8.20.9-javadoc.jar +javadoc.reference.controlsfx-8.20.9.jar=release/modules/ext/controlsfx-8.40.9-javadoc.jar nbm.needs.restart=true -source.reference.controlsfx-8.20.9.jar=release/modules/ext/controlsfx-8.20.9-sources.jar +source.reference.controlsfx-8.20.9.jar=release/modules/ext/controlsfx-8.40.9-sources.jar diff --git a/CoreLibs/nbproject/project.xml b/CoreLibs/nbproject/project.xml index ea65c1e7f9..a76fed8a8f 100644 --- a/CoreLibs/nbproject/project.xml +++ b/CoreLibs/nbproject/project.xml @@ -769,8 +769,8 @@ release/modules/ext/slf4j-simple-1.6.1.jar
- ext/controlsfx-8.20.9.jar - release/modules/ext/controlsfx-8.20.9.jar + ext/controlsfx-8.40.9.jar + release/modules/ext/controlsfx-8.40.9.jar ext/commons-lang3-3.0-javadoc.jar From f2e1c84f3677c9ade86dae9a3c8c4b4905002a07 Mon Sep 17 00:00:00 2001 From: APriestman Date: Tue, 16 Jun 2015 12:16:54 -0400 Subject: [PATCH 044/198] Cleanup --- Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java index 7e1dd9aa88..3223e29382 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentUtils.java @@ -139,7 +139,7 @@ public final class ContentUtils { return TimeZone.getDefault(); } } - } catch (TskException | NullPointerException ex) { + } catch (TskException ex) { return TimeZone.getDefault(); } } From aad2335b34403bd14c2071c15bc689d4dd13a1ae Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 16 Jun 2015 12:51:06 -0400 Subject: [PATCH 045/198] cleanup Follow Up tag and Category TagNames (prevent short name version from being added, by removing commas) --- .../imagegallery/ImageGalleryController.java | 1 + .../autopsy/imagegallery/TagUtils.java | 31 +++++++++++-------- .../actions/DeleteFollowUpTag.java | 2 ++ .../imagegallery/datamodel/Category.java | 19 +++++++----- .../datamodel/CategoryManager.java | 2 ++ 5 files changed, 35 insertions(+), 20 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index b93f362dae..8864ddc264 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -371,6 +371,7 @@ public final class ImageGalleryController { historyManager.clear(); }); Category.clearTagNames(); + TagUtils.clearFollowUpTagName(); Toolbar.getDefault().reset(); groupManager.clear(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java index b5eb4cfc25..8e9e8cfc98 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java @@ -20,10 +20,12 @@ package org.sleuthkit.autopsy.imagegallery; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; +import java.util.stream.Collectors; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.control.MenuItem; @@ -43,34 +45,36 @@ import org.sleuthkit.datamodel.TskCoreException; */ public class TagUtils { - private static final String follow_Up = "Follow Up"; + private static final String FOLLOW_UP = "Follow Up"; private static TagName followUpTagName; + /** + * Use when closing a case to make sure everything is re-initialized in the + * next case. + */ + public static void clearFollowUpTagName() { + followUpTagName = null; + } + private final static List listeners = new ArrayList<>(); synchronized public static TagName getFollowUpTagName() throws TskCoreException { if (followUpTagName == null) { - followUpTagName = getTagName(follow_Up); + followUpTagName = getTagName(FOLLOW_UP); } return followUpTagName; } static public Collection getNonCategoryTagNames() { - List nonCatTagNames = new ArrayList<>(); - List allTagNames; try { - allTagNames = Case.getCurrentCase().getServices().getTagsManager().getAllTagNames(); - for (TagName tn : allTagNames) { - if (tn.getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) { - nonCatTagNames.add(tn); - } - } + return Case.getCurrentCase().getServices().getTagsManager().getAllTagNames().stream() + .filter(Category::isCategoryTagName) + .collect(Collectors.toSet()); } catch (TskCoreException | IllegalStateException ex) { Logger.getLogger(TagUtils.class.getName()).log(Level.WARNING, "couldn't access case", ex); } - - return nonCatTagNames; + return Collections.emptySet(); } synchronized static public TagName getTagName(String displayName) throws TskCoreException { @@ -94,7 +98,7 @@ public class TagUtils { } public static void fireChange(Collection ids) { - Set listenersCopy = new HashSet(listeners); + Set listenersCopy = new HashSet<>(listeners); synchronized (listeners) { listenersCopy.addAll(listeners); } @@ -132,6 +136,7 @@ public class TagUtils { } public static interface TagListener { + public void handleTagsChanged(Collection ids); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java index 0399b545ed..0fe88de953 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java @@ -78,6 +78,8 @@ public class DeleteFollowUpTag extends Action { } } IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + + //make sure rest of ui hears category change. controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 780e851876..4839537731 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -34,16 +34,17 @@ import org.sleuthkit.datamodel.TskCoreException; */ public enum Category implements Comparable { - ZERO(Color.LIGHTGREY, 0, "CAT-0, Uncategorized"), - ONE(Color.RED, 1, "CAT-1, Child Exploitation (Illegal)"), - TWO(Color.ORANGE, 2, "CAT-2, Child Exploitation (Non-Illegal/Age Difficult)"), - THREE(Color.YELLOW, 3, "CAT-3, CGI/Animation (Child Exploitive)"), - FOUR(Color.BISQUE, 4, "CAT-4, Exemplar/Comparison (Internal Use Only)"), - FIVE(Color.GREEN, 5, "CAT-5, Non-pertinent"); + ZERO(Color.LIGHTGREY, 0, "CAT-0: Uncategorized"), + ONE(Color.RED, 1, "CAT-1: Child Exploitation (Illegal)"), + TWO(Color.ORANGE, 2, "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"), + THREE(Color.YELLOW, 3, "CAT-3: CGI/Animation (Child Exploitive)"), + FOUR(Color.BISQUE, 4, "CAT-4: Exemplar/Comparison (Internal Use Only)"), + FIVE(Color.GREEN, 5, "CAT-5: Non-pertinent"); /** map from displayName to enum value */ private static final Map nameMap - = Stream.of(values()).collect(Collectors.toMap(Category::getDisplayName, + = Stream.of(values()).collect(Collectors.toMap( + Category::getDisplayName, Function.identity())); public static final String CATEGORY_PREFIX = "CAT-"; @@ -65,6 +66,10 @@ public enum Category implements Comparable { Category.FIVE.tagName = null; } + public static boolean isCategoryTagName(TagName tName) { + return nameMap.containsKey(tName.getDisplayName()); + } + private TagName tagName; private final Color color; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 699af41bbb..f6e0404c6e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -26,6 +26,7 @@ import java.util.Collection; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.TagUtils; /** * Provides a cached view of the number of files per category, and fires @@ -75,6 +76,7 @@ public class CategoryManager { this.db = db; categoryCounts.invalidateAll(); Category.clearTagNames(); + TagUtils.clearFollowUpTagName(); } /** From 918e454596279b236a4393a2ed78c5cfa481a2cb Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 16 Jun 2015 12:52:18 -0400 Subject: [PATCH 046/198] update to ControlsFX 8.40.9 --- CoreLibs/ivy.xml | 2 +- CoreLibs/nbproject/project.properties | 6 +++--- CoreLibs/nbproject/project.xml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CoreLibs/ivy.xml b/CoreLibs/ivy.xml index 99c18a955b..0274b7fb7d 100644 --- a/CoreLibs/ivy.xml +++ b/CoreLibs/ivy.xml @@ -36,7 +36,7 @@ - + diff --git a/CoreLibs/nbproject/project.properties b/CoreLibs/nbproject/project.properties index e1ebd74bb7..8f133ac7fa 100644 --- a/CoreLibs/nbproject/project.properties +++ b/CoreLibs/nbproject/project.properties @@ -12,7 +12,7 @@ file.reference.commons-lang3-3.0.jar=release/modules/ext/commons-lang3-3.0.jar file.reference.commons-logging-1.1.2-javadoc.jar=release/modules/ext/commons-logging-1.1.2-javadoc.jar file.reference.commons-logging-1.1.2-sources.jar=release/modules/ext/commons-logging-1.1.2-sources.jar file.reference.commons-logging-1.1.2.jar=release/modules/ext/commons-logging-1.1.2.jar -file.reference.controlsfx-8.20.9.jar=release/modules/ext/controlsfx-8.20.9.jar +file.reference.controlsfx-8.40.9.jar=release/modules/ext/controlsfx-8.40.9.jar file.reference.dom4j-1.6.1.jar=release/modules/ext/dom4j-1.6.1.jar file.reference.geronimo-jms_1.1_spec-1.0.jar=release/modules/ext/geronimo-jms_1.1_spec-1.0.jar file.reference.gson-1.4.jar=release/modules/ext/gson-1.4.jar @@ -59,6 +59,6 @@ file.reference.xml-apis-1.0.b2.jar=release/modules/ext/xml-apis-1.0.b2.jar file.reference.xmlbeans-2.3.0.jar=release/modules/ext/xmlbeans-2.3.0.jar javac.source=1.7 javac.compilerargs=-Xlint -Xlint:-serial -javadoc.reference.controlsfx-8.20.9.jar=release/modules/ext/controlsfx-8.20.9-javadoc.jar +javadoc.reference.controlsfx-8.40.9.jar=release/modules/ext/controlsfx-8.40.9-javadoc.jar nbm.needs.restart=true -source.reference.controlsfx-8.20.9.jar=release/modules/ext/controlsfx-8.20.9-sources.jar +source.reference.controlsfx-8.40.9.jar=release/modules/ext/controlsfx-8.40.9-sources.jar diff --git a/CoreLibs/nbproject/project.xml b/CoreLibs/nbproject/project.xml index ea65c1e7f9..a76fed8a8f 100644 --- a/CoreLibs/nbproject/project.xml +++ b/CoreLibs/nbproject/project.xml @@ -769,8 +769,8 @@ release/modules/ext/slf4j-simple-1.6.1.jar - ext/controlsfx-8.20.9.jar - release/modules/ext/controlsfx-8.20.9.jar + ext/controlsfx-8.40.9.jar + release/modules/ext/controlsfx-8.40.9.jar ext/commons-lang3-3.0-javadoc.jar From 31166c39c2afb4f3f7440598e494bc480a53984a Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Tue, 16 Jun 2015 14:14:28 -0400 Subject: [PATCH 047/198] embedded file extractor module refactored --- .../EmbeddedFileExtractorIngestModule.java | 32 ++----------------- .../embeddedfileextractor/ImageExtractor.java | 20 +++++++++--- .../SevenZipExtractor.java | 20 ++++++++++-- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java index 0f5f4ccd72..c66c320621 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java @@ -49,8 +49,8 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule private long jobId; private final static IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); - String moduleDirRelative; - String moduleDirAbsolute; + private String moduleDirRelative; + private String moduleDirAbsolute; private boolean archivextraction; private boolean imageExtraction; @@ -116,22 +116,6 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule return ProcessResult.OK; } - //check if already has derived files, skip - try { - if (abstractFile.hasChildren()) { - //check if local unpacked dir exists - final String uniqueFileName = getUniqueName(abstractFile); - final String localRootAbsPath = getLocalRootAbsPath(uniqueFileName); - if (new File(localRootAbsPath).exists()) { - logger.log(Level.INFO, "File already has been processed as it has children and local unpacked file, skipping: {0}", abstractFile.getName()); //NON-NLS - return ProcessResult.OK; - } - } - } catch (TskCoreException e) { - logger.log(Level.INFO, "Error checking if file already has been processed, skipping: {0}", abstractFile.getName()); //NON-NLS - return ProcessResult.OK; - } - // call the archive extractor if archiveextraction flag is set. if (this.archivextraction) { archiveExtractor.unpack(abstractFile); @@ -157,17 +141,7 @@ public final class EmbeddedFileExtractorIngestModule implements FileIngestModule * @param archiveFile * @return */ - protected static String getUniqueName(AbstractFile archiveFile) { + static String getUniqueName(AbstractFile archiveFile) { return archiveFile.getName() + "_" + archiveFile.getId(); } - - /** - * Get local abs path to the unpacked archive root - * - * @param localRootRelPath relative path to archive, from getUniqueName() - * @return - */ - String getLocalRootAbsPath(String localRootRelPath) { - return moduleDirAbsolute + File.separator + localRootRelPath; - } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java index 419c438968..6ec9b2f973 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java @@ -60,8 +60,8 @@ class ImageExtractor { private final String UNKNOWN_NAME_PREFIX = "image_"; private final FileTypeDetector fileTypeDetector; - String moduleDirRelative; - String moduleDirAbsolute; + private String moduleDirRelative; + private String moduleDirAbsolute; /** * Enum of mimetypes which support image extraction */ @@ -131,7 +131,7 @@ class ImageExtractor { * @param format * @param abstractFile The abstract file to be processed. */ - protected void extractImage(AbstractFile abstractFile) { + void extractImage(AbstractFile abstractFile) { // // switchcase for different supported formats // process abstractFile according to the format by calling appropriate methods. @@ -139,7 +139,19 @@ class ImageExtractor { List listOfExtractedImages = null; List listOfExtractedImageAbstractFiles = null; this.parentFileName = EmbeddedFileExtractorIngestModule.getUniqueName(abstractFile); - + //check if already has derived files, skip + try { + if (abstractFile.hasChildren()) { + //check if local unpacked dir exists + if (new File(getOutputFolderPath(parentFileName)).exists()) { + logger.log(Level.INFO, "File already has been processed as it has children and local unpacked file, skipping: {0}", abstractFile.getName()); //NON-NLS + return; + } + } + } catch (TskCoreException e) { + logger.log(Level.INFO, "Error checking if file already has been processed, skipping: {0}", parentFileName); //NON-NLS + return; + } switch (abstractFileExtractionFormat) { case DOC: listOfExtractedImages = extractImagesFromDoc(abstractFile); diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 1da0949508..1dc6bbb5a4 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -80,8 +80,8 @@ class SevenZipExtractor { //counts archive depth private ArchiveDepthCountTree archiveDepthCountTree; - String moduleDirRelative; - String moduleDirAbsolute; + private String moduleDirRelative; + private String moduleDirAbsolute; private String getLocalRootAbsPath(String uniqueArchiveFileName) { return moduleDirAbsolute + File.separator + uniqueArchiveFileName; @@ -268,7 +268,21 @@ class SevenZipExtractor { * @param archiveFile file to unpack * @return list of unpacked derived files */ - protected void unpack(AbstractFile archiveFile) { + void unpack(AbstractFile archiveFile) { + //check if already has derived files, skip + try { + if (archiveFile.hasChildren()) { + //check if local unpacked dir exists + if (new File(EmbeddedFileExtractorIngestModule.getUniqueName(archiveFile)).exists()) { + logger.log(Level.INFO, "File already has been processed as it has children and local unpacked file, skipping: {0}", archiveFile.getName()); //NON-NLS + return; + } + } + } catch (TskCoreException e) { + logger.log(Level.INFO, "Error checking if file already has been processed, skipping: {0}", archiveFile.getName()); //NON-NLS + return; + } + List unpackedFiles = Collections.emptyList(); //recursion depth check for zip bomb From fe95cc21d774e0c72712936bec77165cdcfe18db Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 16 Jun 2015 16:53:16 -0400 Subject: [PATCH 048/198] clean up and refactor code related to Tagging and actions; move away from singleton by injecting controller rather than using getDefault(); use EventBus in DrawableTagsManager (used to be TagUtils) requires equal and hashcode method implemented on TagName --- .../imagegallery/DrawableTagsManager.java | 161 ++++++++++++++++++ .../imagegallery/ImageGalleryController.java | 14 +- .../ImageGalleryTopComponent.java | 3 +- .../autopsy/imagegallery/TagUtils.java | 142 --------------- .../autopsy/imagegallery/TagsChangeEvent.java | 41 +++++ .../actions/AddDrawableTagAction.java | 45 ++--- .../imagegallery/actions/AddTagAction.java | 9 +- .../actions/CategorizeAction.java | 41 +++-- ...eFollowUpTag.java => DeleteTagAction.java} | 42 +++-- .../imagegallery/datamodel/Category.java | 19 --- .../datamodel/CategoryChangeEvent.java | 10 +- .../datamodel/CategoryManager.java | 29 +++- .../imagegallery/datamodel/DrawableDB.java | 15 +- .../imagegallery/grouping/GroupKey.java | 2 +- .../imagegallery/grouping/GroupManager.java | 36 ++-- .../imagegallery/gui/DrawableTile.java | 7 +- .../imagegallery/gui/DrawableView.java | 12 +- .../imagegallery/gui/DrawableViewBase.java | 62 +++---- .../autopsy/imagegallery/gui/GroupPane.java | 39 +++-- .../autopsy/imagegallery/gui/GuiUtils.java | 62 +++++++ .../imagegallery/gui/MetaDataPane.java | 20 ++- .../imagegallery/gui/SlideShowView.java | 12 +- .../autopsy/imagegallery/gui/Toolbar.java | 28 +-- 23 files changed, 494 insertions(+), 357 deletions(-) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/{DeleteFollowUpTag.java => DeleteTagAction.java} (66%) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java new file mode 100644 index 0000000000..3c1dd42de3 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -0,0 +1,161 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery; + +import com.google.common.eventbus.EventBus; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.stream.Collectors; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Manages Tags, Tagging, and the relationship between Categories and Tags in + * the autopsy Db. delegates some, work to the backing {@link TagsManager}. + */ +public class DrawableTagsManager { + + private static final String FOLLOW_UP = "Follow Up"; + + private TagsManager autopsyTagsManager; + + /** Used to distribute {@link TagsChangeEvent}s */ + private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); + + /** The tag name corresponging to the "built-in" tag "Follow Up" */ + private TagName followUpTagName; + + public DrawableTagsManager(TagsManager autopsyTagsManager) { + this.autopsyTagsManager = autopsyTagsManager; + + } + + /** + * assign a new TagsManager to back this one, ie when the current case + * changes + * + * @param autopsyTagsManager + */ + public synchronized void setAutopsyTagsManager(TagsManager autopsyTagsManager) { + this.autopsyTagsManager = autopsyTagsManager; + clearFollowUpTagName(); + } + + /** + * Use when closing a case to make sure everything is re-initialized in the + * next case. + */ + public synchronized void clearFollowUpTagName() { + followUpTagName = null; + } + + /** + * fire a CategoryChangeEvent with the given fileIDs + * + * @param fileIDs + */ + public final void fireChange(Collection fileIDs) { + tagsEventBus.post(new TagsChangeEvent(fileIDs)); + } + + /** + * register an object to receive CategoryChangeEvents + * + * @param listner + */ + public void registerListener(Object listner) { + tagsEventBus.register(listner); + } + + /** + * unregister an object from receiving CategoryChangeEvents + * + * @param listener + */ + public void unregisterListener(Object listener) { + tagsEventBus.unregister(listener); + } + + /** + * get the (cached) follow up TagName + * + * @return + * + * @throws TskCoreException + */ + synchronized public TagName getFollowUpTagName() throws TskCoreException { + if (followUpTagName == null) { + followUpTagName = getTagName(FOLLOW_UP); + } + return followUpTagName; + } + + public Collection getNonCategoryTagNames() { + try { + return autopsyTagsManager.getAllTagNames().stream() + .filter(Category::isCategoryTagName) + .collect(Collectors.toSet()); + } catch (TskCoreException | IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + } + return Collections.emptySet(); + } + + public synchronized TagName getTagName(String displayName) throws TskCoreException { + try { + for (TagName tn : autopsyTagsManager.getAllTagNames()) { + if (displayName.equals(tn.getDisplayName())) { + return tn; + } + } + try { + return autopsyTagsManager.addTagName(displayName); + } catch (TagsManager.TagNameAlreadyExistsException ex) { + throw new TskCoreException("tagame exists but wasn't found", ex); + } + } catch (IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); + throw new TskCoreException("Case was closed out from underneath", ex); + } + } + + public synchronized TagName getTagName(Category cat) { + try { + return getTagName(cat.getDisplayName()); + } catch (TskCoreException ex) { + return null; + } + } + + public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { + autopsyTagsManager.addContentTag(file, tagName, comment); + } + + public List getContentTagsByTagName(TagName t) throws TskCoreException { + return autopsyTagsManager.getContentTagsByTagName(t); + } + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 8864ddc264..ae7a169e96 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -126,7 +126,8 @@ public final class ImageGalleryController { private final GroupManager groupManager = new GroupManager(this); private final HashSetManager hashSetManager = new HashSetManager(); - private final CategoryManager categoryManager = new CategoryManager(); + private final CategoryManager categoryManager = new CategoryManager(this); + private final DrawableTagsManager tagsManager = new DrawableTagsManager(null); private StackPane fullUIStackPane; @@ -344,7 +345,7 @@ public final class ImageGalleryController { * @param theNewCase the case to configure the controller for */ public synchronized void setCase(Case theNewCase) { - this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), getSleuthKitCase()); + this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); @@ -356,6 +357,7 @@ public final class ImageGalleryController { groupManager.setDB(db); hashSetManager.setDb(db); categoryManager.setDb(db); + tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); SummaryTablePane.getDefault().refresh(); } @@ -371,9 +373,9 @@ public final class ImageGalleryController { historyManager.clear(); }); Category.clearTagNames(); - TagUtils.clearFollowUpTagName(); + tagsManager.clearFollowUpTagName(); - Toolbar.getDefault().reset(); + Toolbar.getDefault(this).reset(); groupManager.clear(); if (db != null) { db.closeDBCon(); @@ -489,6 +491,10 @@ public final class ImageGalleryController { return categoryManager; } + public DrawableTagsManager getTagsManager() { + return tagsManager; + } + // @@@ REVIEW IF THIS SHOLD BE STATIC... //TODO: concept seems like the controller deal with how much work to do at a given time // @@@ review this class for synchronization issues (i.e. reset and cancel being called, add, etc.) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java index 6aa431fb4c..e5c2bb3bd6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java @@ -34,7 +34,6 @@ import org.openide.util.NbBundle.Messages; import org.openide.windows.Mode; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.gui.GroupPane; import org.sleuthkit.autopsy.imagegallery.gui.MetaDataPane; @@ -145,7 +144,7 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl fullUIStack.getChildren().add(borderPane); splitPane = new SplitPane(); borderPane.setCenter(splitPane); - borderPane.setTop(Toolbar.getDefault()); + borderPane.setTop(Toolbar.getDefault(controller)); borderPane.setBottom(new StatusBar(controller)); metaDataTable = new MetaDataPane(controller); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java deleted file mode 100644 index 8e9e8cfc98..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import java.util.stream.Collectors; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.scene.control.MenuItem; -import javafx.scene.control.SplitMenuButton; -import javafx.scene.image.ImageView; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Contains static methods for dealing with Tags in ImageGallery - */ -public class TagUtils { - - private static final String FOLLOW_UP = "Follow Up"; - - private static TagName followUpTagName; - - /** - * Use when closing a case to make sure everything is re-initialized in the - * next case. - */ - public static void clearFollowUpTagName() { - followUpTagName = null; - } - - private final static List listeners = new ArrayList<>(); - - synchronized public static TagName getFollowUpTagName() throws TskCoreException { - if (followUpTagName == null) { - followUpTagName = getTagName(FOLLOW_UP); - } - return followUpTagName; - } - - static public Collection getNonCategoryTagNames() { - try { - return Case.getCurrentCase().getServices().getTagsManager().getAllTagNames().stream() - .filter(Category::isCategoryTagName) - .collect(Collectors.toSet()); - } catch (TskCoreException | IllegalStateException ex) { - Logger.getLogger(TagUtils.class.getName()).log(Level.WARNING, "couldn't access case", ex); - } - return Collections.emptySet(); - } - - synchronized static public TagName getTagName(String displayName) throws TskCoreException { - try { - final TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - - for (TagName tn : tagsManager.getAllTagNames()) { - if (displayName.equals(tn.getDisplayName())) { - return tn; - } - } - try { - return tagsManager.addTagName(displayName); - } catch (TagsManager.TagNameAlreadyExistsException ex) { - throw new TskCoreException("tagame exists but wasn't found", ex); - } - } catch (IllegalStateException ex) { - Logger.getLogger(TagUtils.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); - throw new TskCoreException("Case was closed out from underneath", ex); - } - } - - public static void fireChange(Collection ids) { - Set listenersCopy = new HashSet<>(listeners); - synchronized (listeners) { - listenersCopy.addAll(listeners); - } - for (TagListener list : listenersCopy) { - list.handleTagsChanged(ids); - } - } - - public static void registerListener(TagListener aThis) { - synchronized (listeners) { - listeners.add(aThis); - } - } - - public static void unregisterListener(TagListener aThis) { - synchronized (listeners) { - listeners.remove(aThis); - } - } - - /** - * @param tn the value of tn - */ - static public MenuItem createSelTagMenuItem(final TagName tn, final SplitMenuButton tagSelectedMenuButton) { - final MenuItem menuItem = new MenuItem(tn.getDisplayName(), new ImageView(DrawableAttribute.TAGS.getIcon())); - menuItem.setOnAction(new EventHandler() { - @Override - public void handle(ActionEvent t) { - AddDrawableTagAction.getInstance().addTag(tn, ""); - tagSelectedMenuButton.setText(tn.getDisplayName()); - tagSelectedMenuButton.setOnAction(this); - } - }); - return menuItem; - } - - public static interface TagListener { - - public void handleTagsChanged(Collection ids); - } -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java new file mode 100644 index 0000000000..0647a18456 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java @@ -0,0 +1,41 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery; + +import java.util.Collection; +import java.util.Collections; +import javax.annotation.concurrent.Immutable; + +/** + * + */ +@Immutable +public class TagsChangeEvent { + + private final Collection fileIDs; + + public Collection getFileIDs() { + return Collections.unmodifiableCollection(fileIDs); + } + + public TagsChangeEvent(Collection fileIDs) { + this.fileIDs = fileIDs; + } + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index a098e1a1c9..394f348466 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -27,7 +27,6 @@ import javafx.scene.control.Menu; import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.openide.util.Utilities; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; @@ -45,50 +44,41 @@ import org.sleuthkit.datamodel.TskCoreException; * diverged from autopsy action, make this extend from controlsfx Action */ public class AddDrawableTagAction extends AddTagAction { - + private static final Logger LOGGER = Logger.getLogger(AddDrawableTagAction.class.getName()); - // This class is a singleton to support multi-selection of nodes, since - // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every - // node in the array returns a reference to the same action object from Node.getActions(boolean). - private static AddDrawableTagAction instance; - - public static synchronized AddDrawableTagAction getInstance() { - if (null == instance) { - instance = new AddDrawableTagAction(); - } - return instance; + private final ImageGalleryController controller; + + public AddDrawableTagAction(ImageGalleryController controller) { + this.controller = controller; } - - private AddDrawableTagAction() { - } - + public Menu getPopupMenu() { - return new TagMenu(); + return new TagMenu(controller); } - + @Override protected String getActionDisplayName() { return Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File"; } - + @Override public void addTag(TagName tagName, String comment) { Set selectedFiles = new HashSet<>(FileIDSelectionModel.getInstance().getSelected()); addTagsToFiles(tagName, comment, selectedFiles); } - + @Override - public void addTagsToFiles(TagName tagName, String comment, Set selectedFiles){ + public void addTagsToFiles(TagName tagName, String comment, Set selectedFiles) { new SwingWorker() { - + @Override protected Void doInBackground() throws Exception { for (Long fileID : selectedFiles) { try { - DrawableFile file = ImageGalleryController.getDefault().getFileFromId(fileID); + DrawableFile file = controller.getFileFromId(fileID); LOGGER.log(Level.INFO, "tagging {0} with {1} and comment {2}", new Object[]{file.getName(), tagName.getDisplayName(), comment}); - Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment); + controller.getTagsManager().addContentTag(file, tagName, comment); } catch (IllegalStateException ex) { LOGGER.log(Level.SEVERE, "Case was closed out from underneath Updatefile task", ex); } catch (TskCoreException ex) { @@ -97,14 +87,12 @@ public class AddDrawableTagAction extends AddTagAction { } //make sure rest of ui hears category change. - ImageGalleryController.getDefault().getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); - + controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } - refreshDirectoryTree(); return null; } - + @Override protected void done() { super.done(); @@ -114,7 +102,6 @@ public class AddDrawableTagAction extends AddTagAction { LOGGER.log(Level.SEVERE, "unexpected exception while tagging files", ex); } } - }.execute(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 85894cc661..94bd4e9e36 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -32,6 +32,7 @@ import org.sleuthkit.autopsy.actions.GetTagNameDialog; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -45,7 +46,7 @@ import org.sleuthkit.datamodel.TskCoreException; * * //TODO: this class started as a cut and paste from * org.sleuthkit.autopsy.actions.AddTagAction and needs to be - * refactor or reintegrated to the AddTagAction hierarchy of Autopysy. + * refactored or reintegrated to the AddTagAction hierarchy of Autopysy. */ abstract class AddTagAction { @@ -88,7 +89,7 @@ abstract class AddTagAction { // to be reworked. protected class TagMenu extends Menu { - TagMenu() { + TagMenu(ImageGalleryController controller) { super(getActionDisplayName()); // Get the current set of tag names. @@ -154,9 +155,9 @@ abstract class AddTagAction { GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); if (null != tagNameAndComment) { if (tagNameAndComment.getTagName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { - new CategorizeAction().addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); + new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } else { - AddDrawableTagAction.getInstance().addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); + new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } refreshDirectoryTree(); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 79a04f535d..358516694e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -29,16 +29,18 @@ import javafx.scene.control.MenuItem; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -54,13 +56,13 @@ public class CategorizeAction extends AddTagAction { private final ImageGalleryController controller; - public CategorizeAction() { + public CategorizeAction(ImageGalleryController controller) { super(); - this.controller = ImageGalleryController.getDefault(); + this.controller = controller; } - static public Menu getPopupMenu() { - return new CategoryMenu(); + public Menu getPopupMenu() { + return new CategoryMenu(controller); } @Override @@ -90,7 +92,7 @@ public class CategorizeAction extends AddTagAction { */ static private class CategoryMenu extends Menu { - CategoryMenu() { + CategoryMenu(ImageGalleryController controller) { super("Categorize"); // Each category get an item in the sub-menu. Selecting one of these menu items adds @@ -99,8 +101,8 @@ public class CategorizeAction extends AddTagAction { MenuItem categoryItem = new MenuItem(cat.getDisplayName()); categoryItem.setOnAction((ActionEvent t) -> { - final CategorizeAction categorizeAction = new CategorizeAction(); - categorizeAction.addTag(cat.getTagName(), NO_COMMENT); + final CategorizeAction categorizeAction = new CategorizeAction(controller); + categorizeAction.addTag(controller.getCategoryManager().getTagName(cat), NO_COMMENT); }); categoryItem.setAccelerator(new KeyCodeCombination(KeyCode.getKeyCode(Integer.toString(cat.getCategoryNumber())))); getItems().add(categoryItem); @@ -123,29 +125,34 @@ public class CategorizeAction extends AddTagAction { @Override public void run() { + final GroupManager groupManager = controller.getGroupManager(); + final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + final CategoryManager categoryManager = controller.getCategoryManager(); + try { DrawableFile file = controller.getFileFromId(fileID); //drawable db Category oldCat = file.getCategory(); + // remove file from old category group - controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.CATEGORY, oldCat), fileID); //memory + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.CATEGORY, oldCat), fileID); //memory //remove old category tag if necessary - List allContentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(file); //tsk db + List allContentTags = sleuthKitCase.getContentTagsByContent(file); //tsk db + for (ContentTag ct : allContentTags) { //this is bad: treating tags as categories as long as their names start with prefix //TODO: abandon using tags for categories and instead add a new column to DrawableDB if (ct.getName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { - Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(ct); //tsk db - controller.getCategoryManager().decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db + sleuthKitCase.deleteContentTag(ct); //tsk db + categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db } - } - controller.getCategoryManager().incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db - if (tagName != Category.ZERO.getTagName()) { // no tags for cat-0 - Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment); //tsk db + categoryManager.incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db + if (tagName != categoryManager.getTagName(Category.ZERO)) { // no tags for cat-0 + controller.getTagsManager().addContentTag(file, tagName, comment); //tsk db } //make sure rest of ui hears category change. - controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui + groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error categorizing result", ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java similarity index 66% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java index 0fe88de953..38a8e40256 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java @@ -19,17 +19,16 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.Collections; -import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -39,21 +38,26 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** + * Action to delete the follow up tag a + * * */ -public class DeleteFollowUpTag extends Action { +public class DeleteTagAction extends Action { - private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTag.class.getName()); + private static final Logger LOGGER = Logger.getLogger(DeleteTagAction.class.getName()); private final long fileID; private final DrawableFile file; + private final ImageGalleryController controller; + private final ContentTag tag; - public DeleteFollowUpTag(DrawableFile file) { + public DeleteTagAction(ImageGalleryController controller, DrawableFile file, ContentTag tag) { super("Delete Follow Up Tag"); + this.controller = controller; this.file = file; this.fileID = file.getId(); - + this.tag = tag; setEventHandler((ActionEvent t) -> { - deleteFollowupTag(); + deleteTag(); }); } @@ -63,24 +67,26 @@ public class DeleteFollowUpTag extends Action { * * @throws IllegalStateException */ - private void deleteFollowupTag() throws IllegalStateException { + private void deleteTag() throws IllegalStateException { - final ImageGalleryController controller = ImageGalleryController.getDefault(); final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + final GroupManager groupManager = controller.getGroupManager(); + try { // remove file from old category group - controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); - - List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { - sleuthKitCase.deleteContentTag(ct); - } - } + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, tag.getName()), fileID); + sleuthKitCase.deleteContentTag(tag); +// +// List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); +// for (ContentTag ct : contentTagsByContent) { +// if (ct.getName().getDisplayName().equals(tagsManager.getFollowUpTagName().getDisplayName())) { +// sleuthKitCase.deleteContentTag(ct); +// } +// } IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS //make sure rest of ui hears category change. - controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 4839537731..0ded98426f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -20,14 +20,10 @@ package org.sleuthkit.autopsy.imagegallery.datamodel; import java.util.Map; import java.util.function.Function; -import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; import javafx.scene.paint.Color; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; /** * Enum to represent the six categories in the DHs image categorization scheme. @@ -101,19 +97,4 @@ public enum Category implements Comparable { return displayName; } - /** - * get the TagName used to store this Category in the main autopsy db. - * - * @return the TagName used for this Category - */ - public TagName getTagName() { - if (tagName == null) { - try { - tagName = TagUtils.getTagName(displayName); - } catch (TskCoreException ex) { - Logger.getLogger(Category.class.getName()).log(Level.SEVERE, "failed to get TagName for " + displayName, ex); - } - } - return tagName; - } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java index f53acac5f5..9896325e09 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java @@ -29,16 +29,16 @@ import javax.annotation.concurrent.Immutable; @Immutable public class CategoryChangeEvent { - private final Collection ids; + private final Collection fileIDs; /** * @return the fileIDs of the files whose categories have changed */ - public Collection getIds() { - return Collections.unmodifiableCollection(ids); + public Collection getFileIDs() { + return Collections.unmodifiableCollection(fileIDs); } - public CategoryChangeEvent(Collection ids) { - this.ids = ids; + public CategoryChangeEvent(Collection fileIDs) { + this.fileIDs = fileIDs; } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index f6e0404c6e..08ba1b17a5 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -26,7 +26,8 @@ import java.util.Collection; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.datamodel.TagName; /** * Provides a cached view of the number of files per category, and fires @@ -43,6 +44,7 @@ import org.sleuthkit.autopsy.imagegallery.TagUtils; public class CategoryManager { private static final java.util.logging.Logger LOGGER = Logger.getLogger(CategoryManager.class.getName()); + private final ImageGalleryController controller; /** * the DrawableDB that backs the category counts cache. The counts are @@ -63,6 +65,20 @@ public class CategoryManager { */ private final LoadingCache categoryCounts = CacheBuilder.newBuilder().build(CacheLoader.from(this::getCategoryCountHelper)); + /** + * cached TagNames corresponding to Categories, looked up from + * autopsyTagManager at initial request or if invalidated by case change. + */ + private final LoadingCache catTagNameMap = CacheBuilder.newBuilder().build(CacheLoader.from(cat + -> getController().getTagsManager().getTagName(cat))); + + public CategoryManager(ImageGalleryController controller) { + this.controller = controller; + } + + private ImageGalleryController getController() { + return controller; + } /** * assign a new db. the counts cache is invalidated and all subsequent db @@ -75,8 +91,8 @@ public class CategoryManager { public void setDb(DrawableDB db) { this.db = db; categoryCounts.invalidateAll(); + catTagNameMap.invalidateAll(); Category.clearTagNames(); - TagUtils.clearFollowUpTagName(); } /** @@ -171,4 +187,13 @@ public class CategoryManager { categoryEventBus.unregister(listener); } + /** + * get the TagName used to store this Category in the main autopsy db. + * + * @return the TagName used for this Category + */ + public TagName getTagName(Category cat) { + return catTagNameMap.getUnchecked(cat); + + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index ac1f6c99eb..b043bf126d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -47,6 +47,7 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; @@ -147,6 +148,7 @@ public final class DrawableDB { } } private final SleuthkitCase tskCase; + private final ImageGalleryController controller; //////////////general database logic , mostly borrowed from sleuthkitcase /** @@ -195,9 +197,10 @@ public final class DrawableDB { * * @throws SQLException if there is problem creating or configuring the db */ - private DrawableDB(Path dbPath, SleuthkitCase tskCase) throws SQLException, ExceptionInInitializerError, IOException { + private DrawableDB(Path dbPath, ImageGalleryController controller) throws SQLException, ExceptionInInitializerError, IOException { this.dbPath = dbPath; - this.tskCase = tskCase; + this.controller = controller; + this.tskCase = controller.getSleuthKitCase(); Files.createDirectories(dbPath.getParent()); if (initializeDBSchema()) { updateFileStmt = prepareStatement( @@ -286,10 +289,10 @@ public final class DrawableDB { * * @return */ - public static DrawableDB getDrawableDB(Path dbPath, SleuthkitCase tskCase) { + public static DrawableDB getDrawableDB(Path dbPath, ImageGalleryController controller) { try { - return new DrawableDB(dbPath.resolve("drawable.db"), tskCase); + return new DrawableDB(dbPath.resolve("drawable.db"), controller); } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "sql error creating database connection", ex); return null; @@ -1055,7 +1058,7 @@ public final class DrawableDB { public List> getFilesWithCategory(Category cat) throws TskCoreException, IllegalArgumentException { try { List> files = new ArrayList<>(); - List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(cat.getTagName()); + List contentTags = tskCase.getContentTagsByTagName(controller.getTagsManager().getTagName(cat)); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile) { files.add(DrawableFile.create((AbstractFile) ct.getContent(), isFileAnalyzed(ct.getContent().getId()), @@ -1240,7 +1243,7 @@ public final class DrawableDB { */ public long getCategoryCount(Category cat) { try { - return Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(cat.getTagName()).stream() + return tskCase.getContentTagsByTagName(controller.getTagsManager().getTagName(cat)).stream() .map(ContentTag::getContent) .map(Content::getId) .filter(this::isInDB) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java index 789cac7375..cd41534078 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java @@ -56,7 +56,7 @@ public class GroupKey> implements Comparable @Override public String toString() { - return "GroupKey: " + getAttribute() + " = " + getValue(); + return "GroupKey: " + getAttribute().attrName + " = " + getValue(); } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 68e1044dbc..dab1f9743f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -34,6 +34,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; +import java.util.stream.Stream; import javafx.application.Platform; import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleWrapper; @@ -51,10 +52,10 @@ import org.sleuthkit.autopsy.coreutils.LoggedTask; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; @@ -486,31 +487,34 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public Set getFileIDsWithCategory(Category category) throws TskCoreException { try { + final DrawableTagsManager tagsManager = controller.getTagsManager(); if (category == Category.ZERO) { + List< TagName> tns = Stream.of(Category.ONE, Category.TWO, Category.THREE, Category.FOUR, Category.FIVE) + .map(tagsManager::getTagName) + .collect(Collectors.toList()); Set files = new HashSet<>(); - TagName[] tns = {Category.FOUR.getTagName(), Category.THREE.getTagName(), Category.TWO.getTagName(), Category.ONE.getTagName(), Category.FIVE.getTagName()}; for (TagName tn : tns) { - List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tn); - for (ContentTag ct : contentTags) { - if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { - files.add(ct.getContent().getId()); - } + if (tn != null) { + List contentTags = tagsManager.getContentTagsByTagName(tn); + files.addAll(contentTags.stream() + .filter(ct -> ct.getContent() instanceof AbstractFile) + .filter(ct -> db.isInDB(ct.getContent().getId())) + .map(ct -> ct.getContent().getId()) + .collect(Collectors.toSet())); } } return db.findAllFileIdsWhere("obj_id NOT IN (" + StringUtils.join(files, ',') + ")"); } else { - Set files = new HashSet<>(); - List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(category.getTagName()); - for (ContentTag ct : contentTags) { - if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { - files.add(ct.getContent().getId()); - } - } + List contentTags = tagsManager.getContentTagsByTagName(tagsManager.getTagName(category)); + return contentTags.stream() + .filter(ct -> ct.getContent() instanceof AbstractFile) + .filter(ct -> db.isInDB(ct.getContent().getId())) + .map(ct -> ct.getContent().getId()) + .collect(Collectors.toSet()); - return files; } } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "TSK error getting files in Category:" + category.getDisplayName(), ex); @@ -688,7 +692,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { controller.getCategoryManager().fireChange(fileIDs); if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { - TagUtils.fireChange(fileIDs); + controller.getTagsManager().fireChange(fileIDs); } break; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java index 80f16a3d7a..75332ba158 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java @@ -32,7 +32,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableViewBase.globalSelectionModel; /** @@ -43,7 +42,7 @@ import static org.sleuthkit.autopsy.imagegallery.gui.DrawableViewBase.globalSele * * TODO: refactor this to extend from {@link Control}? -jm */ -public class DrawableTile extends DrawableViewBase implements TagUtils.TagListener { +public class DrawableTile extends DrawableViewBase { private static final DropShadow LAST_SELECTED_EFFECT = new DropShadow(10, Color.BLUE); @@ -73,8 +72,8 @@ public class DrawableTile extends DrawableViewBase implements TagUtils.TagListen setCacheHint(CacheHint.SPEED); nameLabel.prefWidthProperty().bind(imageView.fitWidthProperty()); - imageView.fitHeightProperty().bind(Toolbar.getDefault().sizeSliderValue()); - imageView.fitWidthProperty().bind(Toolbar.getDefault().sizeSliderValue()); + imageView.fitHeightProperty().bind(Toolbar.getDefault(getController()).sizeSliderValue()); + imageView.fitWidthProperty().bind(Toolbar.getDefault(getController()).sizeSliderValue()); globalSelectionModel.lastSelectedProperty().addListener((observable, oldValue, newValue) -> { try { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 8f91cdf932..ed0453ec0b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -1,7 +1,6 @@ package org.sleuthkit.autopsy.imagegallery.gui; import com.google.common.eventbus.Subscribe; -import java.util.Collection; import java.util.logging.Level; import javafx.application.Platform; import javafx.scene.layout.Border; @@ -13,7 +12,8 @@ import javafx.scene.layout.Region; import javafx.scene.paint.Color; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; @@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; * } to have there {@link DrawableView#handleCategoryChanged(org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent) * } method invoked */ -public interface DrawableView extends TagUtils.TagListener { +public interface DrawableView { //TODO: do this all in css? -jm static final int CAT_BORDER_WIDTH = 10; @@ -67,8 +67,10 @@ public interface DrawableView extends TagUtils.TagListener { @Subscribe void handleCategoryChanged(CategoryChangeEvent evt); - @Override - void handleTagsChanged(Collection ids); + @Subscribe + void handleTagsChanged(TagsChangeEvent evt); + + ImageGalleryController getController(); default boolean hasHashHit() { try { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index e866742505..7f29af775e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -64,10 +64,10 @@ import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; -import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; -import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTag; +import org.sleuthkit.autopsy.imagegallery.actions.DeleteTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -138,6 +138,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie */ final private GroupPane groupPane; private boolean registered = false; + private final ImageGalleryController controller; GroupPane getGroupPane() { return groupPane; @@ -145,6 +146,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie protected DrawableViewBase(GroupPane groupPane) { this.groupPane = groupPane; + this.controller = groupPane.getController(); globalSelectionModel.getSelected().addListener((Observable observable) -> { updateSelectionState(); }); @@ -194,9 +196,9 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie private ContextMenu buildContextMenu() { final ArrayList menuItems = new ArrayList<>(); - menuItems.add(CategorizeAction.getPopupMenu()); + menuItems.add(new CategorizeAction(controller).getPopupMenu()); - menuItems.add(AddDrawableTagAction.getInstance().getPopupMenu()); + menuItems.add(new AddDrawableTagAction(controller).getPopupMenu()); final MenuItem extractMenuItem = new MenuItem("Extract File(s)"); extractMenuItem.setOnAction((ActionEvent t) -> { @@ -260,43 +262,16 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie if (followUpToggle.isSelected() == true) { globalSelectionModel.clearAndSelect(fileID); try { - AddDrawableTagAction.getInstance().addTag(TagUtils.getFollowUpTagName(), ""); + new AddDrawableTagAction(controller).addTag(ImageGalleryController.getDefault().getTagsManager().getFollowUpTagName(), ""); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to add follow up tag. Could not load TagName.", ex); } } else { - new DeleteFollowUpTag(file).handle(t); -// deleteFollowupTag(fileID); + new DeleteTagAction(controller, file).handle(t); } }); } -// /** -// * -// * @param fileID1 the value of fileID1 -// * -// * @throws IllegalStateException -// */ -// private void deleteFollowupTag(final Long fileID1) throws IllegalStateException { -// //TODO: convert this to an action! -// final ImageGalleryController controller = ImageGalleryController.getDefault(); -// try { -// // remove file from old category group -// controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID1); -// -// List contentTagsByContent = controller.getSleuthKitCase().getContentTagsByContent(file); -// for (ContentTag ct : contentTagsByContent) { -// if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { -// controller.getSleuthKitCase().deleteContentTag(ct); -// } -// } -// IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS -// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID1), DrawableAttribute.TAGS)); -// } catch (TskCoreException ex) { -// LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); -// } -// } - @Override public DrawableFile getFile() { if (fileID != null) { @@ -315,7 +290,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie } protected boolean hasFollowUp() throws TskCoreException { - String followUpTagName = TagUtils.getFollowUpTagName().getDisplayName(); + String followUpTagName = ImageGalleryController.getDefault().getTagsManager().getFollowUpTagName().getDisplayName(); Collection tagNames = DrawableAttribute.TAGS.getValue(getFile()); return tagNames.stream().anyMatch((tn) -> tn.getDisplayName().equals(followUpTagName)); } @@ -326,8 +301,8 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie } @Override - synchronized public void handleTagsChanged(Collection ids) { - if (fileID != null && ids.contains(fileID)) { + synchronized public void handleTagsChanged(TagsChangeEvent evnt) { + if (fileID != null && evnt.getFileIDs().contains(fileID)) { updateFollowUpIcon(); } } @@ -354,8 +329,8 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie if (this.fileID == null || Case.isCaseOpen() == false) { if (registered == true) { - ImageGalleryController.getDefault().getCategoryManager().unregisterListener(this); - TagUtils.unregisterListener(this); + getController().getCategoryManager().unregisterListener(this); + getController().getTagsManager().unregisterListener(this); registered = false; } file = null; @@ -364,8 +339,8 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie }); } else { if (registered == false) { - ImageGalleryController.getDefault().getCategoryManager().registerListener(this); - TagUtils.registerListener(this); + getController().getCategoryManager().registerListener(this); + getController().getTagsManager().registerListener(this); registered = true; } file = null; @@ -411,8 +386,13 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { - if (evt.getIds().contains(getFileID())) { + if (evt.getFileIDs().contains(getFileID())) { updateCategoryBorder(); } } + + @Override + public ImageGalleryController getController() { + return controller; + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java index 30dcf743fb..09042abaf4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java @@ -100,11 +100,11 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.Back; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; @@ -277,7 +277,7 @@ public class GroupPane extends BorderPane implements GroupView { @Override public void handle(ActionEvent t) { Set fileIdSet = new HashSet<>(getGrouping().fileIds()); - new CategorizeAction().addTagsToFiles(cat.getTagName(), "", fileIdSet); + new CategorizeAction(controller).addTagsToFiles(controller.getTagsManager().getTagName(cat), "", fileIdSet); grpCatSplitMenu.setText(cat.getDisplayName()); grpCatSplitMenu.setOnAction(this); @@ -292,7 +292,7 @@ public class GroupPane extends BorderPane implements GroupView { @Override public void handle(ActionEvent t) { Set fileIdSet = new HashSet<>(getGrouping().fileIds()); - AddDrawableTagAction.getInstance().addTagsToFiles(tn, "", fileIdSet); + new AddDrawableTagAction(controller).addTagsToFiles(tn, "", fileIdSet); grpTagSplitMenu.setText(tn.getDisplayName()); grpTagSplitMenu.setOnAction(this); @@ -340,8 +340,8 @@ public class GroupPane extends BorderPane implements GroupView { flashAnimation.setAutoReverse(true); //configure gridView cell properties - gridView.cellHeightProperty().bind(Toolbar.getDefault().sizeSliderValue().add(75)); - gridView.cellWidthProperty().bind(Toolbar.getDefault().sizeSliderValue().add(75)); + gridView.cellHeightProperty().bind(Toolbar.getDefault(controller).sizeSliderValue().add(75)); + gridView.cellWidthProperty().bind(Toolbar.getDefault(controller).sizeSliderValue().add(75)); gridView.setCellFactory((GridView param) -> new DrawableCell()); //configure toolbar properties @@ -349,8 +349,8 @@ public class GroupPane extends BorderPane implements GroupView { spacer.setMinWidth(Region.USE_PREF_SIZE); try { - grpTagSplitMenu.setText(TagUtils.getFollowUpTagName().getDisplayName()); - grpTagSplitMenu.setOnAction(createGrpTagMenuItem(TagUtils.getFollowUpTagName()).getOnAction()); + grpTagSplitMenu.setText(getController().getTagsManager().getFollowUpTagName().getDisplayName()); + grpTagSplitMenu.setOnAction(createGrpTagMenuItem(getController().getTagsManager().getFollowUpTagName()).getOnAction()); } catch (TskCoreException tskCoreException) { LOGGER.log(Level.WARNING, "failed to load FollowUpTagName", tskCoreException); } @@ -358,8 +358,8 @@ public class GroupPane extends BorderPane implements GroupView { grpTagSplitMenu.showingProperty().addListener((ObservableValue ov, Boolean t, Boolean t1) -> { if (t1) { ArrayList selTagMenues = new ArrayList<>(); - for (final TagName tn : TagUtils.getNonCategoryTagNames()) { - MenuItem menuItem = TagUtils.createSelTagMenuItem(tn, grpTagSplitMenu); + for (final TagName tn : getController().getTagsManager().getNonCategoryTagNames()) { + MenuItem menuItem = GuiUtils.createSelTagMenuItem(tn, grpTagSplitMenu, controller); selTagMenues.add(menuItem); } grpTagSplitMenu.getItems().setAll(selTagMenues); @@ -419,9 +419,8 @@ public class GroupPane extends BorderPane implements GroupView { private ContextMenu buildContextMenu() { ArrayList menuItems = new ArrayList<>(); - menuItems.add(CategorizeAction.getPopupMenu()); - - menuItems.add(AddDrawableTagAction.getInstance().getPopupMenu()); + menuItems.add(new CategorizeAction(controller).getPopupMenu()); + menuItems.add(new AddDrawableTagAction(controller).getPopupMenu()); Collection menuProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class); @@ -653,6 +652,10 @@ public class GroupPane extends BorderPane implements GroupView { } } + ImageGalleryController getController() { + return controller; + } + private class DrawableCell extends GridCell { private final DrawableTile tile = new DrawableTile(GroupPane.this); @@ -751,27 +754,27 @@ public class GroupPane extends BorderPane implements GroupView { switch (t.getCode()) { case NUMPAD0: case DIGIT0: - new CategorizeAction().addTag(Category.ZERO.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.ZERO), ""); break; case NUMPAD1: case DIGIT1: - new CategorizeAction().addTag(Category.ONE.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.ONE), ""); break; case NUMPAD2: case DIGIT2: - new CategorizeAction().addTag(Category.TWO.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.TWO), ""); break; case NUMPAD3: case DIGIT3: - new CategorizeAction().addTag(Category.THREE.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.THREE), ""); break; case NUMPAD4: case DIGIT4: - new CategorizeAction().addTag(Category.FOUR.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.FOUR), ""); break; case NUMPAD5: case DIGIT5: - new CategorizeAction().addTag(Category.FIVE.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.FIVE), ""); break; } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java new file mode 100644 index 0000000000..4a2a84fd46 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java @@ -0,0 +1,62 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery.gui; + +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.scene.control.MenuItem; +import javafx.scene.control.SplitMenuButton; +import javafx.scene.image.ImageView; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.datamodel.TagName; + +/** + * Static utility methods for working with GUI components + */ +public class GuiUtils { + + /** + * make a new menu item that when clicked, tags the selected files with the + * given tagname + * + * @param tagName + * @param tagSelectedMenuButton + * @param controller + * + * @return + */ + public static MenuItem createSelTagMenuItem(final TagName tagName, final SplitMenuButton tagSelectedMenuButton, ImageGalleryController controller) { + final MenuItem menuItem = new MenuItem(tagName.getDisplayName(), new ImageView(DrawableAttribute.TAGS.getIcon())); + menuItem.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent t) { + new AddDrawableTagAction(controller).addTag(tagName, ""); + tagSelectedMenuButton.setText(tagName.getDisplayName()); + tagSelectedMenuButton.setOnAction(this); + } + }); + return menuItem; + } + + private GuiUtils() { + } + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index b4319ac815..f9f6115d67 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -45,7 +45,7 @@ import javafx.util.Pair; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -56,12 +56,17 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Shows details of the selected file. */ -public class MetaDataPane extends AnchorPane implements TagUtils.TagListener, DrawableView { +public class MetaDataPane extends AnchorPane implements DrawableView { private static final Logger LOGGER = Logger.getLogger(MetaDataPane.class.getName()); private final ImageGalleryController controller; + @Override + public ImageGalleryController getController() { + return controller; + } + private Long fileID; @FXML @@ -92,8 +97,8 @@ public class MetaDataPane extends AnchorPane implements TagUtils.TagListener, Dr assert imageView != null : "fx:id=\"imageView\" was not injected: check your FXML file 'MetaDataPane.fxml'."; assert tableView != null : "fx:id=\"tableView\" was not injected: check your FXML file 'MetaDataPane.fxml'."; assert valueColumn != null : "fx:id=\"valueColumn\" was not injected: check your FXML file 'MetaDataPane.fxml'."; - TagUtils.registerListener(this); - ImageGalleryController.getDefault().getCategoryManager().registerListener(this); + getController().getTagsManager().registerListener(this); + getController().getCategoryManager().registerListener(this); tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); tableView.setPlaceholder(new Label("Select a file to show its details here.")); @@ -224,14 +229,15 @@ public class MetaDataPane extends AnchorPane implements TagUtils.TagListener, Dr @Subscribe @Override public void handleCategoryChanged(CategoryChangeEvent evt) { - if (getFile() != null && evt.getIds().contains(getFileID())) { + if (getFile() != null && evt.getFileIDs().contains(getFileID())) { updateUI(); } } @Override - public void handleTagsChanged(Collection ids) { - if (getFile() != null && ids.contains(getFileID())) { + @Subscribe + public void handleTagsChanged(TagsChangeEvent evt) { + if (getFile() != null && evt.getFileIDs().contains(getFileID())) { updateUI(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index 88467e1973..7977eb0219 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -48,9 +48,9 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -66,7 +66,7 @@ import org.sleuthkit.datamodel.TskCoreException; * GroupPane. TODO: Extract a subclass for video files in slideshow mode-jm * TODO: reduce coupling to GroupPane */ -public class SlideShowView extends DrawableViewBase implements TagUtils.TagListener { +public class SlideShowView extends DrawableViewBase { private static final Logger LOGGER = Logger.getLogger(SlideShowView.class.getName()); @@ -127,7 +127,7 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe tagSplitButton.setOnAction((ActionEvent t) -> { try { - TagUtils.createSelTagMenuItem(TagUtils.getFollowUpTagName(), tagSplitButton).getOnAction().handle(t); + GuiUtils.createSelTagMenuItem(getController().getTagsManager().getFollowUpTagName(), tagSplitButton, getController()).getOnAction().handle(t); } catch (TskCoreException ex) { Exceptions.printStackTrace(ex); } @@ -137,8 +137,8 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe tagSplitButton.showingProperty().addListener((ObservableValue ov, Boolean t, Boolean t1) -> { if (t1) { ArrayList selTagMenues = new ArrayList<>(); - for (final TagName tn : TagUtils.getNonCategoryTagNames()) { - MenuItem menuItem = TagUtils.createSelTagMenuItem(tn, tagSplitButton); + for (final TagName tn : getController().getTagsManager().getNonCategoryTagNames()) { + MenuItem menuItem = GuiUtils.createSelTagMenuItem(tn, tagSplitButton, getController()); selTagMenues.add(menuItem); } tagSplitButton.getItems().setAll(selTagMenues); @@ -347,7 +347,7 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe public void changed(ObservableValue ov, Boolean t, Boolean t1) { if (t1) { FileIDSelectionModel.getInstance().clearAndSelect(getFileID()); - new CategorizeAction().addTag(cat.getTagName(), ""); + new CategorizeAction(getController()).addTag(getController().getTagsManager().getTagName(cat), ""); } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index bf62f89084..2131ff73fc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -41,10 +41,10 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javax.swing.SortOrder; import org.openide.util.Exceptions; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.ThumbnailCache; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; @@ -105,6 +105,7 @@ public class Toolbar extends ToolBar { ImageGalleryController.getDefault().getGroupManager().regroup(groupByBox.getSelectionModel().getSelectedItem(), sortByBox.getSelectionModel().getSelectedItem(), getSortOrder(), false); }; + private ImageGalleryController controller; synchronized public SortOrder getSortOrder() { return orderProperty.get(); @@ -117,9 +118,9 @@ public class Toolbar extends ToolBar { return sizeSlider.valueProperty(); } - static synchronized public Toolbar getDefault() { + static synchronized public Toolbar getDefault(ImageGalleryController controller) { if (instance == null) { - instance = new Toolbar(); + instance = new Toolbar(controller); } return instance; } @@ -151,7 +152,7 @@ public class Toolbar extends ToolBar { tagSelectedMenuButton.setOnAction((ActionEvent t) -> { try { - TagUtils.createSelTagMenuItem(TagUtils.getFollowUpTagName(), tagSelectedMenuButton).getOnAction().handle(t); + GuiUtils.createSelTagMenuItem(getController().getTagsManager().getFollowUpTagName(), tagSelectedMenuButton, getController()).getOnAction().handle(t); } catch (TskCoreException ex) { Exceptions.printStackTrace(ex); } @@ -161,22 +162,22 @@ public class Toolbar extends ToolBar { tagSelectedMenuButton.showingProperty().addListener((ObservableValue ov, Boolean t, Boolean t1) -> { if (t1) { ArrayList selTagMenues = new ArrayList<>(); - for (final TagName tn : TagUtils.getNonCategoryTagNames()) { - MenuItem menuItem = TagUtils.createSelTagMenuItem(tn, tagSelectedMenuButton); + for (final TagName tn : getController().getTagsManager().getNonCategoryTagNames()) { + MenuItem menuItem = GuiUtils.createSelTagMenuItem(tn, tagSelectedMenuButton, getController()); selTagMenues.add(menuItem); } tagSelectedMenuButton.getItems().setAll(selTagMenues); } }); - catSelectedMenuButton.setOnAction(createSelCatMenuItem(Category.FIVE, catSelectedMenuButton).getOnAction()); + catSelectedMenuButton.setOnAction(createSelCatMenuItem(Category.FIVE, catSelectedMenuButton, getController()).getOnAction()); catSelectedMenuButton.setText(Category.FIVE.getDisplayName()); catSelectedMenuButton.setGraphic(new ImageView(DrawableAttribute.CATEGORY.getIcon())); catSelectedMenuButton.showingProperty().addListener((ObservableValue ov, Boolean t, Boolean t1) -> { if (t1) { ArrayList categoryMenues = new ArrayList<>(); for (final Category cat : Category.values()) { - MenuItem menuItem = createSelCatMenuItem(cat, catSelectedMenuButton); + MenuItem menuItem = createSelCatMenuItem(cat, catSelectedMenuButton, getController()); categoryMenues.add(menuItem); } catSelectedMenuButton.getItems().setAll(categoryMenues); @@ -221,20 +222,25 @@ public class Toolbar extends ToolBar { }); } - private Toolbar() { + private Toolbar(ImageGalleryController controller) { + this.controller = controller; FXMLConstructor.construct(this, "Toolbar.fxml"); } - private static MenuItem createSelCatMenuItem(Category cat, final SplitMenuButton catSelectedMenuButton) { + private static MenuItem createSelCatMenuItem(Category cat, final SplitMenuButton catSelectedMenuButton, ImageGalleryController controller) { final MenuItem menuItem = new MenuItem(cat.getDisplayName(), new ImageView(DrawableAttribute.CATEGORY.getIcon())); menuItem.setOnAction(new EventHandler() { @Override public void handle(ActionEvent t) { - new CategorizeAction().addTag(cat.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(cat), ""); catSelectedMenuButton.setText(cat.getDisplayName()); catSelectedMenuButton.setOnAction(this); } }); return menuItem; } + + private ImageGalleryController getController() { + return controller; + } } From e1b2844b9598fc7d2462c290388ff654eb6bac33 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Wed, 17 Jun 2015 13:53:44 -0400 Subject: [PATCH 049/198] stack trace removed for POI container init warnings --- .../embeddedfileextractor/ImageExtractor.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java index 419c438968..6203b4fa3e 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java @@ -196,7 +196,7 @@ class ImageExtractor { try { doc = new HWPFDocument(new ReadContentInputStream(af)); } catch (IOException | OldFileFormatException ex) { - logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName()), ex); //NON-NLS + logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName())); //NON-NLS return null; } PicturesTable pictureTable = doc.getPicturesTable(); @@ -234,7 +234,7 @@ class ImageExtractor { try { docx = new XWPFDocument(new ReadContentInputStream(af)); } catch (IOException | OldFileFormatException ex) { - logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docxContainer.init.err", af.getName()), ex); //NON-NLS + logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docxContainer.init.err", af.getName())); //NON-NLS return null; } List listOfAllPictures = docx.getAllPictures(); @@ -273,7 +273,7 @@ class ImageExtractor { try { ppt = new SlideShow(new ReadContentInputStream(af)); } catch (IOException | OldFileFormatException ex) { - logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName()), ex); //NON-NLS + logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName())); //NON-NLS return null; } @@ -343,7 +343,7 @@ class ImageExtractor { try { pptx = new XMLSlideShow(new ReadContentInputStream(af)); } catch (IOException | OldFileFormatException ex) { - logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptxContainer.init.err", af.getName()), ex); //NON-NLS + logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptxContainer.init.err", af.getName())); //NON-NLS return null; } List listOfAllPictures = pptx.getAllPictures(); @@ -390,7 +390,7 @@ class ImageExtractor { try { xls = new HSSFWorkbook(new ReadContentInputStream(af)); } catch (IOException | OldFileFormatException ex) { - logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err", af.getName()) + af.getName(), ex); //NON-NLS + logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err", af.getName()) + af.getName()); //NON-NLS return null; } @@ -433,7 +433,7 @@ class ImageExtractor { try { xlsx = new XSSFWorkbook(new ReadContentInputStream(af)); } catch (IOException | OldFileFormatException ex) { - logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsxContainer.init.err", af.getName()), ex); //NON-NLS + logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsxContainer.init.err", af.getName())); //NON-NLS return null; } From 36b727e94dc30ae0f278ae241df791120a3f7ba1 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 17 Jun 2015 15:51:15 -0400 Subject: [PATCH 050/198] make sure all code is using the correct TagsManager (DrawableTagsManager) from controller; more cleanup --- .../imagegallery/DrawableTagsManager.java | 49 +++++++++++++++++-- .../imagegallery/ImageGalleryController.java | 39 ++++++++------- .../actions/AddDrawableTagAction.java | 3 +- .../imagegallery/actions/AddTagAction.java | 23 ++------- .../actions/CategorizeAction.java | 3 +- ...tion.java => DeleteFollowUpTagAction.java} | 43 ++++++++-------- .../imagegallery/datamodel/DrawableDB.java | 4 +- .../imagegallery/datamodel/DrawableFile.java | 10 ++-- .../imagegallery/grouping/GroupManager.java | 33 ++++++++++--- .../imagegallery/gui/DrawableViewBase.java | 16 +++--- 10 files changed, 134 insertions(+), 89 deletions(-) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/{DeleteTagAction.java => DeleteFollowUpTagAction.java} (69%) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 3c1dd42de3..7ba9ceb842 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -28,6 +28,10 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.ingest.IngestServices; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -45,7 +49,7 @@ public class DrawableTagsManager { /** Used to distribute {@link TagsChangeEvent}s */ private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); - /** The tag name corresponging to the "built-in" tag "Follow Up" */ + /** The tag name corresponding to the "built-in" tag "Follow Up" */ private TagName followUpTagName; public DrawableTagsManager(TagsManager autopsyTagsManager) { @@ -113,7 +117,7 @@ public class DrawableTagsManager { return followUpTagName; } - public Collection getNonCategoryTagNames() { + synchronized public Collection getNonCategoryTagNames() { try { return autopsyTagsManager.getAllTagNames().stream() .filter(Category::isCategoryTagName) @@ -124,6 +128,20 @@ public class DrawableTagsManager { return Collections.emptySet(); } + /** + * Gets content tags count by content. + * + * @param The content of interest. + * + * @return A list, possibly empty, of the tags that have been applied to the + * artifact. + * + * @throws TskCoreException + */ + public synchronized List getContentTagsByContent(Content content) throws TskCoreException { + return autopsyTagsManager.getContentTagsByContent(content); + } + public synchronized TagName getTagName(String displayName) throws TskCoreException { try { for (TagName tn : autopsyTagsManager.getAllTagNames()) { @@ -150,12 +168,35 @@ public class DrawableTagsManager { } } - public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { + synchronized public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { autopsyTagsManager.addContentTag(file, tagName, comment); } - public List getContentTagsByTagName(TagName t) throws TskCoreException { + synchronized public List getContentTagsByTagName(TagName t) throws TskCoreException { return autopsyTagsManager.getContentTagsByTagName(t); } + /** + * Fire the ModuleDataEvent that we use as a place holder for a real Tag + * Event. This is used to refresh the autopsy tag tree and the ui in + * ImageGallery + * + * + * Note: this is a hack. In an ideal world, TagsManager would fire + * events so that the directory tree would refresh. But, we haven't + * had a chance to add that so, we fire these events and the tree + * refreshes based on them. + */ + static public void fireTagsChangedEvent() { + + IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + } + + public synchronized List getAllTagNames() throws TskCoreException { + return autopsyTagsManager.getAllTagNames(); + } + + public synchronized List getTagNamesInUse() throws TskCoreException { + return autopsyTagsManager.getTagNamesInUse(); + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index ae7a169e96..4bed46a023 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.imagegallery; import java.beans.PropertyChangeEvent; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; @@ -134,6 +135,7 @@ public final class ImageGalleryController { private StackPane centralStackPane; private Node infoOverlay; + private SleuthkitCase sleuthKitCase; public ReadOnlyBooleanProperty getMetaDataCollapsed() { return metaDataCollapsed.getReadOnlyProperty(); @@ -345,20 +347,25 @@ public final class ImageGalleryController { * @param theNewCase the case to configure the controller for */ public synchronized void setCase(Case theNewCase) { - this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); + if (Objects.nonNull(theNewCase)) { + this.sleuthKitCase = theNewCase.getSleuthkitCase(); + this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); - setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); - setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); + setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); + setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); - // if we add this line icons are made as files are analyzed rather than on demand. - // db.addUpdatedFileListener(IconCache.getDefault()); - restartWorker(); - historyManager.clear(); - groupManager.setDB(db); - hashSetManager.setDb(db); - categoryManager.setDb(db); - tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); - SummaryTablePane.getDefault().refresh(); + // if we add this line icons are made as files are analyzed rather than on demand. + // db.addUpdatedFileListener(IconCache.getDefault()); + restartWorker(); + historyManager.clear(); + groupManager.setDB(db); + hashSetManager.setDb(db); + categoryManager.setDb(db); + tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); + SummaryTablePane.getDefault().refresh(); + } else { + reset(); + } } /** @@ -558,12 +565,8 @@ public final class ImageGalleryController { } } - public SleuthkitCase getSleuthKitCase() throws IllegalStateException { - if (Case.isCaseOpen()) { - return Case.getCurrentCase().getSleuthkitCase(); - } else { - throw new IllegalStateException("No Case is open!"); - } + public synchronized SleuthkitCase getSleuthKitCase() { + return sleuthKitCase; } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index 394f348466..9d5c5f277b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -28,6 +28,7 @@ import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.openide.util.Utilities; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -89,7 +90,7 @@ public class AddDrawableTagAction extends AddTagAction { //make sure rest of ui hears category change. controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } - refreshDirectoryTree(); + DrawableTagsManager.fireTagsChangedEvent(); return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 94bd4e9e36..7df83c0ff0 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -29,14 +29,11 @@ import javax.swing.SwingUtilities; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -50,16 +47,6 @@ import org.sleuthkit.datamodel.TskCoreException; */ abstract class AddTagAction { - @SuppressWarnings("deprecation") - protected void refreshDirectoryTree() { - - /* Note: this is a hack. In an ideal world, TagsManager would fire - * events so that the directory tree would refresh. But, we haven't - * had a chance to add that so, we fire these events and the tree - * refreshes based on them. - */ - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - } protected static final String NO_COMMENT = ""; /** @@ -93,7 +80,7 @@ abstract class AddTagAction { super(getActionDisplayName()); // Get the current set of tag names. - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + DrawableTagsManager tagsManager = controller.getTagsManager(); List tagNames = null; try { tagNames = tagsManager.getAllTagNames(); @@ -114,7 +101,7 @@ abstract class AddTagAction { MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); tagNameItem.setOnAction((ActionEvent t) -> { addTag(tagName, NO_COMMENT); - refreshDirectoryTree(); + DrawableTagsManager.fireTagsChangedEvent(); }); quickTagMenu.getItems().add(tagNameItem); } @@ -136,7 +123,7 @@ abstract class AddTagAction { TagName tagName = GetTagNameDialog.doDialog(); if (tagName != null) { addTag(tagName, NO_COMMENT); - refreshDirectoryTree(); + DrawableTagsManager.fireTagsChangedEvent(); } }); } catch (InterruptedException | InvocationTargetException ex) { @@ -159,7 +146,7 @@ abstract class AddTagAction { } else { new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } - refreshDirectoryTree(); + DrawableTagsManager.fireTagsChangedEvent(); } }); } catch (InterruptedException | InvocationTargetException ex) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 358516694e..b3bb065644 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -30,6 +30,7 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -159,7 +160,7 @@ public class CategorizeAction extends AddTagAction { JOptionPane.showMessageDialog(null, "Unable to categorize " + fileID + ".", "Categorizing Error", JOptionPane.ERROR_MESSAGE); } - refreshDirectoryTree(); + DrawableTagsManager.fireTagsChangedEvent(); } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java similarity index 69% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 38a8e40256..6a1a54c30d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -19,19 +19,18 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.Collections; +import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; @@ -39,23 +38,19 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Action to delete the follow up tag a - * - * */ -public class DeleteTagAction extends Action { +public class DeleteFollowUpTagAction extends Action { - private static final Logger LOGGER = Logger.getLogger(DeleteTagAction.class.getName()); + private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTagAction.class.getName()); private final long fileID; private final DrawableFile file; private final ImageGalleryController controller; - private final ContentTag tag; - public DeleteTagAction(ImageGalleryController controller, DrawableFile file, ContentTag tag) { + public DeleteFollowUpTagAction(ImageGalleryController controller, DrawableFile file) { super("Delete Follow Up Tag"); this.controller = controller; this.file = file; this.fileID = file.getId(); - this.tag = tag; setEventHandler((ActionEvent t) -> { deleteTag(); }); @@ -63,27 +58,28 @@ public class DeleteTagAction extends Action { /** * - * @param fileID1 the value of fileID1 * - * @throws IllegalStateException + * */ - private void deleteTag() throws IllegalStateException { + private void deleteTag() { final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); final GroupManager groupManager = controller.getGroupManager(); + final DrawableTagsManager tagsManager = controller.getTagsManager(); try { + final TagName followUpTagName = tagsManager.getFollowUpTagName(); // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, tag.getName()), fileID); - sleuthKitCase.deleteContentTag(tag); -// -// List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); -// for (ContentTag ct : contentTagsByContent) { -// if (ct.getName().getDisplayName().equals(tagsManager.getFollowUpTagName().getDisplayName())) { -// sleuthKitCase.deleteContentTag(ct); -// } -// } - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); + + List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); + for (ContentTag ct : contentTagsByContent) { + if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { + sleuthKitCase.deleteContentTag(ct); + } + } + + DrawableTagsManager.fireTagsChangedEvent(); //make sure rest of ui hears category change. groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); @@ -91,4 +87,5 @@ public class DeleteTagAction extends Action { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index b043bf126d..49b0818e3b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -1058,7 +1058,7 @@ public final class DrawableDB { public List> getFilesWithCategory(Category cat) throws TskCoreException, IllegalArgumentException { try { List> files = new ArrayList<>(); - List contentTags = tskCase.getContentTagsByTagName(controller.getTagsManager().getTagName(cat)); + List contentTags = controller.getTagsManager().getContentTagsByTagName(controller.getTagsManager().getTagName(cat)); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile) { files.add(DrawableFile.create((AbstractFile) ct.getContent(), isFileAnalyzed(ct.getContent().getId()), @@ -1145,7 +1145,7 @@ public final class DrawableDB { * in. * * - * //TODO: why does this go to the SKC? don't we already have this in =fo + * //TODO: why does this go to the SKC? don't we already have this info * in the drawable db? */ @Nonnull diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 78bb8c6401..bd4c84dd5e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -170,19 +170,16 @@ public abstract class DrawableFile extends AbstractFile public Set getTagNames() { try { - List contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(this); - return contentTagsByContent.stream() + return getSleuthkitCase().getContentTagsByContent(this).stream() .map(Tag::getName) .collect(Collectors.toSet()); - } catch (TskCoreException ex) { Logger.getAnonymousLogger().log(Level.WARNING, "problem looking up " + DrawableAttribute.TAGS.getDisplayName() + " for " + file.getName(), ex); - return Collections.emptySet(); } catch (IllegalStateException ex) { Logger.getAnonymousLogger().log(Level.WARNING, "there is no case open; failed to look up " + DrawableAttribute.TAGS.getDisplayName() + " for " + file.getName()); - return Collections.emptySet(); } + return Collections.emptySet(); } @Deprecated @@ -275,7 +272,8 @@ public abstract class DrawableFile extends AbstractFile public void updateCategory() { try { - List contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(this); + + List contentTagsByContent = getSleuthkitCase().getContentTagsByContent(this); Category cat = null; for (ContentTag ct : contentTagsByContent) { if (ct.getName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index dab1f9743f..221c7ef4d1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -40,6 +40,9 @@ import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; import javax.swing.SortOrder; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -80,11 +83,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { private DrawableDB db; private final ImageGalleryController controller; + /** * map from {@link GroupKey}s to {@link DrawableGroup}s. All groups (even - * not - * fully analyzed or not visible groups could be in this map + * not fully analyzed or not visible groups could be in this map */ + @GuardedBy("this") private final Map, DrawableGroup> groupMap = new HashMap<>(); /** @@ -153,7 +157,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { Set> resultSet = new HashSet<>(); for (Comparable val : groupBy.getValue(file)) { if (groupBy == DrawableAttribute.TAGS) { - if (((TagName) val).getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) { + if (Category.isCategoryTagName((TagName) val) == false) { resultSet.add(new GroupKey(groupBy, val)); } } else { @@ -189,9 +193,24 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * or * null if no group exists for that key. */ - public DrawableGroup getGroupForKey(GroupKey groupKey) { + @Nullable + public DrawableGroup getGroupForKey(@Nonnull GroupKey groupKey) { synchronized (groupMap) { + if (groupKey.getAttribute() == DrawableAttribute.TAGS) { + + System.out.println(groupKey); +// @SuppressWarnings("unchecked") +// GroupKey tagKey = (GroupKey) groupKey; +// +// return groupMap.keySet().stream() +// .filter((GroupKey t) -> t.getAttribute() == DrawableAttribute.TAGS) +// .map((GroupKey t) -> (GroupKey) t) +// .filter(t -> tagKey.getValue().getDisplayName().equals(t.getValue().getDisplayName())) +// .findFirst().map(groupMap::get).orElse(null); + + } //else { return groupMap.get(groupKey); +// } } } @@ -443,7 +462,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { values = (List) Arrays.asList(Category.values()); break; case TAGS: - values = (List) Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse().stream() + values = (List) controller.getTagsManager().getTagNamesInUse().stream() .filter(t -> t.getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) .collect(Collectors.toList()); break; @@ -525,14 +544,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public Set getFileIDsWithTag(TagName tagName) throws TskCoreException { try { Set files = new HashSet<>(); - List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName); + List contentTags = controller.getTagsManager().getContentTagsByTagName(tagName); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { - files.add(ct.getContent().getId()); } } - return files; } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "TSK error getting files with Tag:" + tagName.getDisplayName(), ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 7f29af775e..52ac70def0 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -67,7 +67,7 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; -import org.sleuthkit.autopsy.imagegallery.actions.DeleteTagAction; +import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -257,17 +257,17 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @SuppressWarnings("deprecation") protected void initialize() { - followUpToggle.setOnAction((ActionEvent t) -> { - + followUpToggle.setOnAction((ActionEvent event) -> { if (followUpToggle.isSelected() == true) { - globalSelectionModel.clearAndSelect(fileID); try { - new AddDrawableTagAction(controller).addTag(ImageGalleryController.getDefault().getTagsManager().getFollowUpTagName(), ""); + final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); + globalSelectionModel.clearAndSelect(fileID); + new AddDrawableTagAction(controller).addTag(followUpTagName, ""); } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to add follow up tag. Could not load TagName.", ex); + LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); } } else { - new DeleteTagAction(controller, file).handle(t); + new DeleteFollowUpTagAction(controller, file).handle(event); } }); } @@ -290,7 +290,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie } protected boolean hasFollowUp() throws TskCoreException { - String followUpTagName = ImageGalleryController.getDefault().getTagsManager().getFollowUpTagName().getDisplayName(); + String followUpTagName = getController().getTagsManager().getFollowUpTagName().getDisplayName(); Collection tagNames = DrawableAttribute.TAGS.getValue(getFile()); return tagNames.stream().anyMatch((tn) -> tn.getDisplayName().equals(followUpTagName)); } From 4ae9eaf01915a1b2117714562ed7cadfd0986d14 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 17 Jun 2015 15:54:34 -0400 Subject: [PATCH 051/198] more cleanup of Categories/Tags and listening to autopsy generated "Tag Events" -remove unused code from Category.java -use Category.isCategoryTagName instead of .getDisplayName().startsWith(Category.CATEGORY_PREFIX) -regroup when notified of Tag Change from autopsy --- .../imagegallery/DrawableTagsManager.java | 3 +- .../imagegallery/ImageGalleryController.java | 229 +++++++++--------- .../imagegallery/actions/AddTagAction.java | 4 +- .../actions/CategorizeAction.java | 4 +- .../imagegallery/datamodel/Category.java | 29 +-- .../datamodel/CategoryManager.java | 1 - .../imagegallery/datamodel/DrawableFile.java | 22 +- .../imagegallery/grouping/GroupManager.java | 17 +- .../imagegallery/gui/DrawableView.java | 32 +-- .../imagegallery/gui/MetaDataPane.java | 18 +- 10 files changed, 181 insertions(+), 178 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 7ba9ceb842..2639de7617 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -22,6 +22,7 @@ import com.google.common.eventbus.EventBus; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.logging.Level; import java.util.stream.Collectors; import org.sleuthkit.autopsy.casemodule.services.TagsManager; @@ -111,7 +112,7 @@ public class DrawableTagsManager { * @throws TskCoreException */ synchronized public TagName getFollowUpTagName() throws TskCoreException { - if (followUpTagName == null) { + if (Objects.isNull(followUpTagName)) { followUpTagName = getTagName(FOLLOW_UP); } return followUpTagName; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 4bed46a023..11fd505ba6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.imagegallery; import java.beans.PropertyChangeEvent; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.BlockingQueue; @@ -57,7 +58,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.History; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -68,6 +68,7 @@ import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; import org.sleuthkit.autopsy.imagegallery.gui.SummaryTablePane; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -83,25 +84,25 @@ import org.sleuthkit.datamodel.TskData; * control. */ public final class ImageGalleryController { - + private static final Logger LOGGER = Logger.getLogger(ImageGalleryController.class.getName()); - + private final Region infoOverLayBackground = new Region() { { setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY))); setOpacity(.4); } }; - + private static ImageGalleryController instance; - + public static synchronized ImageGalleryController getDefault() { if (instance == null) { instance = new ImageGalleryController(); } return instance; } - + private final History historyManager = new History<>(); /** @@ -109,75 +110,75 @@ public final class ImageGalleryController { * not listen to speed up ingest */ private final SimpleBooleanProperty listeningEnabled = new SimpleBooleanProperty(false); - + private final ReadOnlyIntegerWrapper queueSizeProperty = new ReadOnlyIntegerWrapper(0); - + private final ReadOnlyBooleanWrapper regroupDisabled = new ReadOnlyBooleanWrapper(false); - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private final ReadOnlyBooleanWrapper stale = new ReadOnlyBooleanWrapper(false); - + private final ReadOnlyBooleanWrapper metaDataCollapsed = new ReadOnlyBooleanWrapper(false); - + private final FileIDSelectionModel selectionModel = FileIDSelectionModel.getInstance(); - + private DBWorkerThread dbWorkerThread; - + private DrawableDB db; - + private final GroupManager groupManager = new GroupManager(this); private final HashSetManager hashSetManager = new HashSetManager(); private final CategoryManager categoryManager = new CategoryManager(this); private final DrawableTagsManager tagsManager = new DrawableTagsManager(null); - + private StackPane fullUIStackPane; - + private StackPane centralStackPane; - + private Node infoOverlay; private SleuthkitCase sleuthKitCase; - + public ReadOnlyBooleanProperty getMetaDataCollapsed() { return metaDataCollapsed.getReadOnlyProperty(); } - + public void setMetaDataCollapsed(Boolean metaDataCollapsed) { this.metaDataCollapsed.set(metaDataCollapsed); } - + private GroupViewState getViewState() { return historyManager.getCurrentState(); } - + public ReadOnlyBooleanProperty regroupDisabled() { return regroupDisabled.getReadOnlyProperty(); } - + public ReadOnlyObjectProperty viewState() { return historyManager.currentState(); } - + public synchronized FileIDSelectionModel getSelectionModel() { - + return selectionModel; } - + public GroupManager getGroupManager() { return groupManager; } - + public DrawableDB getDatabase() { return db; } - + synchronized public void setListeningEnabled(boolean enabled) { listeningEnabled.set(enabled); } - + synchronized boolean isListeningEnabled() { return listeningEnabled.get(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.ANY) void setStale(Boolean b) { Platform.runLater(() -> { @@ -187,18 +188,18 @@ public final class ImageGalleryController { new PerCaseProperties(Case.getCurrentCase()).setConfigSetting(ImageGalleryModule.getModuleName(), PerCaseProperties.STALE, b.toString()); } } - + public ReadOnlyBooleanProperty stale() { return stale.getReadOnlyProperty(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) boolean isStale() { return stale.get(); } - + private ImageGalleryController() { - + listeningEnabled.addListener((observable, oldValue, newValue) -> { //if we just turned on listening and a case is open and that case is not up to date if (newValue && !oldValue && Case.existsCurrentCase() && ImageGalleryModule.isDrawableDBStale(Case.getCurrentCase())) { @@ -206,28 +207,28 @@ public final class ImageGalleryController { queueDBWorkerTask(new CopyAnalyzedFiles()); } }); - + groupManager.getAnalyzedGroups().addListener((Observable o) -> { if (Case.isCaseOpen()) { checkForGroups(); } }); - + groupManager.getUnSeenGroups().addListener((Observable observable) -> { //if there are unseen groups and none being viewed if (groupManager.getUnSeenGroups().isEmpty() == false && (getViewState() == null || getViewState().getGroup() == null)) { advance(GroupViewState.tile(groupManager.getUnSeenGroups().get(0))); } }); - + viewState().addListener((Observable observable) -> { selectionModel.clearSelection(); }); - + regroupDisabled.addListener((Observable observable) -> { checkForGroups(); }); - + IngestManager.getInstance().addIngestModuleEventListener((PropertyChangeEvent evt) -> { Platform.runLater(this::updateRegroupDisabled); }); @@ -236,27 +237,27 @@ public final class ImageGalleryController { }); // metaDataCollapsed.bind(Toolbar.getDefault().showMetaDataProperty()); } - + public ReadOnlyBooleanProperty getCanAdvance() { return historyManager.getCanAdvance(); } - + public ReadOnlyBooleanProperty getCanRetreat() { return historyManager.getCanRetreat(); } - + public void advance(GroupViewState newState) { historyManager.advance(newState); } - + public GroupViewState advance() { return historyManager.advance(); } - + public GroupViewState retreat() { return historyManager.retreat(); } - + private void updateRegroupDisabled() { regroupDisabled.set(getFileUpdateQueueSizeProperty().get() > 0 || IngestManager.getInstance().isIngestRunning()); } @@ -278,7 +279,7 @@ public final class ImageGalleryController { new NoGroupsDialog("No groups are fully analyzed yet, but ingest is still ongoing. Please Wait.", new ProgressIndicator())); } - + } else if (getFileUpdateQueueSizeProperty().get() > 0) { replaceNotification(fullUIStackPane, new NoGroupsDialog("No groups are fully analyzed yet, but image / video data is still being populated. Please Wait.", @@ -292,19 +293,19 @@ public final class ImageGalleryController { replaceNotification(fullUIStackPane, new NoGroupsDialog("There are no images/videos in the added datasources.")); } - + } else if (!groupManager.isRegrouping()) { replaceNotification(centralStackPane, new NoGroupsDialog("There are no fully analyzed groups to display:" + " the current Group By setting resulted in no groups, " + "or no groups are fully analyzed but ingest is not running.")); } - + } else { clearNotification(); } } - + private void clearNotification() { //remove the ingest spinner if (fullUIStackPane != null) { @@ -315,27 +316,27 @@ public final class ImageGalleryController { centralStackPane.getChildren().remove(infoOverlay); } } - + private void replaceNotification(StackPane stackPane, Node newNode) { clearNotification(); - + infoOverlay = new StackPane(infoOverLayBackground, newNode); if (stackPane != null) { stackPane.getChildren().add(infoOverlay); } } - + private void restartWorker() { if (dbWorkerThread != null) { // Keep using the same worker thread if one exists return; } dbWorkerThread = new DBWorkerThread(); - + getFileUpdateQueueSizeProperty().addListener((Observable o) -> { Platform.runLater(this::updateRegroupDisabled); }); - + Thread th = new Thread(dbWorkerThread); th.setDaemon(false); // we want it to go away when it is done th.start(); @@ -350,7 +351,7 @@ public final class ImageGalleryController { if (Objects.nonNull(theNewCase)) { this.sleuthKitCase = theNewCase.getSleuthkitCase(); this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); - + setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); @@ -362,7 +363,9 @@ public final class ImageGalleryController { hashSetManager.setDb(db); categoryManager.setDb(db); tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); + tagsManager.registerListener(groupManager); SummaryTablePane.getDefault().refresh(); + } else { reset(); } @@ -379,9 +382,9 @@ public final class ImageGalleryController { Platform.runLater(() -> { historyManager.clear(); }); - Category.clearTagNames(); tagsManager.clearFollowUpTagName(); - + tagsManager.unregisterListener(groupManager); + Toolbar.getDefault(this).reset(); groupManager.clear(); if (db != null) { @@ -403,21 +406,21 @@ public final class ImageGalleryController { } dbWorkerThread.addTask(innerTask); } - + public DrawableFile getFileFromId(Long fileID) throws TskCoreException { return db.getFileFromID(fileID); } - + public void setStacks(StackPane fullUIStack, StackPane centralStack) { fullUIStackPane = fullUIStack; this.centralStackPane = centralStack; Platform.runLater(this::checkForGroups); } - + public ReadOnlyIntegerProperty getFileUpdateQueueSizeProperty() { return queueSizeProperty.getReadOnlyProperty(); } - + public ReadOnlyDoubleProperty regroupProgress() { return groupManager.regroupProgress(); } @@ -436,6 +439,10 @@ public final class ImageGalleryController { case CONTENT_CHANGED: //TODO: do we need to do anything here? -jm case DATA_ADDED: + ModuleDataEvent oldValue = (ModuleDataEvent) evt.getOldValue(); + if ("TagAction".equals(oldValue.getModuleName()) && oldValue.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { + getTagsManager().fireChange(Collections.singleton(-1L)); + } /* we could listen to DATA events and progressivly * update files, and get data from DataSource ingest * modules, but given that most modules don't post new @@ -489,15 +496,15 @@ public final class ImageGalleryController { } }); } - + public HashSetManager getHashSetManager() { return hashSetManager; } - + public CategoryManager getCategoryManager() { return categoryManager; } - + public DrawableTagsManager getTagsManager() { return tagsManager; } @@ -538,7 +545,7 @@ public final class ImageGalleryController { queueSizeProperty.set(workQueue.size()); }); } - + @Override public void run() { @@ -549,22 +556,22 @@ public final class ImageGalleryController { } try { InnerTask it = workQueue.take(); - + if (it.cancelled == false) { it.run(); } - + Platform.runLater(() -> { queueSizeProperty.set(workQueue.size()); }); - + } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); } } } } - + public synchronized SleuthkitCase getSleuthKitCase() { return sleuthKitCase; } @@ -573,55 +580,55 @@ public final class ImageGalleryController { * Abstract base class for task to be done on {@link DBWorkerThread} */ static public abstract class InnerTask implements Runnable { - + public double getProgress() { return progress.get(); } - + public final void updateProgress(Double workDone) { this.progress.set(workDone); } - + public String getMessage() { return message.get(); } - + public final void updateMessage(String Status) { this.message.set(Status); } SimpleObjectProperty state = new SimpleObjectProperty<>(Worker.State.READY); SimpleDoubleProperty progress = new SimpleDoubleProperty(this, "pregress"); SimpleStringProperty message = new SimpleStringProperty(this, "status"); - + public SimpleDoubleProperty progressProperty() { return progress; } - + public SimpleStringProperty messageProperty() { return message; } - + public Worker.State getState() { return state.get(); } - + protected void updateState(Worker.State newState) { state.set(newState); } - + public ReadOnlyObjectProperty stateProperty() { return new ReadOnlyObjectWrapper<>(state.get()); } - + protected InnerTask() { } - + protected volatile boolean cancelled = false; - + public void cancel() { updateState(Worker.State.CANCELLED); } - + protected boolean isCancelled() { return getState() == Worker.State.CANCELLED; } @@ -631,25 +638,25 @@ public final class ImageGalleryController { * Abstract base class for tasks associated with a file in the database */ static public abstract class FileTask extends InnerTask { - + private final AbstractFile file; - + public AbstractFile getFile() { return file; } - + public FileTask(AbstractFile f) { super(); this.file = f; } - + } /** * task that updates one file in database with results from ingest */ private class UpdateFileTask extends FileTask { - + public UpdateFileTask(AbstractFile f) { super(f); } @@ -676,7 +683,7 @@ public final class ImageGalleryController { * task that updates one file in database with results from ingest */ private class RemoveFileTask extends FileTask { - + public RemoveFileTask(AbstractFile f) { super(f); } @@ -695,7 +702,7 @@ public final class ImageGalleryController { Logger.getLogger(RemoveFileTask.class.getName()).log(Level.SEVERE, "Case was closed out from underneath RemoveFile task"); } } - + } } @@ -707,16 +714,16 @@ public final class ImageGalleryController { * adds them to the Drawable DB */ private class CopyAnalyzedFiles extends InnerTask { - + final private String DRAWABLE_QUERY = "name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "'"; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("populating analyzed image/video database"); - + @Override public void run() { progressHandle.start(); updateMessage("populating analyzed image/video database"); - + try { //grab all files with supported extension or detected mime types final List files = getSleuthKitCase().findAllFilesWhere(DRAWABLE_QUERY + " or tsk_files.obj_id in (select tsk_files.obj_id from tsk_files , blackboard_artifacts, blackboard_attributes" @@ -726,7 +733,7 @@ public final class ImageGalleryController { + " and blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID() + " and blackboard_attributes.value_text in ('" + StringUtils.join(ImageGalleryModule.getSupportedMimes(), "','") + "'))"); progressHandle.switchToDeterminate(files.size()); - + updateProgress(0.0); //do in transaction @@ -740,7 +747,7 @@ public final class ImageGalleryController { } final Boolean hasMimeType = ImageGalleryModule.hasSupportedMimeType(f); final boolean known = f.getKnown() == TskData.FileKnown.KNOWN; - + if (known) { db.removeFile(f.getId(), tr); //remove known files } else { @@ -760,38 +767,38 @@ public final class ImageGalleryController { } } } - + units++; final int prog = units; progressHandle.progress(f.getName(), units); updateProgress(prog - 1 / (double) files.size()); updateMessage(f.getName()); } - + progressHandle.finish(); - + progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); updateMessage("commiting image/video database"); updateProgress(1.0); - + progressHandle.start(); db.commitTransaction(tr, true); - + } catch (TskCoreException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.SEVERE, "Case was closed out from underneath CopyDataSource task", ex); } - + progressHandle.finish(); - + updateMessage( ""); updateProgress( -1.0); setStale(false); } - + } /** @@ -802,7 +809,7 @@ public final class ImageGalleryController { * netbeans and ImageGallery progress/status */ class PrePopulateDataSourceFiles extends InnerTask { - + private final Content dataSource; /** @@ -812,7 +819,7 @@ public final class ImageGalleryController { */ // (name like '.jpg' or name like '.png' ...) private final String DRAWABLE_QUERY = "(name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "') "; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("prepopulating image/video database"); /** @@ -838,7 +845,7 @@ public final class ImageGalleryController { final List files; try { List fsObjIds = new ArrayList<>(); - + String fsQuery; if (dataSource instanceof Image) { Image image = (Image) dataSource; @@ -852,7 +859,7 @@ public final class ImageGalleryController { else { fsQuery = "(fs_obj_id IS NULL) "; } - + files = getSleuthKitCase().findAllFilesWhere(fsQuery + " and " + DRAWABLE_QUERY); progressHandle.switchToDeterminate(files.size()); @@ -870,21 +877,21 @@ public final class ImageGalleryController { final int prog = units; progressHandle.progress(f.getName(), units); } - + progressHandle.finish(); progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); - + progressHandle.start(); db.commitTransaction(tr, false); - + } catch (TskCoreException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException | NullPointerException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "Case was closed out from underneath prepopulating database"); } - + progressHandle.finish(); } } - + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 7df83c0ff0..b933d592d4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -97,7 +97,7 @@ abstract class AddTagAction { // a tag with the associated tag name. if (null != tagNames && !tagNames.isEmpty()) { for (final TagName tagName : tagNames) { - if (tagName.getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) { + if (Category.isNotCategoryTagName(tagName)) { MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); tagNameItem.setOnAction((ActionEvent t) -> { addTag(tagName, NO_COMMENT); @@ -141,7 +141,7 @@ abstract class AddTagAction { SwingUtilities.invokeAndWait(() -> { GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); if (null != tagNameAndComment) { - if (tagNameAndComment.getTagName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { + if (Category.isCategoryTagName(tagNameAndComment.getTagName())) { new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } else { new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index b3bb065644..1b84b005bf 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -141,9 +141,7 @@ public class CategorizeAction extends AddTagAction { List allContentTags = sleuthKitCase.getContentTagsByContent(file); //tsk db for (ContentTag ct : allContentTags) { - //this is bad: treating tags as categories as long as their names start with prefix - //TODO: abandon using tags for categories and instead add a new column to DrawableDB - if (ct.getName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { + if (Category.isCategoryTagName(ct.getName())) { sleuthKitCase.deleteContentTag(ct); //tsk db categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 0ded98426f..ee6a46098e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -43,30 +43,25 @@ public enum Category implements Comparable { Category::getDisplayName, Function.identity())); - public static final String CATEGORY_PREFIX = "CAT-"; - public static Category fromDisplayName(String displayName) { return nameMap.get(displayName); } - /** - * Use when closing a case to make sure everything is re-initialized in the - * next case. - */ - public static void clearTagNames() { - Category.ZERO.tagName = null; - Category.ONE.tagName = null; - Category.TWO.tagName = null; - Category.THREE.tagName = null; - Category.FOUR.tagName = null; - Category.FIVE.tagName = null; - } - public static boolean isCategoryTagName(TagName tName) { - return nameMap.containsKey(tName.getDisplayName()); + return isCategoryName(tName.getDisplayName()); } - private TagName tagName; + public static boolean isNotCategoryTagName(TagName tName) { + return isNotCategoryName(tName.getDisplayName()); + } + + public static boolean isCategoryName(String tName) { + return nameMap.containsKey(tName); + } + + public static boolean isNotCategoryName(String tName) { + return nameMap.containsKey(tName) == false; + } private final Color color; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 08ba1b17a5..0197c3c847 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -92,7 +92,6 @@ public class CategoryManager { this.db = db; categoryCounts.invalidateAll(); catTagNameMap.invalidateAll(); - Category.clearTagNames(); } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index bd4c84dd5e..4d3de0d553 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -46,7 +46,6 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBU import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.LONG; import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.SleuthkitItemVisitor; import org.sleuthkit.datamodel.Tag; @@ -111,7 +110,6 @@ public abstract class DrawableFile extends AbstractFile super(file.getSleuthkitCase(), file.getId(), file.getAttrType(), file.getAttrId(), file.getName(), file.getType(), file.getMetaAddr(), (int) file.getMetaSeq(), file.getDirType(), file.getMetaType(), null, new Integer(0).shortValue(), file.getSize(), file.getCtime(), file.getCrtime(), file.getAtime(), file.getMtime(), new Integer(0).shortValue(), file.getUid(), file.getGid(), file.getMd5Hash(), file.getKnown(), file.getParentPath()); this.analyzed = new SimpleBooleanProperty(analyzed); this.file = file; - } public abstract boolean isVideo(); @@ -272,20 +270,14 @@ public abstract class DrawableFile extends AbstractFile public void updateCategory() { try { + category.set(getSleuthkitCase().getContentTagsByContent(this).stream() + .map(Tag::getName).filter(Category::isCategoryTagName) + .findFirst() + .map(TagName::getDisplayName) + .map(Category::fromDisplayName) + .orElse(Category.ZERO) + ); - List contentTagsByContent = getSleuthkitCase().getContentTagsByContent(this); - Category cat = null; - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { - cat = Category.fromDisplayName(ct.getName().getDisplayName()); - break; - } - } - if (cat == null) { - category.set(Category.ZERO); - } else { - category.set(cat); - } } catch (TskCoreException ex) { Logger.getLogger(DrawableFile.class.getName()).log(Level.WARNING, "problem looking up category for file " + this.getName(), ex); } catch (IllegalStateException ex) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 221c7ef4d1..cd02ba9c0a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.grouping; +import com.google.common.eventbus.Subscribe; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; @@ -59,6 +60,7 @@ import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; +import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; @@ -157,7 +159,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { Set> resultSet = new HashSet<>(); for (Comparable val : groupBy.getValue(file)) { if (groupBy == DrawableAttribute.TAGS) { - if (Category.isCategoryTagName((TagName) val) == false) { + if (Category.isNotCategoryTagName((TagName) val)) { resultSet.add(new GroupKey(groupBy, val)); } } else { @@ -463,7 +465,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { break; case TAGS: values = (List) controller.getTagsManager().getTagNamesInUse().stream() - .filter(t -> t.getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) + .filter(Category::isNotCategoryTagName) .collect(Collectors.toList()); break; case ANALYZED: @@ -590,7 +592,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @param sortOrder * @param force true to force a full db query regroup */ - public > void regroup(final DrawableAttribute groupBy, final GroupSortBy sortBy, final SortOrder sortOrder, Boolean force) { + public synchronized > void regroup(final DrawableAttribute groupBy, final GroupSortBy sortBy, final SortOrder sortOrder, Boolean force) { if (!Case.isCaseOpen()) { return; @@ -633,6 +635,15 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { return regroupProgress.getReadOnlyProperty(); } + @Subscribe + public void handleAutopsyTagChange(TagsChangeEvent evt) { + if (groupBy == DrawableAttribute.TAGS + && evt.getFileIDs().size() == 1 + && evt.getFileIDs().contains(-1L)) { + regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); + } + } + /** * handle {@link FileUpdateEvent} sent from Db when files are * inserted/updated diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index ed0453ec0b..93dbae801e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -84,21 +84,25 @@ public interface DrawableView { } static Border getCategoryBorder(Category category) { - switch (category) { - case ONE: - return CAT1_BORDER; - case TWO: - return CAT2_BORDER; - case THREE: - return CAT3_BORDER; - case FOUR: - return CAT4_BORDER; - case FIVE: - return CAT5_BORDER; - case ZERO: - default: - return CAT0_BORDER; + if (category != null) { + switch (category) { + case ONE: + return CAT1_BORDER; + case TWO: + return CAT2_BORDER; + case THREE: + return CAT3_BORDER; + case FOUR: + return CAT4_BORDER; + case FIVE: + return CAT5_BORDER; + case ZERO: + default: + return CAT0_BORDER; + } + } else { + return CAT0_BORDER; } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index f9f6115d67..4ab6fff208 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -92,6 +92,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { } @FXML + @SuppressWarnings("unchecked") void initialize() { assert attributeColumn != null : "fx:id=\"attributeColumn\" was not injected: check your FXML file 'MetaDataPane.fxml'."; assert imageView != null : "fx:id=\"imageView\" was not injected: check your FXML file 'MetaDataPane.fxml'."; @@ -121,14 +122,12 @@ public class MetaDataPane extends AnchorPane implements DrawableView { attributeColumn.setPrefWidth(USE_COMPUTED_SIZE); valueColumn.setCellValueFactory((p) -> { - if (p.getValue().getKey() == DrawableAttribute.TAGS) { - return new SimpleStringProperty(((Collection) p.getValue().getValue()).stream() - .map(TagName::getDisplayName) - .filter((String t) -> t.startsWith(Category.CATEGORY_PREFIX) == false) - .collect(Collectors.joining(" ; ", "", ""))); - } else { - return new SimpleStringProperty(StringUtils.join((Iterable) p.getValue().getValue(), " ; ")); - } + return (p.getValue().getKey() == DrawableAttribute.TAGS) + ? new SimpleStringProperty(((Collection) p.getValue().getValue()).stream() + .map(TagName::getDisplayName) + .filter(Category::isNotCategoryName) + .collect(Collectors.joining(" ; "))) + : new SimpleStringProperty(StringUtils.join((Iterable) p.getValue().getValue(), " ; ")); }); valueColumn.setPrefWidth(USE_COMPUTED_SIZE); valueColumn.setCellFactory((p) -> new TableCell, ? extends Object>, String>() { @@ -150,9 +149,6 @@ public class MetaDataPane extends AnchorPane implements DrawableView { controller.getSelectionModel().lastSelectedProperty().addListener((observable, oldFileID, newFileID) -> { setFile(newFileID); }); - -// MetaDataPane.this.visibleProperty().bind(controller.getMetaDataCollapsed().not()); -// MetaDataPane.this.managedProperty().bind(controller.getMetaDataCollapsed().not()); } @Override From d39644687b6cb5c295a7e8b246a010f5d98fcda1 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 17 Jun 2015 17:42:00 -0400 Subject: [PATCH 052/198] more work to keep autopsy and ImageGallery tags in sync add setFiles method to DrawableGroup; don't clear groups from GroupMap except for CaseChange; reuse groups via setFiles method when regrouping reselect group in navpanel after regroup --- .../imagegallery/DrawableTagsManager.java | 2 +- .../imagegallery/grouping/DrawableGroup.java | 25 +++++++-- .../imagegallery/grouping/GroupManager.java | 56 ++++++++----------- .../imagegallery/gui/navpanel/NavPanel.java | 6 ++ 4 files changed, 50 insertions(+), 39 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 2639de7617..149c7fd888 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index b59a1b8edd..386ae51d65 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -134,7 +134,7 @@ public class DrawableGroup implements Comparable { ((DrawableGroup) obj).groupKey); } - synchronized public void addFile(Long f) { + synchronized void addFile(Long f) { invalidateHashSetHitsCount(); if (fileIDs.contains(f) == false) { fileIDs.add(f); @@ -142,7 +142,21 @@ public class DrawableGroup implements Comparable { } } - synchronized public void removeFile(Long f) { + synchronized void setFiles(Set newFileIds) { + invalidateHashSetHitsCount(); + boolean filesRemoved = fileIDs.removeIf((Long t) -> newFileIds.contains(t) == false); + if (filesRemoved) { + seen.set(false); + } + for (Long f : newFileIds) { + if (fileIDs.contains(f) == false) { + fileIDs.add(f); + seen.set(false); + } + } + } + + synchronized void removeFile(Long f) { invalidateHashSetHitsCount(); if (fileIDs.removeAll(f)) { seen.set(false); @@ -151,11 +165,13 @@ public class DrawableGroup implements Comparable { // By default, sort by group key name @Override - public int compareTo(DrawableGroup other) { + public int compareTo(DrawableGroup other + ) { return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName()); } - void setSeen(boolean isSeen) { + void setSeen(boolean isSeen + ) { this.seen.set(isSeen); } @@ -166,4 +182,5 @@ public class DrawableGroup implements Comparable { public boolean isSeen() { return seen.get(); } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index cd02ba9c0a..a79b8e3b48 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -198,21 +198,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Nullable public DrawableGroup getGroupForKey(@Nonnull GroupKey groupKey) { synchronized (groupMap) { - if (groupKey.getAttribute() == DrawableAttribute.TAGS) { - - System.out.println(groupKey); -// @SuppressWarnings("unchecked") -// GroupKey tagKey = (GroupKey) groupKey; -// -// return groupMap.keySet().stream() -// .filter((GroupKey t) -> t.getAttribute() == DrawableAttribute.TAGS) -// .map((GroupKey t) -> (GroupKey) t) -// .filter(t -> tagKey.getValue().getDisplayName().equals(t.getValue().getDisplayName())) -// .findFirst().map(groupMap::get).orElse(null); - - } //else { return groupMap.get(groupKey); -// } } } @@ -255,7 +241,8 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { /** * make and return a new group with the given key and files. If a group - * already existed for that key, it will be replaced. + * already existed for that key, it will be updated to contain the given + * files. * * NOTE: this is the only API for making a new group. * @@ -265,28 +252,33 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @return the new DrawableGroup for the given key */ public DrawableGroup makeGroup(GroupKey groupKey, Set files) { - - Set newFiles = ObjectUtils.defaultIfNull(files, new HashSet()); - final boolean groupSeen = db.isGroupSeen(groupKey); - DrawableGroup g = new DrawableGroup(groupKey, newFiles, groupSeen); - - g.seenProperty().addListener((observable, oldSeen, newSeen) -> { - markGroupSeen(g, newSeen); - }); synchronized (groupMap) { - groupMap.put(groupKey, g); + if (groupMap.containsKey(groupKey)) { + DrawableGroup group = groupMap.get(groupKey); + group.setFiles(ObjectUtils.defaultIfNull(files, Collections.emptySet())); + return group; + } else { + final boolean groupSeen = db.isGroupSeen(groupKey); + DrawableGroup group = new DrawableGroup(groupKey, files, groupSeen); + group.seenProperty().addListener((observable, oldSeen, newSeen) -> { + markGroupSeen(group, newSeen); + }); + groupMap.put(groupKey, group); + return group; + } } - return g; } /** - * 'mark' the given group as seen. This removes it from the queue of groups + * 'mark' the given group as seen. This removes it from the queue of + * groups * to review, and is persisted in the drawable db. * * @param group the {@link DrawableGroup} to mark as seen */ @ThreadConfined(type = ThreadType.JFX) - public void markGroupSeen(DrawableGroup group, boolean seen) { + public void markGroupSeen(DrawableGroup group, boolean seen + ) { db.markGroupSeen(group.getGroupKey(), seen); group.setSeen(seen); if (seen) { @@ -314,9 +306,6 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { // If we're grouping by category, we don't want to remove empty groups. if (groupKey.getAttribute() != DrawableAttribute.CATEGORY) { if (group.fileIds().isEmpty()) { - synchronized (groupMap) { - groupMap.remove(groupKey, group); - } Platform.runLater(() -> { analyzedGroups.remove(group); unSeenGroups.remove(group); @@ -624,6 +613,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder)); }); } + } /** @@ -723,6 +713,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { controller.getTagsManager().fireChange(fileIDs); } break; + } } @@ -768,14 +759,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { unSeenGroups.clear(); } }); - synchronized (groupMap) { - groupMap.clear(); - } // Get the list of group keys final List vals = findValuesForAttribute(groupBy); - // Make a list of each group + // Make a list of each group final List groups = new ArrayList<>(); groupProgress.start(vals.size()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java index 09b025d75e..482ff66f7c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java @@ -155,6 +155,7 @@ public class NavPanel extends TabPane { initNavTree(); controller.getGroupManager().getAnalyzedGroups().addListener((ListChangeListener.Change change) -> { + TreeItem selectedItem = activeTreeProperty.get().getSelectionModel().getSelectedItem(); boolean wasPermuted = false; while (change.next()) { for (DrawableGroup g : change.getAddedSubList()) { @@ -175,6 +176,11 @@ public class NavPanel extends TabPane { if (wasPermuted) { rebuildTrees(); + } + if (selectedItem != null) { + Platform.runLater(() -> { + setFocusedGroup(selectedItem.getValue().getGroup()); + }); } }); From 7d68ed1b66689f83330d781baf32570caade9591 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 11:39:16 -0400 Subject: [PATCH 053/198] refactor in GroupManager, to make logic and flow cleaner split FileUpdateEvent handlers to seperate update and removed methods name DbWorkerThread, Thread --- .../autopsy/imagegallery/FileUpdateEvent.java | 5 +- .../imagegallery/ImageGalleryController.java | 222 ++++++------ .../imagegallery/actions/NextUnseenGroup.java | 1 + .../imagegallery/datamodel/DrawableDB.java | 2 +- .../imagegallery/grouping/DrawableGroup.java | 6 +- .../imagegallery/grouping/GroupManager.java | 323 +++++++----------- .../imagegallery/gui/navpanel/NavPanel.java | 4 +- 7 files changed, 238 insertions(+), 325 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java index 038ac4bafb..c2803a5090 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.imagegallery; import java.util.Collection; +import java.util.Collections; import java.util.EventListener; import java.util.HashSet; import java.util.Set; @@ -43,7 +44,7 @@ public class FileUpdateEvent { } public Collection getFileIDs() { - return fileIDs; + return Collections.unmodifiableCollection(fileIDs); } public DrawableAttribute getChangedAttribute() { @@ -86,5 +87,7 @@ public class FileUpdateEvent { public static interface FileUpdateListener extends EventListener { public void handleFileUpdate(FileUpdateEvent evt); + + public void handleFileRemoved(FileUpdateEvent evt); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 11fd505ba6..e649afbc39 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -84,25 +84,25 @@ import org.sleuthkit.datamodel.TskData; * control. */ public final class ImageGalleryController { - + private static final Logger LOGGER = Logger.getLogger(ImageGalleryController.class.getName()); - + private final Region infoOverLayBackground = new Region() { { setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY))); setOpacity(.4); } }; - + private static ImageGalleryController instance; - + public static synchronized ImageGalleryController getDefault() { if (instance == null) { instance = new ImageGalleryController(); } return instance; } - + private final History historyManager = new History<>(); /** @@ -110,75 +110,75 @@ public final class ImageGalleryController { * not listen to speed up ingest */ private final SimpleBooleanProperty listeningEnabled = new SimpleBooleanProperty(false); - + private final ReadOnlyIntegerWrapper queueSizeProperty = new ReadOnlyIntegerWrapper(0); - + private final ReadOnlyBooleanWrapper regroupDisabled = new ReadOnlyBooleanWrapper(false); - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private final ReadOnlyBooleanWrapper stale = new ReadOnlyBooleanWrapper(false); - + private final ReadOnlyBooleanWrapper metaDataCollapsed = new ReadOnlyBooleanWrapper(false); - + private final FileIDSelectionModel selectionModel = FileIDSelectionModel.getInstance(); - + private DBWorkerThread dbWorkerThread; - + private DrawableDB db; - + private final GroupManager groupManager = new GroupManager(this); private final HashSetManager hashSetManager = new HashSetManager(); private final CategoryManager categoryManager = new CategoryManager(this); private final DrawableTagsManager tagsManager = new DrawableTagsManager(null); - + private StackPane fullUIStackPane; - + private StackPane centralStackPane; - + private Node infoOverlay; private SleuthkitCase sleuthKitCase; - + public ReadOnlyBooleanProperty getMetaDataCollapsed() { return metaDataCollapsed.getReadOnlyProperty(); } - + public void setMetaDataCollapsed(Boolean metaDataCollapsed) { this.metaDataCollapsed.set(metaDataCollapsed); } - + private GroupViewState getViewState() { return historyManager.getCurrentState(); } - + public ReadOnlyBooleanProperty regroupDisabled() { return regroupDisabled.getReadOnlyProperty(); } - + public ReadOnlyObjectProperty viewState() { return historyManager.currentState(); } - + public synchronized FileIDSelectionModel getSelectionModel() { - + return selectionModel; } - + public GroupManager getGroupManager() { return groupManager; } - + public DrawableDB getDatabase() { return db; } - + synchronized public void setListeningEnabled(boolean enabled) { listeningEnabled.set(enabled); } - + synchronized boolean isListeningEnabled() { return listeningEnabled.get(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.ANY) void setStale(Boolean b) { Platform.runLater(() -> { @@ -188,18 +188,18 @@ public final class ImageGalleryController { new PerCaseProperties(Case.getCurrentCase()).setConfigSetting(ImageGalleryModule.getModuleName(), PerCaseProperties.STALE, b.toString()); } } - + public ReadOnlyBooleanProperty stale() { return stale.getReadOnlyProperty(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) boolean isStale() { return stale.get(); } - + private ImageGalleryController() { - + listeningEnabled.addListener((observable, oldValue, newValue) -> { //if we just turned on listening and a case is open and that case is not up to date if (newValue && !oldValue && Case.existsCurrentCase() && ImageGalleryModule.isDrawableDBStale(Case.getCurrentCase())) { @@ -207,28 +207,28 @@ public final class ImageGalleryController { queueDBWorkerTask(new CopyAnalyzedFiles()); } }); - + groupManager.getAnalyzedGroups().addListener((Observable o) -> { if (Case.isCaseOpen()) { checkForGroups(); } }); - + groupManager.getUnSeenGroups().addListener((Observable observable) -> { //if there are unseen groups and none being viewed if (groupManager.getUnSeenGroups().isEmpty() == false && (getViewState() == null || getViewState().getGroup() == null)) { advance(GroupViewState.tile(groupManager.getUnSeenGroups().get(0))); } }); - + viewState().addListener((Observable observable) -> { selectionModel.clearSelection(); }); - + regroupDisabled.addListener((Observable observable) -> { checkForGroups(); }); - + IngestManager.getInstance().addIngestModuleEventListener((PropertyChangeEvent evt) -> { Platform.runLater(this::updateRegroupDisabled); }); @@ -237,27 +237,27 @@ public final class ImageGalleryController { }); // metaDataCollapsed.bind(Toolbar.getDefault().showMetaDataProperty()); } - + public ReadOnlyBooleanProperty getCanAdvance() { return historyManager.getCanAdvance(); } - + public ReadOnlyBooleanProperty getCanRetreat() { return historyManager.getCanRetreat(); } - + public void advance(GroupViewState newState) { historyManager.advance(newState); } - + public GroupViewState advance() { return historyManager.advance(); } - + public GroupViewState retreat() { return historyManager.retreat(); } - + private void updateRegroupDisabled() { regroupDisabled.set(getFileUpdateQueueSizeProperty().get() > 0 || IngestManager.getInstance().isIngestRunning()); } @@ -279,7 +279,7 @@ public final class ImageGalleryController { new NoGroupsDialog("No groups are fully analyzed yet, but ingest is still ongoing. Please Wait.", new ProgressIndicator())); } - + } else if (getFileUpdateQueueSizeProperty().get() > 0) { replaceNotification(fullUIStackPane, new NoGroupsDialog("No groups are fully analyzed yet, but image / video data is still being populated. Please Wait.", @@ -293,19 +293,19 @@ public final class ImageGalleryController { replaceNotification(fullUIStackPane, new NoGroupsDialog("There are no images/videos in the added datasources.")); } - + } else if (!groupManager.isRegrouping()) { replaceNotification(centralStackPane, new NoGroupsDialog("There are no fully analyzed groups to display:" + " the current Group By setting resulted in no groups, " + "or no groups are fully analyzed but ingest is not running.")); } - + } else { clearNotification(); } } - + private void clearNotification() { //remove the ingest spinner if (fullUIStackPane != null) { @@ -316,28 +316,28 @@ public final class ImageGalleryController { centralStackPane.getChildren().remove(infoOverlay); } } - + private void replaceNotification(StackPane stackPane, Node newNode) { clearNotification(); - + infoOverlay = new StackPane(infoOverLayBackground, newNode); if (stackPane != null) { stackPane.getChildren().add(infoOverlay); } } - + private void restartWorker() { if (dbWorkerThread != null) { // Keep using the same worker thread if one exists return; } dbWorkerThread = new DBWorkerThread(); - + getFileUpdateQueueSizeProperty().addListener((Observable o) -> { Platform.runLater(this::updateRegroupDisabled); }); - - Thread th = new Thread(dbWorkerThread); + + Thread th = new Thread(dbWorkerThread, "DB-Worker-Thread"); th.setDaemon(false); // we want it to go away when it is done th.start(); } @@ -351,7 +351,7 @@ public final class ImageGalleryController { if (Objects.nonNull(theNewCase)) { this.sleuthKitCase = theNewCase.getSleuthkitCase(); this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); - + setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); @@ -365,7 +365,7 @@ public final class ImageGalleryController { tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); tagsManager.registerListener(groupManager); SummaryTablePane.getDefault().refresh(); - + } else { reset(); } @@ -384,7 +384,7 @@ public final class ImageGalleryController { }); tagsManager.clearFollowUpTagName(); tagsManager.unregisterListener(groupManager); - + Toolbar.getDefault(this).reset(); groupManager.clear(); if (db != null) { @@ -406,21 +406,21 @@ public final class ImageGalleryController { } dbWorkerThread.addTask(innerTask); } - + public DrawableFile getFileFromId(Long fileID) throws TskCoreException { return db.getFileFromID(fileID); } - + public void setStacks(StackPane fullUIStack, StackPane centralStack) { fullUIStackPane = fullUIStack; this.centralStackPane = centralStack; Platform.runLater(this::checkForGroups); } - + public ReadOnlyIntegerProperty getFileUpdateQueueSizeProperty() { return queueSizeProperty.getReadOnlyProperty(); } - + public ReadOnlyDoubleProperty regroupProgress() { return groupManager.regroupProgress(); } @@ -496,15 +496,15 @@ public final class ImageGalleryController { } }); } - + public HashSetManager getHashSetManager() { return hashSetManager; } - + public CategoryManager getCategoryManager() { return categoryManager; } - + public DrawableTagsManager getTagsManager() { return tagsManager; } @@ -545,7 +545,7 @@ public final class ImageGalleryController { queueSizeProperty.set(workQueue.size()); }); } - + @Override public void run() { @@ -556,22 +556,22 @@ public final class ImageGalleryController { } try { InnerTask it = workQueue.take(); - + if (it.cancelled == false) { it.run(); } - + Platform.runLater(() -> { queueSizeProperty.set(workQueue.size()); }); - + } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); } } } } - + public synchronized SleuthkitCase getSleuthKitCase() { return sleuthKitCase; } @@ -580,55 +580,55 @@ public final class ImageGalleryController { * Abstract base class for task to be done on {@link DBWorkerThread} */ static public abstract class InnerTask implements Runnable { - + public double getProgress() { return progress.get(); } - + public final void updateProgress(Double workDone) { this.progress.set(workDone); } - + public String getMessage() { return message.get(); } - + public final void updateMessage(String Status) { this.message.set(Status); } SimpleObjectProperty state = new SimpleObjectProperty<>(Worker.State.READY); SimpleDoubleProperty progress = new SimpleDoubleProperty(this, "pregress"); SimpleStringProperty message = new SimpleStringProperty(this, "status"); - + public SimpleDoubleProperty progressProperty() { return progress; } - + public SimpleStringProperty messageProperty() { return message; } - + public Worker.State getState() { return state.get(); } - + protected void updateState(Worker.State newState) { state.set(newState); } - + public ReadOnlyObjectProperty stateProperty() { return new ReadOnlyObjectWrapper<>(state.get()); } - + protected InnerTask() { } - + protected volatile boolean cancelled = false; - + public void cancel() { updateState(Worker.State.CANCELLED); } - + protected boolean isCancelled() { return getState() == Worker.State.CANCELLED; } @@ -638,25 +638,25 @@ public final class ImageGalleryController { * Abstract base class for tasks associated with a file in the database */ static public abstract class FileTask extends InnerTask { - + private final AbstractFile file; - + public AbstractFile getFile() { return file; } - + public FileTask(AbstractFile f) { super(); this.file = f; } - + } /** * task that updates one file in database with results from ingest */ private class UpdateFileTask extends FileTask { - + public UpdateFileTask(AbstractFile f) { super(f); } @@ -683,7 +683,7 @@ public final class ImageGalleryController { * task that updates one file in database with results from ingest */ private class RemoveFileTask extends FileTask { - + public RemoveFileTask(AbstractFile f) { super(f); } @@ -702,7 +702,7 @@ public final class ImageGalleryController { Logger.getLogger(RemoveFileTask.class.getName()).log(Level.SEVERE, "Case was closed out from underneath RemoveFile task"); } } - + } } @@ -714,16 +714,16 @@ public final class ImageGalleryController { * adds them to the Drawable DB */ private class CopyAnalyzedFiles extends InnerTask { - + final private String DRAWABLE_QUERY = "name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "'"; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("populating analyzed image/video database"); - + @Override public void run() { progressHandle.start(); updateMessage("populating analyzed image/video database"); - + try { //grab all files with supported extension or detected mime types final List files = getSleuthKitCase().findAllFilesWhere(DRAWABLE_QUERY + " or tsk_files.obj_id in (select tsk_files.obj_id from tsk_files , blackboard_artifacts, blackboard_attributes" @@ -733,7 +733,7 @@ public final class ImageGalleryController { + " and blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID() + " and blackboard_attributes.value_text in ('" + StringUtils.join(ImageGalleryModule.getSupportedMimes(), "','") + "'))"); progressHandle.switchToDeterminate(files.size()); - + updateProgress(0.0); //do in transaction @@ -747,7 +747,7 @@ public final class ImageGalleryController { } final Boolean hasMimeType = ImageGalleryModule.hasSupportedMimeType(f); final boolean known = f.getKnown() == TskData.FileKnown.KNOWN; - + if (known) { db.removeFile(f.getId(), tr); //remove known files } else { @@ -767,38 +767,38 @@ public final class ImageGalleryController { } } } - + units++; final int prog = units; progressHandle.progress(f.getName(), units); updateProgress(prog - 1 / (double) files.size()); updateMessage(f.getName()); } - + progressHandle.finish(); - + progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); updateMessage("commiting image/video database"); updateProgress(1.0); - + progressHandle.start(); db.commitTransaction(tr, true); - + } catch (TskCoreException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.SEVERE, "Case was closed out from underneath CopyDataSource task", ex); } - + progressHandle.finish(); - + updateMessage( ""); updateProgress( -1.0); setStale(false); } - + } /** @@ -809,7 +809,7 @@ public final class ImageGalleryController { * netbeans and ImageGallery progress/status */ class PrePopulateDataSourceFiles extends InnerTask { - + private final Content dataSource; /** @@ -819,7 +819,7 @@ public final class ImageGalleryController { */ // (name like '.jpg' or name like '.png' ...) private final String DRAWABLE_QUERY = "(name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "') "; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("prepopulating image/video database"); /** @@ -845,7 +845,7 @@ public final class ImageGalleryController { final List files; try { List fsObjIds = new ArrayList<>(); - + String fsQuery; if (dataSource instanceof Image) { Image image = (Image) dataSource; @@ -859,7 +859,7 @@ public final class ImageGalleryController { else { fsQuery = "(fs_obj_id IS NULL) "; } - + files = getSleuthKitCase().findAllFilesWhere(fsQuery + " and " + DRAWABLE_QUERY); progressHandle.switchToDeterminate(files.size()); @@ -877,21 +877,21 @@ public final class ImageGalleryController { final int prog = units; progressHandle.progress(f.getName(), units); } - + progressHandle.finish(); progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); - + progressHandle.start(); db.commitTransaction(tr, false); - + } catch (TskCoreException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException | NullPointerException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "Case was closed out from underneath prepopulating database"); } - + progressHandle.finish(); } } - + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java index ab8ef06401..550581d8b2 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java @@ -51,6 +51,7 @@ public class NextUnseenGroup extends Action { this.controller = controller; setGraphic(new ImageView(ADVANCE)); + //TODO: do we need both these listeners? controller.getGroupManager().getAnalyzedGroups().addListener((Observable observable) -> { Platform.runLater(this::updateButton); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 49b0818e3b..9dfbbdc239 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -656,7 +656,7 @@ public final class DrawableDB { private void fireRemovedFiles(Collection fileIDs) { for (FileUpdateEvent.FileUpdateListener listener : updateListeners) { - listener.handleFileUpdate(FileUpdateEvent.newRemovedEvent(fileIDs)); + listener.handleFileRemoved(FileUpdateEvent.newRemovedEvent(fileIDs)); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index 386ae51d65..0ad8b2640e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -165,13 +165,11 @@ public class DrawableGroup implements Comparable { // By default, sort by group key name @Override - public int compareTo(DrawableGroup other - ) { + public int compareTo(DrawableGroup other) { return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName()); } - void setSeen(boolean isSeen - ) { + void setSeen(boolean isSeen) { this.seen.set(isSeen); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index a79b8e3b48..2027dae724 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-4 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,10 +25,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ExecutorService; @@ -41,12 +43,14 @@ import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javafx.collections.transformation.SortedList; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; import javax.swing.SortOrder; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; @@ -98,16 +102,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { */ @ThreadConfined(type = ThreadType.JFX) private final ObservableList analyzedGroups = FXCollections.observableArrayList(); + private final SortedList unmodifiableAnalyzedGroups = new SortedList<>(analyzedGroups); - private final ObservableList publicAnalyzedGroupsWrapper = FXCollections.unmodifiableObservableList(analyzedGroups); - /** - * list of unseen groups - */ + /** list of unseen groups */ @ThreadConfined(type = ThreadType.JFX) private final ObservableList unSeenGroups = FXCollections.observableArrayList(); - -// private final SortedList sortedUnSeenGroups = new SortedList<>(unSeenGroups); - private final ObservableList publicSortedUnseenGroupsWrapper = FXCollections.unmodifiableObservableList(unSeenGroups); + private final SortedList unmodifiableUnSeenGroups = new SortedList<>(unSeenGroups); private ReGroupTask groupByTask; @@ -117,7 +117,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { private volatile DrawableAttribute groupBy = DrawableAttribute.PATH; private volatile SortOrder sortOrder = SortOrder.ASCENDING; - private ReadOnlyDoubleWrapper regroupProgress = new ReadOnlyDoubleWrapper(); + private final ReadOnlyDoubleWrapper regroupProgress = new ReadOnlyDoubleWrapper(); public void setDB(DrawableDB db) { this.db = db; @@ -125,13 +125,15 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); } + @SuppressWarnings("ReturnOfCollectionOrArrayField") public ObservableList getAnalyzedGroups() { - return publicAnalyzedGroupsWrapper; + return unmodifiableAnalyzedGroups; } @ThreadConfined(type = ThreadType.JFX) + @SuppressWarnings("ReturnOfCollectionOrArrayField") public ObservableList getUnSeenGroups() { - return publicSortedUnseenGroupsWrapper; + return unmodifiableUnSeenGroups; } /** @@ -239,36 +241,6 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } - /** - * make and return a new group with the given key and files. If a group - * already existed for that key, it will be updated to contain the given - * files. - * - * NOTE: this is the only API for making a new group. - * - * @param groupKey the groupKey that uniquely identifies this group - * @param files a list of fileids that are members of this group - * - * @return the new DrawableGroup for the given key - */ - public DrawableGroup makeGroup(GroupKey groupKey, Set files) { - synchronized (groupMap) { - if (groupMap.containsKey(groupKey)) { - DrawableGroup group = groupMap.get(groupKey); - group.setFiles(ObjectUtils.defaultIfNull(files, Collections.emptySet())); - return group; - } else { - final boolean groupSeen = db.isGroupSeen(groupKey); - DrawableGroup group = new DrawableGroup(groupKey, files, groupSeen); - group.seenProperty().addListener((observable, oldSeen, newSeen) -> { - markGroupSeen(group, newSeen); - }); - groupMap.put(groupKey, group); - return group; - } - } - } - /** * 'mark' the given group as seen. This removes it from the queue of * groups @@ -277,15 +249,13 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @param group the {@link DrawableGroup} to mark as seen */ @ThreadConfined(type = ThreadType.JFX) - public void markGroupSeen(DrawableGroup group, boolean seen - ) { + public void markGroupSeen(DrawableGroup group, boolean seen) { db.markGroupSeen(group.getGroupKey(), seen); group.setSeen(seen); if (seen) { unSeenGroups.removeAll(group); } else if (unSeenGroups.contains(group) == false) { unSeenGroups.add(group); - FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); } } @@ -297,7 +267,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @param groupKey the value of groupKey * @param fileID the value of file */ - public synchronized void removeFromGroup(GroupKey groupKey, final Long fileID) { + public synchronized DrawableGroup removeFromGroup(GroupKey groupKey, final Long fileID) { //get grouping this file would be in final DrawableGroup group = getGroupForKey(groupKey); if (group != null) { @@ -311,74 +281,10 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { unSeenGroups.remove(group); }); } - } else { } } - } - public synchronized void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup) { - populateAnalyzedGroup(groupKey, filesInGroup, null); - } - - /** - * create a group with the given GroupKey and file ids and add it to the - * analyzed group list. - * - * @param groupKey - * @param filesInGroup - */ - private synchronized > void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup, ReGroupTask task) { - - /* if this is not part of a regroup task or it is but the task is not - * cancelled... - * - * this allows us to stop if a regroup task has been cancelled (e.g. the - * user picked a different group by attribute, while the current task - * was still running) */ - if (task == null || (task.isCancelled() == false)) { - DrawableGroup g = makeGroup(groupKey, filesInGroup); - populateAnalyzedGroup(g, task); - } - } - - private synchronized void populateAnalyzedGroup(final DrawableGroup g, ReGroupTask task) { - - if (task == null || (task.isCancelled() == false)) { - final boolean groupSeen = db.isGroupSeen(g.getGroupKey()); - - Platform.runLater(() -> { - if (analyzedGroups.contains(g) == false) { - analyzedGroups.add(g); - } - markGroupSeen(g, groupSeen); - - }); - } - } - - /** - * check if the group for the given groupkey is analyzed - * - * @param groupKey - * - * @return null if this group is not analyzed or a list of file ids in - * this - * group if they are all analyzed - */ - public Set checkAnalyzed(final GroupKey groupKey) { - try { - /* for attributes other than path we can't be sure a group is fully - * analyzed because we don't know all the files that will be a part - * of that group */ - if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { - return getFileIDsInGroup(groupKey); - } else { - return null; - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); - return null; - } + return group; } /** @@ -595,9 +501,6 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { if (groupByTask != null) { groupByTask.cancel(true); } - Platform.runLater(() -> { - FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); - }); groupByTask = new ReGroupTask(groupBy, sortBy, sortOrder); Platform.runLater(() -> { @@ -605,15 +508,14 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { }); regroupExecutor.submit(groupByTask); } else { - // just resort the list of groups + // resort the list of groups setSortBy(sortBy); setSortOrder(sortOrder); Platform.runLater(() -> { - FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); - FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder)); + unmodifiableAnalyzedGroups.setComparator(sortBy.getGrpComparator(sortOrder)); + unmodifiableUnSeenGroups.setComparator(sortBy.getGrpComparator(sortOrder)); }); } - } /** @@ -634,86 +536,114 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } + @Override + synchronized public void handleFileRemoved(FileUpdateEvent evt) { + Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.REMOVE); + + for (final long fileId : evt.getFileIDs()) { + //get grouping(s) this file would be in + Set> groupsForFile = getGroupKeysForFileID(fileId); + + for (GroupKey gk : groupsForFile) { + DrawableGroup g = removeFromGroup(gk, fileId); + + if (g == null) { + // It may be that this was the last unanalyzed file in the group, so test + // whether the group is now fully analyzed. + popuplateIfAnalyzed(gk, null); + } + } + } + } + /** * handle {@link FileUpdateEvent} sent from Db when files are * inserted/updated * - * TODO: why isn't this just two methods! - * * @param evt */ @Override synchronized public void handleFileUpdate(FileUpdateEvent evt) { - final Collection fileIDs = evt.getFileIDs(); - switch (evt.getUpdateType()) { - case REMOVE: - for (final long fileId : fileIDs) { - //get grouping(s) this file would be in - Set> groupsForFile = getGroupKeysForFileID(fileId); + Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.UPDATE); + Collection fileIDs = evt.getFileIDs(); + /** + * TODO: is there a way to optimize this to avoid quering to db + * so much. the problem is that as a new files are analyzed they + * might be in new groups( if we are grouping by say make or + * model) -jm + */ + for (long fileId : fileIDs) { - for (GroupKey gk : groupsForFile) { - removeFromGroup(gk, fileId); + controller.getHashSetManager().invalidateHashSetsForFile(fileId); - DrawableGroup g = getGroupForKey(gk); + //get grouping(s) this file would be in + Set> groupsForFile = getGroupKeysForFileID(fileId); - if (g == null) { - // It may be that this was the last unanalyzed file in the group, so test - // whether the group is now fully analyzed. - //TODO: use method in groupmanager ? - Set checkAnalyzed = checkAnalyzed(gk); - if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui - populateAnalyzedGroup(gk, checkAnalyzed); + for (GroupKey gk : groupsForFile) { + DrawableGroup g = getGroupForKey(gk); + + if (g == null) { + //if there wasn't already a group check if there should be one now + popuplateIfAnalyzed(gk, null); + } else { + //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. + g.addFile(fileId); + } + } + } + + //we fire this event for all files so that the category counts get updated during initial db population + controller.getCategoryManager().fireChange(fileIDs); + + if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { + controller.getTagsManager().fireChange(fileIDs); + } + } + + private void popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { + + if (Objects.nonNull(task) && (task.isCancelled())) { + /* if this method call is part of a ReGroupTask and that task is + * cancelled, no-op + * + * this allows us to stop if a regroup task has been cancelled (e.g. + * the user picked a different group by attribute, while the + * current task was still running) */ + } else { // no task or un-cancelled task + if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { + /* for attributes other than path we can't be sure a group is + * fully analyzed because we don't know all the files that + * will be a part of that group */ + + try { + Set fileIDs = getFileIDsInGroup(groupKey); + if (Objects.nonNull(fileIDs)) { + DrawableGroup group; + final boolean groupSeen = db.isGroupSeen(groupKey); + synchronized (groupMap) { + if (groupMap.containsKey(groupKey)) { + group = groupMap.get(groupKey); + group.setFiles(ObjectUtils.defaultIfNull(fileIDs, Collections.emptySet())); + } else { + + group = new DrawableGroup(groupKey, fileIDs, groupSeen); + group.seenProperty().addListener((observable, oldSeen, newSeen) -> { + markGroupSeen(group, newSeen); + }); + groupMap.put(groupKey, group); } } - } - } - - break; - case UPDATE: - - /** - * TODO: is there a way to optimize this to avoid quering to db - * so much. the problem is that as a new files are analyzed they - * might be in new groups( if we are grouping by say make or - * model) - * - * TODO: Should this be a InnerTask so it can be done by the - * WorkerThread? Is it already done by worker thread because - * handlefileUpdate is invoked through call on db in UpdateTask - * innertask? -jm - */ - for (final long fileId : fileIDs) { - - controller.getHashSetManager().invalidateHashSetsForFile(fileId); - - //get grouping(s) this file would be in - Set> groupsForFile = getGroupKeysForFileID(fileId); - - for (GroupKey gk : groupsForFile) { - DrawableGroup g = getGroupForKey(gk); - - if (g != null) { - //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. - g.addFile(fileId); - } else { - //if there wasn't already a group check if there should be one now - //TODO: use method in groupmanager ? - Set checkAnalyzed = checkAnalyzed(gk); - if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui - populateAnalyzedGroup(gk, checkAnalyzed); + Platform.runLater(() -> { + if (analyzedGroups.contains(group) == false) { + analyzedGroups.add(group); } - } + markGroupSeen(group, groupSeen); + }); } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); } - - //we fire this event for all files so that the category counts get updated during initial db population - controller.getCategoryManager().fireChange(fileIDs); - - if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { - controller.getTagsManager().fireChange(fileIDs); - } - break; - + } } } @@ -755,17 +685,16 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { groupProgress = ProgressHandleFactory.createHandle("regrouping files by " + groupBy.attrName.toString() + " sorted by " + sortBy.name() + " in " + sortOrder.toString() + " order", this); Platform.runLater(() -> { analyzedGroups.clear(); - synchronized (unSeenGroups) { - unSeenGroups.clear(); - } + unSeenGroups.clear(); + + final Comparator grpComparator = sortBy.getGrpComparator(sortOrder); + unmodifiableAnalyzedGroups.setComparator(grpComparator); + unmodifiableUnSeenGroups.setComparator(grpComparator); }); // Get the list of group keys final List vals = findValuesForAttribute(groupBy); - // Make a list of each group - final List groups = new ArrayList<>(); - groupProgress.start(vals.size()); int p = 0; @@ -778,25 +707,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { updateMessage("regrouping files by " + groupBy.attrName.toString() + " : " + val); updateProgress(p, vals.size()); groupProgress.progress("regrouping files by " + groupBy.attrName.toString() + " : " + val, p); - //check if this group is analyzed - final GroupKey groupKey = new GroupKey<>(groupBy, val); - - Set checkAnalyzed = checkAnalyzed(groupKey); - if (checkAnalyzed != null) { // != null => the group is analyzed, so add it to the ui - - // makeGroup will create the group and add it to the map groupMap, but does not - // update anything else - DrawableGroup g = makeGroup(groupKey, checkAnalyzed); - groups.add(g); - } - } - - // Sort the group list - Collections.sort(groups, sortBy.getGrpComparator(sortOrder)); - - // Officially add all groups in order - for (DrawableGroup g : groups) { - populateAnalyzedGroup(g, ReGroupTask.this); + popuplateIfAnalyzed(new GroupKey(groupBy, val), this); } updateProgress(1, 1); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java index 482ff66f7c..efc855e8ca 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java @@ -171,13 +171,14 @@ public class NavPanel extends TabPane { if (change.wasPermutated()) { // Handle this afterward wasPermuted = true; + break; } } if (wasPermuted) { rebuildTrees(); } - if (selectedItem != null) { + if (selectedItem != null && selectedItem.getValue().getGroup() != null) { Platform.runLater(() -> { setFocusedGroup(selectedItem.getValue().getGroup()); }); @@ -268,7 +269,6 @@ public class NavPanel extends TabPane { } private static List groupingToPath(DrawableGroup g) { - if (g.groupKey.getAttribute() == DrawableAttribute.PATH) { String path = g.groupKey.getValueDisplayName(); From 37eee8444e937ebad199303c22562708c79fa73c Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 13:18:03 -0400 Subject: [PATCH 054/198] fix javadoc and sources reference --- CoreLibs/nbproject/project.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CoreLibs/nbproject/project.properties b/CoreLibs/nbproject/project.properties index 53bd6cf9e0..8f133ac7fa 100644 --- a/CoreLibs/nbproject/project.properties +++ b/CoreLibs/nbproject/project.properties @@ -59,6 +59,6 @@ file.reference.xml-apis-1.0.b2.jar=release/modules/ext/xml-apis-1.0.b2.jar file.reference.xmlbeans-2.3.0.jar=release/modules/ext/xmlbeans-2.3.0.jar javac.source=1.7 javac.compilerargs=-Xlint -Xlint:-serial -javadoc.reference.controlsfx-8.20.9.jar=release/modules/ext/controlsfx-8.40.9-javadoc.jar +javadoc.reference.controlsfx-8.40.9.jar=release/modules/ext/controlsfx-8.40.9-javadoc.jar nbm.needs.restart=true -source.reference.controlsfx-8.20.9.jar=release/modules/ext/controlsfx-8.40.9-sources.jar +source.reference.controlsfx-8.40.9.jar=release/modules/ext/controlsfx-8.40.9-sources.jar From b572ac4742d647a5a317869e91f5d787919a0b00 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 13:51:37 -0400 Subject: [PATCH 055/198] rename method; add synchronization; remove singletonness from SummaryTablePane --- .../imagegallery/DrawableTagsManager.java | 4 ++-- .../imagegallery/ImageGalleryController.java | 4 +--- .../ImageGalleryTopComponent.java | 2 +- .../actions/AddDrawableTagAction.java | 2 +- .../imagegallery/actions/AddTagAction.java | 6 +++--- .../actions/CategorizeAction.java | 2 +- .../actions/DeleteFollowUpTagAction.java | 2 +- .../datamodel/CategoryManager.java | 21 +++++++++++++------ .../imagegallery/gui/SummaryTablePane.java | 18 ++++++---------- 9 files changed, 31 insertions(+), 30 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 149c7fd888..7e0303fe4d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -78,7 +78,7 @@ public class DrawableTagsManager { } /** - * fire a CategoryChangeEvent with the given fileIDs + * fire a TagsChangeEvent with the given fileIDs * * @param fileIDs */ @@ -188,7 +188,7 @@ public class DrawableTagsManager { * had a chance to add that so, we fire these events and the tree * refreshes based on them. */ - static public void fireTagsChangedEvent() { + static public void refreshTagsInAutopsy() { IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index e649afbc39..6c54db8185 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -65,7 +65,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; -import org.sleuthkit.autopsy.imagegallery.gui.SummaryTablePane; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -364,8 +363,6 @@ public final class ImageGalleryController { categoryManager.setDb(db); tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); tagsManager.registerListener(groupManager); - SummaryTablePane.getDefault().refresh(); - } else { reset(); } @@ -442,6 +439,7 @@ public final class ImageGalleryController { ModuleDataEvent oldValue = (ModuleDataEvent) evt.getOldValue(); if ("TagAction".equals(oldValue.getModuleName()) && oldValue.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { getTagsManager().fireChange(Collections.singleton(-1L)); + getCategoryManager().invalidateCaches(); } /* we could listen to DATA events and progressivly * update files, and get data from DataSource ingest diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java index e5c2bb3bd6..850230cb88 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java @@ -150,7 +150,7 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl metaDataTable = new MetaDataPane(controller); navPanel = new NavPanel(controller); - leftPane = new VBox(navPanel, SummaryTablePane.getDefault()); + leftPane = new VBox(navPanel, new SummaryTablePane(controller)); SplitPane.setResizableWithParent(leftPane, Boolean.FALSE); SplitPane.setResizableWithParent(groupPane, Boolean.TRUE); SplitPane.setResizableWithParent(metaDataTable, Boolean.FALSE); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index 9d5c5f277b..e88c51f12b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -90,7 +90,7 @@ public class AddDrawableTagAction extends AddTagAction { //make sure rest of ui hears category change. controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index b933d592d4..4e8f9b827f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -101,7 +101,7 @@ abstract class AddTagAction { MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); tagNameItem.setOnAction((ActionEvent t) -> { addTag(tagName, NO_COMMENT); - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); }); quickTagMenu.getItems().add(tagNameItem); } @@ -123,7 +123,7 @@ abstract class AddTagAction { TagName tagName = GetTagNameDialog.doDialog(); if (tagName != null) { addTag(tagName, NO_COMMENT); - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); } }); } catch (InterruptedException | InvocationTargetException ex) { @@ -146,7 +146,7 @@ abstract class AddTagAction { } else { new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); } }); } catch (InterruptedException | InvocationTargetException ex) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 1b84b005bf..27f599cafe 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -158,7 +158,7 @@ public class CategorizeAction extends AddTagAction { JOptionPane.showMessageDialog(null, "Unable to categorize " + fileID + ".", "Categorizing Error", JOptionPane.ERROR_MESSAGE); } - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 6a1a54c30d..bba6d5e4dc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -79,7 +79,7 @@ public class DeleteFollowUpTagAction extends Action { } } - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); //make sure rest of ui hears category change. groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 0197c3c847..f8b0e6beb1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -23,6 +23,7 @@ import com.google.common.cache.LoadingCache; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import java.util.Collection; +import java.util.Collections; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; @@ -44,6 +45,7 @@ import org.sleuthkit.datamodel.TagName; public class CategoryManager { private static final java.util.logging.Logger LOGGER = Logger.getLogger(CategoryManager.class.getName()); + private final ImageGalleryController controller; /** @@ -88,10 +90,17 @@ public class CategoryManager { * * @param db */ - public void setDb(DrawableDB db) { + synchronized public void setDb(DrawableDB db) { this.db = db; categoryCounts.invalidateAll(); catTagNameMap.invalidateAll(); + fireChange(Collections.singleton(-1L)); + } + + synchronized public void invalidateCaches() { + categoryCounts.invalidateAll(); + catTagNameMap.invalidateAll(); + fireChange(Collections.singleton(-1L)); } /** @@ -101,7 +110,7 @@ public class CategoryManager { * * @return the long the number of files with the given Category */ - public long getCategoryCount(Category cat) { + synchronized public long getCategoryCount(Category cat) { if (cat == Category.ZERO) { // Keeping track of the uncategorized files is a bit tricky while ingest // is going on, so always use the list of file IDs we already have along with the @@ -119,7 +128,7 @@ public class CategoryManager { * * @param cat the Category to increment */ - public void incrementCategoryCount(Category cat) { + synchronized public void incrementCategoryCount(Category cat) { if (cat != Category.ZERO) { categoryCounts.getUnchecked(cat).increment(); } @@ -131,7 +140,7 @@ public class CategoryManager { * * @param cat the Category to decrement */ - public void decrementCategoryCount(Category cat) { + synchronized public void decrementCategoryCount(Category cat) { if (cat != Category.ZERO) { categoryCounts.getUnchecked(cat).decrement(); } @@ -147,7 +156,7 @@ public class CategoryManager { * @return a LongAdder whose value is set to the number of file with the * given Category */ - private LongAdder getCategoryCountHelper(Category cat) { + synchronized private LongAdder getCategoryCountHelper(Category cat) { LongAdder longAdder = new LongAdder(); longAdder.decrement(); try { @@ -191,7 +200,7 @@ public class CategoryManager { * * @return the TagName used for this Category */ - public TagName getTagName(Category cat) { + synchronized public TagName getTagName(Category cat) { return catTagNameMap.getUnchecked(cat); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java index 6692bf873f..2710020c45 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java @@ -43,8 +43,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; */ public class SummaryTablePane extends AnchorPane { - private static SummaryTablePane instance; - @FXML private TableColumn, String> catColumn; @@ -53,6 +51,7 @@ public class SummaryTablePane extends AnchorPane { @FXML private TableView> tableView; + private final ImageGalleryController controller; @FXML void initialize() { @@ -74,19 +73,14 @@ public class SummaryTablePane extends AnchorPane { tableView.getColumns().setAll(Arrays.asList(catColumn, countColumn)); -// //register for category events - ImageGalleryController.getDefault().getCategoryManager().registerListener(this); + //register for category events + controller.getCategoryManager().registerListener(this); } - private SummaryTablePane() { + public SummaryTablePane(ImageGalleryController controller) { + this.controller = controller; FXMLConstructor.construct(this, "SummaryTablePane.fxml"); - } - public static synchronized SummaryTablePane getDefault() { - if (instance == null) { - instance = new SummaryTablePane(); - } - return instance; } /** @@ -101,7 +95,7 @@ public class SummaryTablePane extends AnchorPane { final ObservableList> data = FXCollections.observableArrayList(); if (Case.isCaseOpen()) { for (Category cat : Category.values()) { - data.add(new Pair<>(cat, ImageGalleryController.getDefault().getCategoryManager().getCategoryCount(cat))); + data.add(new Pair<>(cat, controller.getCategoryManager().getCategoryCount(cat))); } } Platform.runLater(() -> { From a6790d79e3b32d65a5a5ee7b86f7a0981812ea4c Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 18 Jun 2015 14:01:46 -0400 Subject: [PATCH 056/198] Updated NEWS for 3.1.3 release --- NEWS.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/NEWS.txt b/NEWS.txt index a7e5b55d9e..89ac163923 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,3 +1,13 @@ +---------------- VERSION 3.1.3 -------------- +Improvements: +- New Embedded File Extractor module that incorporates ZIP file module and extracts images from Office documents +- Views area counts updates when ZIP files and such are found +- Updates to python scripting for new version of Python, scripts are reloaded each time ingest is run, and errors are better shown. +- Updated right click actions to be consistent accross all file types +- Changed logic of Interesting Files module to look for substrings of parent path. +- Lots of minor fixes and enhancements + + ---------------- VERSION 3.1.2 -------------- Improvements: - New PhotoRec carving ingest module From 48d455bf29e5806ac413c45309590a7ce9cfe97f Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 15:20:02 -0400 Subject: [PATCH 057/198] more tag/category autopsy integeration update CategoryCounts, FollowUp and Category border on general Tag Event use most severe category if multiple categories are present for a file enforce category ordering via enum declaration order --- .../imagegallery/datamodel/Category.java | 9 +++++--- .../imagegallery/datamodel/DrawableFile.java | 7 +++--- .../imagegallery/gui/DrawableView.java | 22 +++++++++++-------- .../imagegallery/gui/DrawableViewBase.java | 6 ++--- .../imagegallery/gui/MetaDataPane.java | 4 ++-- .../imagegallery/gui/SummaryTablePane.java | 5 +---- 6 files changed, 28 insertions(+), 25 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index ee6a46098e..aed95afec6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -28,14 +28,17 @@ import org.sleuthkit.datamodel.TagName; /** * Enum to represent the six categories in the DHs image categorization scheme. */ -public enum Category implements Comparable { +public enum Category { - ZERO(Color.LIGHTGREY, 0, "CAT-0: Uncategorized"), + /* This order of declaration is required so that Enum's compareTo method + * preserves the fact that lower category numbers are first/most sever, + * except 0 which is last */ ONE(Color.RED, 1, "CAT-1: Child Exploitation (Illegal)"), TWO(Color.ORANGE, 2, "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"), THREE(Color.YELLOW, 3, "CAT-3: CGI/Animation (Child Exploitive)"), FOUR(Color.BISQUE, 4, "CAT-4: Exemplar/Comparison (Internal Use Only)"), - FIVE(Color.GREEN, 5, "CAT-5: Non-pertinent"); + FIVE(Color.GREEN, 5, "CAT-5: Non-pertinent"), + ZERO(Color.LIGHTGREY, 0, "CAT-0: Uncategorized"); /** map from displayName to enum value */ private static final Map nameMap diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 4d3de0d553..3890ca577a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -268,22 +268,21 @@ public abstract class DrawableFile extends AbstractFile return category; } - public void updateCategory() { + /** set the category property to the most severe one found */ + private void updateCategory() { try { category.set(getSleuthkitCase().getContentTagsByContent(this).stream() .map(Tag::getName).filter(Category::isCategoryTagName) - .findFirst() .map(TagName::getDisplayName) .map(Category::fromDisplayName) + .sorted().findFirst() //sort by severity and take the first .orElse(Category.ZERO) ); - } catch (TskCoreException ex) { Logger.getLogger(DrawableFile.class.getName()).log(Level.WARNING, "problem looking up category for file " + this.getName(), ex); } catch (IllegalStateException ex) { // We get here many times if the case is closed during ingest, so don't print out a ton of warnings. } - } public abstract Image getThumbnail(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 93dbae801e..99d8671a63 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -108,15 +108,19 @@ public interface DrawableView { @ThreadConfined(type = ThreadConfined.ThreadType.ANY) default Category updateCategoryBorder() { - final Category category = getFile().getCategory(); - final Border border = hasHashHit() && (category == Category.ZERO) - ? HASH_BORDER - : getCategoryBorder(category); + if (getFile() != null) { + final Category category = getFile().getCategory(); + final Border border = hasHashHit() && (category == Category.ZERO) + ? HASH_BORDER + : getCategoryBorder(category); - Platform.runLater(() -> { - getCategoryBorderRegion().setBorder(border); - getCategoryBorderRegion().requestLayout(); - }); - return category; + Platform.runLater(() -> { + getCategoryBorderRegion().setBorder(border); + getCategoryBorderRegion().requestLayout(); + }); + return category; + } else { + return Category.ZERO; + } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 52ac70def0..38c48c2951 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -2,7 +2,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-14 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -302,7 +302,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Override synchronized public void handleTagsChanged(TagsChangeEvent evnt) { - if (fileID != null && evnt.getFileIDs().contains(fileID)) { + if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { updateFollowUpIcon(); } } @@ -386,7 +386,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { - if (evt.getFileIDs().contains(getFileID())) { + if (evt.getFileIDs().contains(getFileID()) || evt.getFileIDs().contains(-1L)) { updateCategoryBorder(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index 4ab6fff208..4f4cace550 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -225,7 +225,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @Subscribe @Override public void handleCategoryChanged(CategoryChangeEvent evt) { - if (getFile() != null && evt.getFileIDs().contains(getFileID())) { + if (getFile() != null && (evt.getFileIDs().contains(-1L) || evt.getFileIDs().contains(getFileID()))) { updateUI(); } } @@ -233,7 +233,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @Override @Subscribe public void handleTagsChanged(TagsChangeEvent evt) { - if (getFile() != null && evt.getFileIDs().contains(getFileID())) { + if (getFile() != null && (evt.getFileIDs().contains(-1L) || evt.getFileIDs().contains(getFileID()))) { updateUI(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java index 2710020c45..955cf0760f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java @@ -75,6 +75,7 @@ public class SummaryTablePane extends AnchorPane { //register for category events controller.getCategoryManager().registerListener(this); + handleCategoryChanged(null); } public SummaryTablePane(ImageGalleryController controller) { @@ -88,10 +89,6 @@ public class SummaryTablePane extends AnchorPane { */ @Subscribe public void handleCategoryChanged(CategoryChangeEvent evt) { - refresh(); - } - - public void refresh() { final ObservableList> data = FXCollections.observableArrayList(); if (Case.isCaseOpen()) { for (Category cat : Category.values()) { From 91725425f48534c1b086e6171c5e039a9dafc51f Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 18 Jun 2015 15:41:47 -0400 Subject: [PATCH 058/198] Updated versions to 3.1.3 --- BUILDING.txt | 2 +- Core/manifest.mf | 2 +- Core/nbproject/project.properties | 2 +- KeywordSearch/manifest.mf | 2 +- RecentActivity/manifest.mf | 2 +- nbproject/project.properties | 6 +++--- thunderbirdparser/manifest.mf | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/BUILDING.txt b/BUILDING.txt index 0e0172c4d8..7361735adf 100644 --- a/BUILDING.txt +++ b/BUILDING.txt @@ -11,7 +11,7 @@ correct C libraries. STEPS: 1) Get Java Setup -1a) Download and install JDK version 1.8. You can now use 32-bit or 64-bit, but special work is needed to get The Sleuth Kit to compile as 64-bit. So, 32-bit is easier. +1a) Download and install JDK version 1.8. For the current version of JavaFX that we use, you'll need 1.8.0_40 or greater. You can now use 32-bit or 64-bit, but special work is needed to get The Sleuth Kit to compile as 64-bit. So, 32-bit is easier. Autopsy has been used and tested with Oracle JavaSE and the included JavaFX support (http://www.oracle.com/technetwork/java/javase/downloads/index.html). diff --git a/Core/manifest.mf b/Core/manifest.mf index 63742e1281..1b19165b34 100644 --- a/Core/manifest.mf +++ b/Core/manifest.mf @@ -2,7 +2,7 @@ Manifest-Version: 1.0 OpenIDE-Module: org.sleuthkit.autopsy.core/10 OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml -OpenIDE-Module-Implementation-Version: 13 +OpenIDE-Module-Implementation-Version: 14 OpenIDE-Module-Requires: org.openide.windows.WindowManager AutoUpdate-Show-In-Client: true AutoUpdate-Essential-Module: true diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index 2d5925dbdf..3ec5353c90 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -17,5 +17,5 @@ license.file=../LICENSE-2.0.txt nbm.homepage=http://www.sleuthkit.org/ nbm.module.author=Brian Carrier nbm.needs.restart=true -spec.version.base=10.2 +spec.version.base=10.3 diff --git a/KeywordSearch/manifest.mf b/KeywordSearch/manifest.mf index 9921e1c77e..210215bc71 100644 --- a/KeywordSearch/manifest.mf +++ b/KeywordSearch/manifest.mf @@ -1,7 +1,7 @@ Manifest-Version: 1.0 AutoUpdate-Show-In-Client: true OpenIDE-Module: org.sleuthkit.autopsy.keywordsearch/6 -OpenIDE-Module-Implementation-Version: 13 +OpenIDE-Module-Implementation-Version: 14 OpenIDE-Module-Install: org/sleuthkit/autopsy/keywordsearch/Installer.class OpenIDE-Module-Layer: org/sleuthkit/autopsy/keywordsearch/layer.xml OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/keywordsearch/Bundle.properties diff --git a/RecentActivity/manifest.mf b/RecentActivity/manifest.mf index 3c4c75fbbc..79cec7e7ca 100644 --- a/RecentActivity/manifest.mf +++ b/RecentActivity/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.sleuthkit.autopsy.recentactivity/6 -OpenIDE-Module-Implementation-Version: 12 +OpenIDE-Module-Implementation-Version: 13 OpenIDE-Module-Layer: org/sleuthkit/autopsy/recentactivity/layer.xml OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/recentactivity/Bundle.properties OpenIDE-Module-Requires: diff --git a/nbproject/project.properties b/nbproject/project.properties index de529c07a2..502bbab27d 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -4,11 +4,11 @@ app.title=Autopsy ### lowercase version of above app.name=${branding.token} ### if left unset, version will default to today's date -app.version=3.1.2 +app.version=3.1.3 ### Build type isn't used at this point, but it may be useful ### Must be one of: DEVELOPMENT, RELEASE -#build.type=RELEASE -build.type=DEVELOPMENT +build.type=RELEASE +#build.type=DEVELOPMENT update_versions=false #custom JVM options diff --git a/thunderbirdparser/manifest.mf b/thunderbirdparser/manifest.mf index 13c840d7e5..784f895c93 100644 --- a/thunderbirdparser/manifest.mf +++ b/thunderbirdparser/manifest.mf @@ -1,7 +1,7 @@ Manifest-Version: 1.0 AutoUpdate-Show-In-Client: true OpenIDE-Module: org.sleuthkit.autopsy.thunderbirdparser/4 -OpenIDE-Module-Implementation-Version: 13 +OpenIDE-Module-Implementation-Version: 14 OpenIDE-Module-Layer: org/sleuthkit/autopsy/thunderbirdparser/layer.xml OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/thunderbirdparser/Bundle.properties From 5e0d8a6f5ef3900a9307a542be8b8b3f2fac5914 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 18 Jun 2015 16:01:30 -0400 Subject: [PATCH 059/198] Fixed compiler warnings --- .../org/sleuthkit/autopsy/datamodel/DataSourcesNode.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index 2a1e62d9e1..b0c84fe805 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -62,10 +62,11 @@ public class DataSourcesNode extends DisplayableItemNode { private static final Logger logger = Logger.getLogger(DataSourcesNodeChildren.class.getName()); - List currentKeys = new ArrayList(); + List currentKeys; public DataSourcesNodeChildren() { super(); + this.currentKeys = new ArrayList<>(); } private final PropertyChangeListener pcl = new PropertyChangeListener() { @@ -87,7 +88,7 @@ public class DataSourcesNode extends DisplayableItemNode { @Override protected void removeNotify() { Case.removePropertyChangeListener(pcl); - setKeys(Collections.EMPTY_SET); + setKeys(Collections.emptySet()); } private void reloadKeys() { @@ -96,7 +97,7 @@ public class DataSourcesNode extends DisplayableItemNode { setKeys(currentKeys); } catch (TskCoreException | IllegalStateException ex) { logger.severe("Error getting data sources: " + ex.getMessage()); // NON-NLS - setKeys(Collections.EMPTY_SET); + setKeys(Collections.emptySet()); } } From 1fc618f0dfaee2dd5006046379203e6fc05aa9d7 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 16:57:28 -0400 Subject: [PATCH 060/198] new Tag event system --- .../imagegallery/DrawableTagsManager.java | 148 +++++++++++------- .../imagegallery/ImageGalleryController.java | 30 +++- .../actions/CategorizeAction.java | 1 + .../actions/DeleteFollowUpTagAction.java | 70 ++++----- .../imagegallery/datamodel/Category.java | 3 + .../imagegallery/grouping/GroupManager.java | 6 +- .../imagegallery/gui/DrawableViewBase.java | 15 +- 7 files changed, 163 insertions(+), 110 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 7e0303fe4d..add7065742 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -45,6 +45,7 @@ public class DrawableTagsManager { private static final String FOLLOW_UP = "Follow Up"; + private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; /** Used to distribute {@link TagsChangeEvent}s */ @@ -64,26 +65,21 @@ public class DrawableTagsManager { * * @param autopsyTagsManager */ - public synchronized void setAutopsyTagsManager(TagsManager autopsyTagsManager) { - this.autopsyTagsManager = autopsyTagsManager; - clearFollowUpTagName(); + public void setAutopsyTagsManager(TagsManager autopsyTagsManager) { + synchronized (autopsyTagsManager) { + this.autopsyTagsManager = autopsyTagsManager; + clearFollowUpTagName(); + } } /** * Use when closing a case to make sure everything is re-initialized in the * next case. */ - public synchronized void clearFollowUpTagName() { - followUpTagName = null; - } - - /** - * fire a TagsChangeEvent with the given fileIDs - * - * @param fileIDs - */ - public final void fireChange(Collection fileIDs) { - tagsEventBus.post(new TagsChangeEvent(fileIDs)); + public void clearFollowUpTagName() { + synchronized (autopsyTagsManager) { + followUpTagName = null; + } } /** @@ -111,22 +107,26 @@ public class DrawableTagsManager { * * @throws TskCoreException */ - synchronized public TagName getFollowUpTagName() throws TskCoreException { - if (Objects.isNull(followUpTagName)) { - followUpTagName = getTagName(FOLLOW_UP); + public TagName getFollowUpTagName() throws TskCoreException { + synchronized (autopsyTagsManager) { + if (Objects.isNull(followUpTagName)) { + followUpTagName = getTagName(FOLLOW_UP); + } + return followUpTagName; } - return followUpTagName; } - synchronized public Collection getNonCategoryTagNames() { - try { - return autopsyTagsManager.getAllTagNames().stream() - .filter(Category::isCategoryTagName) - .collect(Collectors.toSet()); - } catch (TskCoreException | IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + public Collection getNonCategoryTagNames() { + synchronized (autopsyTagsManager) { + try { + return autopsyTagsManager.getAllTagNames().stream() + .filter(Category::isCategoryTagName) + .collect(Collectors.toSet()); + } catch (TskCoreException | IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + } + return Collections.emptySet(); } - return Collections.emptySet(); } /** @@ -139,29 +139,33 @@ public class DrawableTagsManager { * * @throws TskCoreException */ - public synchronized List getContentTagsByContent(Content content) throws TskCoreException { - return autopsyTagsManager.getContentTagsByContent(content); - } - - public synchronized TagName getTagName(String displayName) throws TskCoreException { - try { - for (TagName tn : autopsyTagsManager.getAllTagNames()) { - if (displayName.equals(tn.getDisplayName())) { - return tn; - } - } - try { - return autopsyTagsManager.addTagName(displayName); - } catch (TagsManager.TagNameAlreadyExistsException ex) { - throw new TskCoreException("tagame exists but wasn't found", ex); - } - } catch (IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); - throw new TskCoreException("Case was closed out from underneath", ex); + public List getContentTagsByContent(Content content) throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getContentTagsByContent(content); } } - public synchronized TagName getTagName(Category cat) { + public TagName getTagName(String displayName) throws TskCoreException { + synchronized (autopsyTagsManager) { + try { + for (TagName tn : autopsyTagsManager.getAllTagNames()) { + if (displayName.equals(tn.getDisplayName())) { + return tn; + } + } + try { + return autopsyTagsManager.addTagName(displayName); + } catch (TagsManager.TagNameAlreadyExistsException ex) { + throw new TskCoreException("tagame exists but wasn't found", ex); + } + } catch (IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); + throw new TskCoreException("Case was closed out from underneath", ex); + } + } + } + + public TagName getTagName(Category cat) { try { return getTagName(cat.getDisplayName()); } catch (TskCoreException ex) { @@ -169,12 +173,18 @@ public class DrawableTagsManager { } } - synchronized public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { - autopsyTagsManager.addContentTag(file, tagName, comment); + public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { + ContentTag addContentTag; + synchronized (autopsyTagsManager) { + addContentTag = autopsyTagsManager.addContentTag(file, tagName, comment); + } + fireTagAdded(addContentTag); } - synchronized public List getContentTagsByTagName(TagName t) throws TskCoreException { - return autopsyTagsManager.getContentTagsByTagName(t); + public List getContentTagsByTagName(TagName t) throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getContentTagsByTagName(t); + } } /** @@ -189,15 +199,43 @@ public class DrawableTagsManager { * refreshes based on them. */ static public void refreshTagsInAutopsy() { - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS } - public synchronized List getAllTagNames() throws TskCoreException { - return autopsyTagsManager.getAllTagNames(); + public List getAllTagNames() throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getAllTagNames(); + } } - public synchronized List getTagNamesInUse() throws TskCoreException { - return autopsyTagsManager.getTagNamesInUse(); + public List getTagNamesInUse() throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getTagNamesInUse(); + } } + + public void fireTagAdded(ContentTag newTag) { + tagsEventBus.post(new TagsChangeEvent(Collections.singleton(newTag.getContent().getId()))); + } + + public void fireTagDeleted(ContentTag oldTag) { + tagsEventBus.post(new TagsChangeEvent(Collections.singleton(oldTag.getContent().getId()))); + } +// +// /** +// * fire a TagsChangeEvent with the given fileIDs +// * +// * @param fileIDs +// */ +// public final void fireChange(Collection fileIDs) { +// tagsEventBus.post(new TagsChangeEvent(fileIDs)); +// } + + public void deleteContentTag(ContentTag ct) throws TskCoreException { + synchronized (autopsyTagsManager) { + autopsyTagsManager.deleteContentTag(ct); + } + fireTagDeleted(ct); + } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index ebe9d71424..d4649dc09c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -58,7 +58,10 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.History; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; +import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; @@ -67,11 +70,11 @@ import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase; @@ -435,11 +438,6 @@ public final class ImageGalleryController { case CONTENT_CHANGED: //TODO: do we need to do anything here? -jm case DATA_ADDED: - ModuleDataEvent oldValue = (ModuleDataEvent) evt.getOldValue(); - if ("TagAction".equals(oldValue.getModuleName()) && oldValue.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { - getTagsManager().fireChange(Collections.singleton(-1L)); - getCategoryManager().invalidateCaches(); - } /* we could listen to DATA events and progressivly * update files, and get data from DataSource ingest * modules, but given that most modules don't post new @@ -490,6 +488,26 @@ public final class ImageGalleryController { setStale(true); } break; + case CONTENT_TAG_ADDED: + ContentTag newTag = (ContentTag) evt.getNewValue(); + if (Category.isCategoryTagName(newTag.getName())) { + new CategorizeAction(ImageGalleryController.this).addTag(newTag.getName(), ""); + } else { + getTagsManager().fireTagAdded(newTag); + } + break; + case CONTENT_TAG_DELETED: + ContentTag oldTag = (ContentTag) evt.getOldValue(); + final long fileID = oldTag.getContent().getId(); + if (getDatabase().isInDB(fileID)) { + if (Category.isCategoryTagName(oldTag.getName())) { + getCategoryManager().decrementCategoryCount(Category.fromTagName(oldTag.getName())); + getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); + } else { + getTagsManager().fireTagDeleted(oldTag); + } + } + break; } }); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 27f599cafe..8918934a6e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -161,4 +161,5 @@ public class CategorizeAction extends AddTagAction { DrawableTagsManager.refreshTagsInAutopsy(); } } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index bba6d5e4dc..98fdc316ad 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; +import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; @@ -43,49 +44,40 @@ public class DeleteFollowUpTagAction extends Action { private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTagAction.class.getName()); private final long fileID; - private final DrawableFile file; - private final ImageGalleryController controller; - public DeleteFollowUpTagAction(ImageGalleryController controller, DrawableFile file) { + public DeleteFollowUpTagAction(final ImageGalleryController controller, final DrawableFile file) { super("Delete Follow Up Tag"); - this.controller = controller; - this.file = file; this.fileID = file.getId(); setEventHandler((ActionEvent t) -> { - deleteTag(); + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + final GroupManager groupManager = controller.getGroupManager(); + final DrawableTagsManager tagsManager = controller.getTagsManager(); + + try { + final TagName followUpTagName = tagsManager.getFollowUpTagName(); + // remove file from old category group + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); + + List contentTagsByContent = tagsManager.getContentTagsByContent(file); + for (ContentTag ct : contentTagsByContent) { + if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { + tagsManager.deleteContentTag(ct); + } + } + + DrawableTagsManager.refreshTagsInAutopsy(); + //make sure rest of ui hears category change. + groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); + } + return null; + } + }.execute(); }); } - - /** - * - * - * - */ - private void deleteTag() { - - final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); - final GroupManager groupManager = controller.getGroupManager(); - final DrawableTagsManager tagsManager = controller.getTagsManager(); - - try { - final TagName followUpTagName = tagsManager.getFollowUpTagName(); - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); - - List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { - sleuthKitCase.deleteContentTag(ct); - } - } - - DrawableTagsManager.refreshTagsInAutopsy(); - - //make sure rest of ui hears category change. - groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); - } - } - } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index aed95afec6..00750c4ba9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -49,6 +49,9 @@ public enum Category { public static Category fromDisplayName(String displayName) { return nameMap.get(displayName); } + public static Category fromTagName(TagName tagName) { + return nameMap.get(tagName.getDisplayName()); + } public static boolean isCategoryTagName(TagName tName) { return isCategoryName(tName.getDisplayName()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 2027dae724..51a99bd5f7 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -595,9 +595,9 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { //we fire this event for all files so that the category counts get updated during initial db population controller.getCategoryManager().fireChange(fileIDs); - if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { - controller.getTagsManager().fireChange(fileIDs); - } +// if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { +// controller.getTagsManager().fireChange(fileIDs); +// } } private void popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 38c48c2951..93026d688d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -300,13 +300,6 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie return fileID; } - @Override - synchronized public void handleTagsChanged(TagsChangeEvent evnt) { - if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { - updateFollowUpIcon(); - } - } - synchronized protected void updateFollowUpIcon() { if (file != null) { try { @@ -383,6 +376,14 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie return imageBorder; } + @Subscribe + @Override + synchronized public void handleTagsChanged(TagsChangeEvent evnt) { + if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { + updateFollowUpIcon(); + } + } + @Subscribe @Override synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { From 62df408f0e349b903f89e6059b8428c5b016aabd Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 18 Jun 2015 17:23:08 -0400 Subject: [PATCH 061/198] do not add to list --- Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index b0c84fe805..f113a1b515 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -88,12 +88,13 @@ public class DataSourcesNode extends DisplayableItemNode { @Override protected void removeNotify() { Case.removePropertyChangeListener(pcl); + currentKeys.clear(); setKeys(Collections.emptySet()); } private void reloadKeys() { try { - currentKeys.addAll(Case.getCurrentCase().getDataSources()); + currentKeys = Case.getCurrentCase().getDataSources(); setKeys(currentKeys); } catch (TskCoreException | IllegalStateException ex) { logger.severe("Error getting data sources: " + ex.getMessage()); // NON-NLS From 7f6bbf1ebcd314966612d666ce2dc2c717f847db Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 17:00:05 -0400 Subject: [PATCH 062/198] more granular synchronization in DrawableTagsManager --- .../sleuthkit/autopsy/casemodule/Case.java | 21 ++++++++++-- .../casemodule/services/TagsManager.java | 20 +++++++---- .../imagegallery/DrawableTagsManager.java | 34 +++++++------------ 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index db1250ebf7..c304e97f9e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -49,8 +49,13 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.Version; -import org.sleuthkit.datamodel.*; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.Report; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitJNI.CaseDbHandle.AddImageProcess; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskException; /** * Stores all information for a given case. Only a single case can currently be @@ -126,7 +131,19 @@ public class Case implements SleuthkitCase.ErrorObserver { * case. The old value supplied by the event object is null and the new * value is a reference to a Report object representing the new report. */ - REPORT_ADDED; + REPORT_ADDED, + /** new value is tag added */ + BLACKBOARD_ARTIFACT_TAG_ADDED, + /** + * old value is tag deleted + */ + BLACKBOARD_ARTIFACT_TAG_DELETED, + /** new value is tag added */ + CONTENT_TAG_ADDED, + /** + * old value is tag deleted + */ + CONTENT_TAG_DELETED; }; private String name; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 6be8439029..4e5aaecdc8 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -24,9 +24,9 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; - import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; @@ -216,8 +216,10 @@ public class TagsManager implements Closeable { NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endLTbegin.msg")); } } - - return tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); + + final ContentTag newContentTag = tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); + Case.getPropertyChangeSupport().firePropertyChange(Case.Events.CONTENT_TAG_ADDED.toString(), null, newContentTag); + return newContentTag; } /** @@ -232,6 +234,7 @@ public class TagsManager implements Closeable { } tskCase.deleteContentTag(tag); + Case.getPropertyChangeSupport().firePropertyChange(Case.Events.CONTENT_TAG_DELETED.toString(), tag, null); } /** @@ -317,8 +320,10 @@ public class TagsManager implements Closeable { if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.addBlackboardArtifactTag(artifact, tagName, comment); + + final BlackboardArtifactTag newBlackboardArtifactTag = tskCase.addBlackboardArtifactTag(artifact, tagName, comment); + Case.getPropertyChangeSupport().firePropertyChange(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString(), null, newBlackboardArtifactTag); + return newBlackboardArtifactTag; } /** @@ -331,7 +336,8 @@ public class TagsManager implements Closeable { if (!tagNamesInitialized) { getExistingTagNames(); } - + + Case.getPropertyChangeSupport().firePropertyChange(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString(), tag, null); tskCase.deleteBlackboardArtifactTag(tag); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index add7065742..13455d2fb1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -45,7 +45,7 @@ public class DrawableTagsManager { private static final String FOLLOW_UP = "Follow Up"; - private Object autopsyTagsManagerLock = new Object(); + final private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; /** Used to distribute {@link TagsChangeEvent}s */ @@ -66,7 +66,7 @@ public class DrawableTagsManager { * @param autopsyTagsManager */ public void setAutopsyTagsManager(TagsManager autopsyTagsManager) { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { this.autopsyTagsManager = autopsyTagsManager; clearFollowUpTagName(); } @@ -77,7 +77,7 @@ public class DrawableTagsManager { * next case. */ public void clearFollowUpTagName() { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { followUpTagName = null; } } @@ -108,7 +108,7 @@ public class DrawableTagsManager { * @throws TskCoreException */ public TagName getFollowUpTagName() throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { if (Objects.isNull(followUpTagName)) { followUpTagName = getTagName(FOLLOW_UP); } @@ -117,7 +117,7 @@ public class DrawableTagsManager { } public Collection getNonCategoryTagNames() { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { try { return autopsyTagsManager.getAllTagNames().stream() .filter(Category::isCategoryTagName) @@ -140,13 +140,13 @@ public class DrawableTagsManager { * @throws TskCoreException */ public List getContentTagsByContent(Content content) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getContentTagsByContent(content); } } public TagName getTagName(String displayName) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { try { for (TagName tn : autopsyTagsManager.getAllTagNames()) { if (displayName.equals(tn.getDisplayName())) { @@ -175,14 +175,14 @@ public class DrawableTagsManager { public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { ContentTag addContentTag; - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { addContentTag = autopsyTagsManager.addContentTag(file, tagName, comment); } fireTagAdded(addContentTag); } public List getContentTagsByTagName(TagName t) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getContentTagsByTagName(t); } } @@ -203,13 +203,13 @@ public class DrawableTagsManager { } public List getAllTagNames() throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getAllTagNames(); } } public List getTagNamesInUse() throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getTagNamesInUse(); } } @@ -221,21 +221,11 @@ public class DrawableTagsManager { public void fireTagDeleted(ContentTag oldTag) { tagsEventBus.post(new TagsChangeEvent(Collections.singleton(oldTag.getContent().getId()))); } -// -// /** -// * fire a TagsChangeEvent with the given fileIDs -// * -// * @param fileIDs -// */ -// public final void fireChange(Collection fileIDs) { -// tagsEventBus.post(new TagsChangeEvent(fileIDs)); -// } public void deleteContentTag(ContentTag ct) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { autopsyTagsManager.deleteContentTag(ct); } fireTagDeleted(ct); } - } From b6d0c3c5b69bd812ea453f95d0a267da21c79b30 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Fri, 19 Jun 2015 11:43:13 -0400 Subject: [PATCH 063/198] catch all throwables while instantiating the POI container --- .../embeddedfileextractor/ImageExtractor.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java index 0ac96aedd1..4ed8341e37 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java @@ -207,7 +207,7 @@ class ImageExtractor { HWPFDocument doc = null; try { doc = new HWPFDocument(new ReadContentInputStream(af)); - } catch (IOException | OldFileFormatException ex) { + } catch (Throwable ex) { logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName())); //NON-NLS return null; } @@ -245,7 +245,7 @@ class ImageExtractor { XWPFDocument docx = null; try { docx = new XWPFDocument(new ReadContentInputStream(af)); - } catch (IOException | OldFileFormatException ex) { + } catch (Throwable ex) { logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docxContainer.init.err", af.getName())); //NON-NLS return null; } @@ -284,7 +284,7 @@ class ImageExtractor { SlideShow ppt = null; try { ppt = new SlideShow(new ReadContentInputStream(af)); - } catch (IOException | OldFileFormatException ex) { + } catch (Throwable ex) { logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName())); //NON-NLS return null; } @@ -354,7 +354,7 @@ class ImageExtractor { XMLSlideShow pptx; try { pptx = new XMLSlideShow(new ReadContentInputStream(af)); - } catch (IOException | OldFileFormatException ex) { + } catch (Throwable ex) { logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptxContainer.init.err", af.getName())); //NON-NLS return null; } @@ -401,7 +401,7 @@ class ImageExtractor { Workbook xls; try { xls = new HSSFWorkbook(new ReadContentInputStream(af)); - } catch (IOException | OldFileFormatException ex) { + } catch (Throwable ex) { logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err", af.getName()) + af.getName()); //NON-NLS return null; } @@ -444,7 +444,7 @@ class ImageExtractor { Workbook xlsx; try { xlsx = new XSSFWorkbook(new ReadContentInputStream(af)); - } catch (IOException | OldFileFormatException ex) { + } catch (Throwable ex) { logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsxContainer.init.err", af.getName())); //NON-NLS return null; } From ba81377eb0c260ce8bb36c7349b74fc3ca8ce059 Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 10:22:18 -0400 Subject: [PATCH 064/198] Tag Events - created new Case.Event enum values for BlackBoard/Content tags added/deleted - created new PropertyChangeEvent subclasses for BlackBoard/Content tags added/deleted - replaced ModuleDataEvent hack with new Tag Events - removed [in] from javadocs, other minor cleanup --- .../autopsy/actions/AddTagAction.java | 38 +- .../sleuthkit/autopsy/actions/TagAction.java | 35 +- .../sleuthkit/autopsy/casemodule/Case.java | 113 ++++- .../casemodule/services/TagsManager.java | 392 +++++++++++------- .../org/sleuthkit/autopsy/datamodel/Tags.java | 15 +- .../BlackBoardArtifactTagAddedEvent.java | 33 ++ .../BlackBoardArtifactTagDeletedEvent.java | 32 ++ .../autopsy/events/ContentTagAddedEvent.java | 35 ++ .../events/ContentTagDeletedEvent.java | 34 ++ .../autopsy/events/TagAddedEvent.java | 46 ++ .../autopsy/events/TagDeletedEvent.java | 45 ++ 11 files changed, 580 insertions(+), 238 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagAddedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagDeletedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/ContentTagAddedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/ContentTagDeletedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index b051fa2238..9c552247fd 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,20 +19,18 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.Collections; import java.util.List; import java.util.logging.Level; import javax.swing.JMenu; import javax.swing.JMenuItem; - import org.openide.util.NbBundle; import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.coreutils.Logger; /** * An abstract base class for Actions that allow users to tag SleuthKit data @@ -98,12 +96,8 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { if (null != tagNames && !tagNames.isEmpty()) { for (final TagName tagName : tagNames) { JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName()); - tagNameItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - addTag(tagName, NO_COMMENT); - refreshDirectoryTree(); - } + tagNameItem.addActionListener((ActionEvent e) -> { + addTag(tagName, NO_COMMENT); }); quickTagMenu.add(tagNameItem); } @@ -120,14 +114,10 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { // Selecting this item initiates a dialog that can be used to create // or select a tag name and adds a tag with the resulting name. JMenuItem newTagMenuItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.newTag")); - newTagMenuItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - TagName tagName = GetTagNameDialog.doDialog(); - if (tagName != null) { - addTag(tagName, NO_COMMENT); - refreshDirectoryTree(); - } + newTagMenuItem.addActionListener((ActionEvent e) -> { + TagName tagName = GetTagNameDialog.doDialog(); + if (null != tagName) { + addTag(tagName, NO_COMMENT); } }); quickTagMenu.add(newTagMenuItem); @@ -137,14 +127,10 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { // optional comment and adds a tag with the resulting name. JMenuItem tagAndCommentItem = new JMenuItem( NbBundle.getMessage(this.getClass(), "AddTagAction.tagAndComment")); - tagAndCommentItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); - if (null != tagNameAndComment) { - addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); - refreshDirectoryTree(); - } + tagAndCommentItem.addActionListener((ActionEvent e) -> { + GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); + if (null != tagNameAndComment) { + addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } }); add(tagAndCommentItem); diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagAction.java b/Core/src/org/sleuthkit/autopsy/actions/TagAction.java index a540ce878a..ed53af2c6f 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/TagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/TagAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,41 +20,26 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; /** * Abstract base class for Actions involving tags. */ - abstract class TagAction extends AbstractAction { +abstract class TagAction extends AbstractAction { + public TagAction(String menuText) { super(menuText); } - + @Override public void actionPerformed(ActionEvent event) { doAction(event); - refreshDirectoryTree(); - } - + } + /** - * Derived classes must implement this Template Method for actionPerformed(). - * @param event ActionEvent object passed to actionPerformed() + * Derived classes must implement this Template Method for + * actionPerformed(). + * + * @param event ActionEvent object passed to actionPerformed() */ abstract protected void doAction(ActionEvent event); - - /** - * Derived classes should call this method any time a tag is created, updated - * or deleted outside of an actionPerformed() call. - */ - @SuppressWarnings("deprecation") - protected void refreshDirectoryTree() { - - /* Note: this is a hack. In an ideal world, TagsManager would fire events so - * that the directory tree would refresh. But, we haven't had a chance to add - * that so, we fire these events and the tree refreshes based on them. - */ - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index db1250ebf7..19ec87e3cc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.Frame; +import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.BufferedInputStream; @@ -49,8 +50,19 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.Version; -import org.sleuthkit.datamodel.*; +import org.sleuthkit.autopsy.events.BlackBoardArtifactTagAddedEvent; +import org.sleuthkit.autopsy.events.BlackBoardArtifactTagDeletedEvent; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.Report; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitJNI.CaseDbHandle.AddImageProcess; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskException; /** * Stores all information for a given case. Only a single case can currently be @@ -126,7 +138,19 @@ public class Case implements SleuthkitCase.ErrorObserver { * case. The old value supplied by the event object is null and the new * value is a reference to a Report object representing the new report. */ - REPORT_ADDED; + REPORT_ADDED, + /** Property name for the event when a new BlackBoardArtifactTag is + * added. The new value is tag added, the old value is empty */ + BLACKBOARD_ARTIFACT_TAG_ADDED, + /** Property name for the event when a new BlackBoardArtifactTag is + * deleted. The new value is empty, the old value is the deleted tag */ + BLACKBOARD_ARTIFACT_TAG_DELETED, + /** Property name for the event when a new ContentTag is + * added. The new value is tag added, the old value is empty */ + CONTENT_TAG_ADDED, + /** Property name for the event when a new ContentTag is + * deleted. The new value is empty, the old value is the deleted tag */ + CONTENT_TAG_DELETED; }; private String name; @@ -267,12 +291,13 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Creates a new case (create the XML config file and database) * - * @param caseDir The directory to store case data in. Will be created if it - * doesn't already exist. If it exists, it should have all of the needed sub - * dirs that createCaseDirectory() will create. - * @param caseName the name of case + * @param caseDir The directory to store case data in. Will be created if + * it + * doesn't already exist. If it exists, it should have all of the needed sub + * dirs that createCaseDirectory() will create. + * @param caseName the name of case * @param caseNumber the case number - * @param examiner the examiner for this case + * @param examiner the examiner for this case */ public static void create(String caseDir, String caseName, String caseNumber, String examiner) throws CaseActionException { logger.log(Level.INFO, "Creating new case.\ncaseDir: {0}\ncaseName: {1}", new Object[]{caseDir, caseName}); //NON-NLS @@ -418,7 +443,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Sends out event and reopens windows if needed. * * @param imgPaths the paths of the image that being added - * @param imgId the ID of the image that being added + * @param imgId the ID of the image that being added * @param timeZone the timeZone of the image where it's added */ @Deprecated @@ -476,6 +501,59 @@ public class Case implements SleuthkitCase.ErrorObserver { CoreComponentControl.openCoreWindows(); } + /** + * Notifies the UI that a new ContentTag has been added. + * + * @param newTag new ContentTag added + */ + public void notifyContentTagAdded(ContentTag newTag) { + notify(new ContentTagAddedEvent(newTag)); + } + + /** + * Notifies the UI that a ContentTag has been deleted. + * + * @param deletedTag ContentTag deleted + */ + public void notifyContentTagDeleted(ContentTag deletedTag) { + notify(new ContentTagDeletedEvent(deletedTag)); + } + + /** + * Notifies the UI that a new BlackboardArtifactTag has been added. + * + * @param newTag new BlackboardArtifactTag added + */ + public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) { + notify(new BlackBoardArtifactTagAddedEvent(newTag)); + } + + /** + * Notifies the UI that a BlackboardArtifactTag has been. + * + * @param deletedTag BlackboardArtifactTag deleted + */ + public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { + notify(new BlackBoardArtifactTagDeletedEvent(deletedTag)); + } + + /** + * Notifies the UI about a Case level event. + * + * @param propertyChangeEvent the event to distribute + */ + private void notify(final PropertyChangeEvent propertyChangeEvent) { + try { + pcs.firePropertyChange(propertyChangeEvent); + } catch (Exception e) { + logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS + MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), + NbBundle.getMessage(this.getClass(), + "Case.changeCase.errListenToCaseUpdates.msg"), + MessageNotifyUtil.MessageType.ERROR); + } + } + /** * @return The Services object for this case. */ @@ -540,9 +618,9 @@ public class Case implements SleuthkitCase.ErrorObserver { * Updates the case name. * * @param oldCaseName the old case name that wants to be updated - * @param oldPath the old path that wants to be updated + * @param oldPath the old path that wants to be updated * @param newCaseName the new case name - * @param newPath the new path + * @param newPath the new path */ void updateCaseName(String oldCaseName, String oldPath, String newCaseName, String newPath) throws CaseActionException { try { @@ -801,6 +879,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Get the data model Content objects in the root of this case's hierarchy. * * @return a list of the root objects + * * @throws org.sleuthkit.datamodel.TskCoreException */ public List getDataSources() throws TskCoreException { @@ -934,7 +1013,7 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * to create the case directory * - * @param caseDir Path to the case directory (typically base + case name) + * @param caseDir Path to the case directory (typically base + case name) * @param caseName the case name (used only for error messages) * * @throws CaseActionException throw if could not create the case dir @@ -1154,12 +1233,14 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Adds a report to the case. * - * @param [in] localPath The path of the report file, must be in the case - * directory or one of its subdirectories. - * @param [in] sourceModuleName The name of the module that created the - * report. - * @param [in] reportName The report name, may be empty. + * @param localPath The path of the report file, must be in the case + * directory or one of its subdirectories. + * @param sourceModuleName The name of the module that created the + * report. + * @param reportName The report name, may be empty. + * * @return A Report data transfer object (DTO) for the new row. + * * @throws TskCoreException */ public void addReport(String localPath, String srcModuleName, String reportName) throws TskCoreException { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 6be8439029..123238c4e3 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,9 +24,9 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; - import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; @@ -37,28 +37,32 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** - * A per case instance of this class functions as an Autopsy service that - * manages the creation, updating, and deletion of tags applied to content and - * blackboard artifacts by users. + * A per case instance of this class functions as an Autopsy service that + * manages the creation, updating, and deletion of tags applied to content and + * blackboard artifacts by users. */ public class TagsManager implements Closeable { + private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS - private final SleuthkitCase tskCase; + private final SleuthkitCase tskCase; private final HashMap uniqueTagNames = new HashMap<>(); private boolean tagNamesInitialized = false; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized. - - // Use this exception and the member hash map to manage uniqueness of hash - // names. This is deemed more proactive and informative than leaving this to - // the UNIQUE constraint on the display_name field of the tag_names table in - // the case database. - public class TagNameAlreadyExistsException extends Exception { - } - + /** - * Package-scope constructor for use of the Services class. An instance of + * Use this exception and the member hash map to manage uniqueness of hash + * names. This is deemed more proactive and informative than leaving this to + * the UNIQUE constraint on the display_name field of the tag_names table in + * the case database. + */ + public static class TagNameAlreadyExistsException extends Exception { + } + + /** + * Package-scope constructor for use of the Services class. An instance of * TagsManager should be created for each case that is opened. - * @param [in] tskCase The SleuthkitCase object for the current case. + * + * @param tskCase The SleuthkitCase object for the current case. */ TagsManager(SleuthkitCase tskCase) { this.tskCase = tskCase; @@ -67,38 +71,44 @@ public class TagsManager implements Closeable { } /** - * Gets a list of all tag names currently available for tagging content or + * Gets a list of all tag names currently available for tagging content or * blackboard artifacts. - * @return A list, possibly empty, of TagName data transfer objects (DTOs). - * @throws TskCoreException + * + * @return A list, possibly empty, of TagName data transfer objects (DTOs). + * + * @throws TskCoreException */ - public synchronized List getAllTagNames() throws TskCoreException { + public synchronized List getAllTagNames() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + return tskCase.getAllTagNames(); } /** - * Gets a list of all tag names currently used for tagging content or + * Gets a list of all tag names currently used for tagging content or * blackboard artifacts. - * @return A list, possibly empty, of TagName data transfer objects (DTOs). - * @throws TskCoreException + * + * @return A list, possibly empty, of TagName data transfer objects (DTOs). + * + * @throws TskCoreException */ - public synchronized List getTagNamesInUse() throws TskCoreException { + public synchronized List getTagNamesInUse() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + return tskCase.getTagNamesInUse(); } - + /** * Checks whether a tag name with a given display name exists. - * @param [in] tagDisplayName The display name for which to check. + * + * @param tagDisplayName The display name for which to check. + * * @return True if the tag name exists, false otherwise. */ public synchronized boolean tagNameExists(String tagDisplayName) { @@ -106,15 +116,19 @@ public class TagsManager implements Closeable { if (!tagNamesInitialized) { getExistingTagNames(); } - + return uniqueTagNames.containsKey(tagDisplayName); } - + /** * Adds a new tag name to the current case and to the tags settings. - * @param [in] displayName The display name for the new tag name. - * @return A TagName data transfer object (DTO) representing the new tag name. - * @throws TagNameAlreadyExistsException, TskCoreException + * + * @param displayName The display name for the new tag name. + * + * @return A TagName data transfer object (DTO) representing the new tag + * name. + * + * @throws TagNameAlreadyExistsException, TskCoreException */ public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, "", TagName.HTML_COLOR.NONE); @@ -122,10 +136,14 @@ public class TagsManager implements Closeable { /** * Adds a new tag name to the current case and to the tags settings. - * @param [in] displayName The display name for the new tag name. - * @param [in] description The description for the new tag name. - * @return A TagName data transfer object (DTO) representing the new tag name. - * @throws TagNameAlreadyExistsException, TskCoreException + * + * @param displayName The display name for the new tag name. + * @param description The description for the new tag name. + * + * @return A TagName data transfer object (DTO) representing the new tag + * name. + * + * @throws TagNameAlreadyExistsException, TskCoreException */ public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, description, TagName.HTML_COLOR.NONE); @@ -133,82 +151,95 @@ public class TagsManager implements Closeable { /** * Adds a new tag name to the current case and to the tags settings. - * @param [in] displayName The display name for the new tag name. - * @param [in] description The description for the new tag name. - * @param [in] color The HTML color to associate with the new tag name. - * @return A TagName data transfer object (DTO) representing the new tag name. - * @throws TagNameAlreadyExistsException, TskCoreException + * + * @param displayName The display name for the new tag name. + * @param description The description for the new tag name. + * @param color The HTML color to associate with the new tag name. + * + * @return A TagName data transfer object (DTO) representing the new tag + * name. + * + * @throws TagNameAlreadyExistsException, TskCoreException */ public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + if (uniqueTagNames.containsKey(displayName)) { throw new TagNameAlreadyExistsException(); } // Add the tag name to the case. - TagName newTagName = tskCase.addTagName(displayName, description, color); + TagName newTagName = tskCase.addTagName(displayName, description, color); // Add the tag name to the tags settings. uniqueTagNames.put(newTagName.getDisplayName(), newTagName); - saveTagNamesToTagsSettings(); + saveTagNamesToTagsSettings(); return newTagName; } - + /** * Tags a content object. - * @param [in] content The content to tag. - * @param [in] tagName The name to use for the tag. - * @return A ContentTag data transfer object (DTO) representing the new tag. - * @throws TskCoreException + * + * @param content The content to tag. + * @param tagName The name to use for the tag. + * + * @return A ContentTag data transfer object (DTO) representing the new tag. + * + * @throws TskCoreException */ public ContentTag addContentTag(Content content, TagName tagName) throws TskCoreException { return addContentTag(content, tagName, "", -1, -1); - } - + } + /** * Tags a content object. - * @param [in] content The content to tag. - * @param [in] tagName The name to use for the tag. - * @param [in] comment A comment to store with the tag. - * @return A ContentTag data transfer object (DTO) representing the new tag. - * @throws TskCoreException + * + * @param content The content to tag. + * @param tagName The name to use for the tag. + * @param comment A comment to store with the tag. + * + * @return A ContentTag data transfer object (DTO) representing the new tag. + * + * @throws TskCoreException */ public ContentTag addContentTag(Content content, TagName tagName, String comment) throws TskCoreException { return addContentTag(content, tagName, comment, -1, -1); - } - + } + /** * Tags a content object or a section of a content object. - * @param [in] content The content to tag. - * @param [in] tagName The name to use for the tag. - * @param [in] comment A comment to store with the tag. - * @param [in] beginByteOffset Designates the beginning of a tagged section. - * @param [in] endByteOffset Designates the end of a tagged section. - * @return A ContentTag data transfer object (DTO) representing the new tag. - * @throws IllegalArgumentException, TskCoreException + * + * @param content The content to tag. + * @param tagName The name to use for the tag. + * @param comment A comment to store with the tag. + * @param beginByteOffset Designates the beginning of a tagged section. + * @param endByteOffset Designates the end of a tagged section. + * + * @return A ContentTag data transfer object (DTO) representing the new tag. + * + * @throws IllegalArgumentException, TskCoreException */ public synchronized ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + if (beginByteOffset >= 0 && endByteOffset >= 1) { if (beginByteOffset > content.getSize() - 1) { throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), - "TagsManager.addContentTag.exception.beginByteOffsetOOR.msg", - beginByteOffset, content.getSize() - 1)); + "TagsManager.addContentTag.exception.beginByteOffsetOOR.msg", + beginByteOffset, content.getSize() - 1)); } if (endByteOffset > content.getSize() - 1) { throw new IllegalArgumentException( NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endByteOffsetOOR.msg", - endByteOffset, content.getSize() - 1)); + endByteOffset, content.getSize() - 1)); } if (endByteOffset < beginByteOffset) { @@ -216,28 +247,34 @@ public class TagsManager implements Closeable { NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endLTbegin.msg")); } } - - return tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); + final ContentTag newContentTag = tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); + Case.getCurrentCase().notifyContentTagAdded(newContentTag); + return newContentTag; } - + /** * Deletes a content tag. - * @param [in] tag The tag to delete. - * @throws TskCoreException + * + * @param tag The tag to delete. + * + * @throws TskCoreException */ public synchronized void deleteContentTag(ContentTag tag) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + tskCase.deleteContentTag(tag); + Case.getCurrentCase().notifyContentTagDeleted(tag); } /** * Gets all content tags for the current case. + * * @return A list, possibly empty, of content tags. - * @throws TskCoreException + * + * @throws TskCoreException */ public List getAllContentTags() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. @@ -245,100 +282,126 @@ public class TagsManager implements Closeable { getExistingTagNames(); } - return tskCase.getAllContentTags(); + return tskCase.getAllContentTags(); } - + /** * Gets content tags count by tag name. - * @param [in] tagName The tag name of interest. + * + * @param tagName The tag name of interest. + * * @return A count of the content tags with the specified tag name. - * @throws TskCoreException + * + * @throws TskCoreException */ public synchronized long getContentTagsCountByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getContentTagsCountByTagName(tagName); + + return tskCase.getContentTagsCountByTagName(tagName); } - + /** * Gets content tags by tag name. - * @param [in] tagName The tag name of interest. - * @return A list, possibly empty, of the content tags with the specified tag name. - * @throws TskCoreException + * + * @param tagName The tag name of interest. + * + * @return A list, possibly empty, of the content tags with the specified + * tag name. + * + * @throws TskCoreException */ public synchronized List getContentTagsByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getContentTagsByTagName(tagName); + + return tskCase.getContentTagsByTagName(tagName); } - + /** * Gets content tags count by content. - * @param [in] content The content of interest. - * @return A list, possibly empty, of the tags that have been applied to the artifact. - * @throws TskCoreException + * + * @param content The content of interest. + * + * @return A list, possibly empty, of the tags that have been applied to the + * artifact. + * + * @throws TskCoreException */ public synchronized List getContentTagsByContent(Content content) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getContentTagsByContent(content); + + return tskCase.getContentTagsByContent(content); } - + /** * Tags a blackboard artifact object. - * @param [in] artifact The blackboard artifact to tag. - * @param [in] tagName The name to use for the tag. - * @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag. - * @throws TskCoreException + * + * @param artifact The blackboard artifact to tag. + * @param tagName The name to use for the tag. + * + * @return A BlackboardArtifactTag data transfer object (DTO) representing + * the new tag. + * + * @throws TskCoreException */ public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException { - return addBlackboardArtifactTag(artifact, tagName, ""); + return addBlackboardArtifactTag(artifact, tagName, ""); } - + /** * Tags a blackboard artifact object. - * @param [in] artifact The blackboard artifact to tag. - * @param [in] tagName The name to use for the tag. - * @param [in] comment A comment to store with the tag. - * @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag. - * @throws TskCoreException + * + * @param artifact The blackboard artifact to tag. + * @param tagName The name to use for the tag. + * @param comment A comment to store with the tag. + * + * @return A BlackboardArtifactTag data transfer object (DTO) representing + * the new tag. + * + * @throws TskCoreException */ public synchronized BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.addBlackboardArtifactTag(artifact, tagName, comment); + + BlackboardArtifactTag addBlackboardArtifactTag = tskCase.addBlackboardArtifactTag(artifact, tagName, comment); + Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(addBlackboardArtifactTag); + return addBlackboardArtifactTag; } /** * Deletes a blackboard artifact tag. - * @param [in] tag The tag to delete. - * @throws TskCoreException + * + * @param tag The tag to delete. + * + * @throws TskCoreException */ public synchronized void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + tskCase.deleteBlackboardArtifactTag(tag); + Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); } - + /** * Gets all blackboard artifact tags for the current case. + * * @return A list, possibly empty, of blackboard artifact tags. - * @throws TskCoreException + * + * @throws TskCoreException */ public List getAllBlackboardArtifactTags() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. @@ -346,100 +409,110 @@ public class TagsManager implements Closeable { getExistingTagNames(); } - return tskCase.getAllBlackboardArtifactTags(); + return tskCase.getAllBlackboardArtifactTags(); } - + /** * Gets blackboard artifact tags count by tag name. - * @param [in] tagName The tag name of interest. - * @return A count of the blackboard artifact tags with the specified tag name. - * @throws TskCoreException + * + * @param tagName The tag name of interest. + * + * @return A count of the blackboard artifact tags with the specified tag + * name. + * + * @throws TskCoreException */ public synchronized long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getBlackboardArtifactTagsCountByTagName(tagName); + + return tskCase.getBlackboardArtifactTagsCountByTagName(tagName); } - + /** * Gets blackboard artifact tags by tag name. - * @param [in] tagName The tag name of interest. - * @return A list, possibly empty, of the blackboard artifact tags with the specified tag name. - * @throws TskCoreException + * + * @param tagName The tag name of interest. + * + * @return A list, possibly empty, of the blackboard artifact tags with the + * specified tag name. + * + * @throws TskCoreException */ - public synchronized List getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException { + public synchronized List getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getBlackboardArtifactTagsByTagName(tagName); + + return tskCase.getBlackboardArtifactTagsByTagName(tagName); } /** * Gets blackboard artifact tags for a particular blackboard artifact. - * @param [in] artifact The blackboard artifact of interest. - * @return A list, possibly empty, of the tags that have been applied to the artifact. - * @throws TskCoreException + * + * @param artifact The blackboard artifact of interest. + * + * @return A list, possibly empty, of the tags that have been applied to the + * artifact. + * + * @throws TskCoreException */ - public synchronized List getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException { + public synchronized List getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getBlackboardArtifactTagsByArtifact(artifact); + + return tskCase.getBlackboardArtifactTagsByArtifact(artifact); } - + @Override - public void close() throws IOException { - saveTagNamesToTagsSettings(); - } - + public void close() throws IOException { + saveTagNamesToTagsSettings(); + } + private void getExistingTagNames() { getTagNamesFromCurrentCase(); getTagNamesFromTagsSettings(); getPredefinedTagNames(); - saveTagNamesToTagsSettings(); + saveTagNamesToTagsSettings(); tagNamesInitialized = true; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized. } - + private void getTagNamesFromCurrentCase() { try { List currentTagNames = tskCase.getAllTagNames(); for (TagName tagName : currentTagNames) { uniqueTagNames.put(tagName.getDisplayName(), tagName); } - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); //NON-NLS - } + } } - + private void getTagNamesFromTagsSettings() { String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); - if (null != setting && !setting.isEmpty()) { + if (null != setting && !setting.isEmpty()) { // Read the tag name setting and break it into tag name tuples. - List tagNameTuples = Arrays.asList(setting.split(";")); - + List tagNameTuples = Arrays.asList(setting.split(";")); + // Parse each tuple and add the tag names to the current case, one // at a time to gracefully discard any duplicates or corrupt tuples. - for (String tagNameTuple : tagNameTuples) { + for (String tagNameTuple : tagNameTuples) { String[] tagNameAttributes = tagNameTuple.split(","); - if (!uniqueTagNames.containsKey(tagNameAttributes[0])) { + if (!uniqueTagNames.containsKey(tagNameAttributes[0])) { try { TagName tagName = tskCase.addTagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2])); uniqueTagNames.put(tagName.getDisplayName(), tagName); - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + tagNameAttributes[0], ex); //NON-NLS } } } - } + } } private void getPredefinedTagNames() { @@ -448,13 +521,12 @@ public class TagsManager implements Closeable { TagName tagName = tskCase.addTagName( NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"), "", TagName.HTML_COLOR.NONE); uniqueTagNames.put(tagName.getDisplayName(), tagName); - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add predefined 'Bookmark' tag name", ex); //NON-NLS } } - } - + } + private void saveTagNamesToTagsSettings() { if (!uniqueTagNames.isEmpty()) { StringBuilder setting = new StringBuilder(); @@ -466,7 +538,7 @@ public class TagsManager implements Closeable { setting.append(tagName.getDescription()).append(","); setting.append(tagName.getColor().name()); } - ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); + ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); } - } + } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index cc7958355e..5dccc5252d 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -35,8 +35,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -119,19 +117,14 @@ public class Tags implements AutopsyVisitableItem { private final PropertyChangeListener pcl = new PropertyChangeListener() { @Override - @SuppressWarnings("deprecation") public void propertyChange(PropertyChangeEvent evt) { String eventType = evt.getPropertyName(); - if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { - /* Note: this is a hack. In an ideal world, TagsManager - * would fire events so that the directory tree would - * refresh. But, we haven't had a chance to add that so, we - * fire these events and the tree refreshes based on them. */ - if ((((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT) - || ((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { + if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString()) + || eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString()) + || eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString()) + || eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) { refresh(true); tagResults.update(); - } } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { refresh(true); tagResults.update(); diff --git a/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagAddedEvent.java b/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagAddedEvent.java new file mode 100644 index 0000000000..d50bd2237b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagAddedEvent.java @@ -0,0 +1,33 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.BlackboardArtifactTag; + +/** + * + */ +public class BlackBoardArtifactTagAddedEvent extends TagAddedEvent { + + public BlackBoardArtifactTagAddedEvent(BlackboardArtifactTag newTag) { + super(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString(), newTag + ); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagDeletedEvent.java b/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagDeletedEvent.java new file mode 100644 index 0000000000..b2901ac5dc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagDeletedEvent.java @@ -0,0 +1,32 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.BlackboardArtifactTag; + +/** + * + */ +public class BlackBoardArtifactTagDeletedEvent extends TagDeletedEvent { + + public BlackBoardArtifactTagDeletedEvent(BlackboardArtifactTag oldValue) { + super(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString(), oldValue); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/events/ContentTagAddedEvent.java b/Core/src/org/sleuthkit/autopsy/events/ContentTagAddedEvent.java new file mode 100644 index 0000000000..ffd196a4c7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/ContentTagAddedEvent.java @@ -0,0 +1,35 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.ContentTag; + +/** + * An event that is fired when a ContentTag is added. + */ +@Immutable +public class ContentTagAddedEvent extends TagAddedEvent { + + public ContentTagAddedEvent(ContentTag newTag) { + super(Case.Events.CONTENT_TAG_ADDED.toString(), newTag); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/events/ContentTagDeletedEvent.java b/Core/src/org/sleuthkit/autopsy/events/ContentTagDeletedEvent.java new file mode 100644 index 0000000000..6c6d11745f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/ContentTagDeletedEvent.java @@ -0,0 +1,34 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.ContentTag; + +/** + * An event that is fired when a ContentTag is deleted. + */ +@Immutable +public class ContentTagDeletedEvent extends TagDeletedEvent { + + public ContentTagDeletedEvent(ContentTag deletedTag) { + super(Case.Events.CONTENT_TAG_DELETED.toString(), deletedTag); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java b/Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java new file mode 100644 index 0000000000..b9acb256bb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java @@ -0,0 +1,46 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import java.beans.PropertyChangeEvent; +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.Tag; + +/** + * Base Class for events that are fired when a Tag is added + */ +@Immutable +abstract class TagAddedEvent extends PropertyChangeEvent { + + protected TagAddedEvent(String propertyName, T newValue) { + super(Case.class, propertyName, null, newValue); + } + + /** + * get the Tag that was added + * + * @return the tTag + */ + @SuppressWarnings("unchecked") + public T getAddedTag() { + return (T) getNewValue(); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java b/Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java new file mode 100644 index 0000000000..7d0cfca18e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java @@ -0,0 +1,45 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import java.beans.PropertyChangeEvent; +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.Tag; + +/** + * Base Class for events that are fired when a Tag is deleted + */ +@Immutable +abstract class TagDeletedEvent extends PropertyChangeEvent { + + protected TagDeletedEvent(String propertyName, T oldValue) { + super(Case.class, propertyName, oldValue, null); + } + + /** + * get the Tag that was deleted + * + * @return the Tag + */ + @SuppressWarnings("unchecked") + public T getDeletedTag() { + return (T) getOldValue(); + } +} From 03731d9756916aeeed71ee5ac8ac8dde9339f42c Mon Sep 17 00:00:00 2001 From: Sidhesh Mhatre Date: Fri, 19 Jun 2015 13:23:27 -0400 Subject: [PATCH 065/198] comment about POI RuntimeExceptions added --- .../modules/embeddedfileextractor/ImageExtractor.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java index 4ed8341e37..7a48c061ad 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java @@ -208,6 +208,7 @@ class ImageExtractor { try { doc = new HWPFDocument(new ReadContentInputStream(af)); } catch (Throwable ex) { + // instantiating POI containers throw RuntimeExceptions logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName())); //NON-NLS return null; } @@ -246,6 +247,7 @@ class ImageExtractor { try { docx = new XWPFDocument(new ReadContentInputStream(af)); } catch (Throwable ex) { + // instantiating POI containers throw RuntimeExceptions logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docxContainer.init.err", af.getName())); //NON-NLS return null; } @@ -285,6 +287,7 @@ class ImageExtractor { try { ppt = new SlideShow(new ReadContentInputStream(af)); } catch (Throwable ex) { + // instantiating POI containers throw RuntimeExceptions logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName())); //NON-NLS return null; } @@ -355,6 +358,7 @@ class ImageExtractor { try { pptx = new XMLSlideShow(new ReadContentInputStream(af)); } catch (Throwable ex) { + // instantiating POI containers throw RuntimeExceptions logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptxContainer.init.err", af.getName())); //NON-NLS return null; } @@ -402,6 +406,7 @@ class ImageExtractor { try { xls = new HSSFWorkbook(new ReadContentInputStream(af)); } catch (Throwable ex) { + // instantiating POI containers throw RuntimeExceptions logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err", af.getName()) + af.getName()); //NON-NLS return null; } @@ -445,6 +450,7 @@ class ImageExtractor { try { xlsx = new XSSFWorkbook(new ReadContentInputStream(af)); } catch (Throwable ex) { + // instantiating POI containers throw RuntimeExceptions logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsxContainer.init.err", af.getName())); //NON-NLS return null; } @@ -590,4 +596,4 @@ class ImageExtractor { return parentFile; } } -} \ No newline at end of file +} From c6834afb4a0587534b8ee1989f9acb7f3aa97755 Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 13:53:53 -0400 Subject: [PATCH 066/198] use new Autopsy Tag events, don't fire extra events from ig, but listen to events from autopsy --- .../casemodule/services/TagsManager.java | 1 - .../imagegallery/DrawableTagsManager.java | 82 ++++++++----------- .../imagegallery/ImageGalleryController.java | 30 +++---- .../autopsy/imagegallery/TagsChangeEvent.java | 41 ---------- .../actions/AddDrawableTagAction.java | 9 +- .../imagegallery/actions/AddTagAction.java | 9 +- .../actions/CategorizeAction.java | 27 +++--- .../actions/DeleteFollowUpTagAction.java | 7 +- .../imagegallery/datamodel/Category.java | 12 --- .../datamodel/CategoryChangeEvent.java | 14 +++- .../datamodel/CategoryManager.java | 69 +++++++++++++++- .../imagegallery/datamodel/DrawableFile.java | 2 +- .../imagegallery/grouping/GroupManager.java | 64 +++++++++------ .../imagegallery/gui/DrawableView.java | 8 +- .../imagegallery/gui/DrawableViewBase.java | 18 ++-- .../imagegallery/gui/MetaDataPane.java | 18 ++-- 16 files changed, 208 insertions(+), 203 deletions(-) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 5a52cefde9..72fdf22ca4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -250,7 +250,6 @@ public class TagsManager implements Closeable { final ContentTag newContentTag = tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); Case.getCurrentCase().notifyContentTagAdded(newContentTag); return newContentTag; - return newContentTag; } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 13455d2fb1..0bbc4b9d5a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -27,11 +27,11 @@ import java.util.logging.Level; import java.util.stream.Collectors; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -59,6 +59,32 @@ public class DrawableTagsManager { } + /** + * register an object to receive CategoryChangeEvents + * + * @param listner + */ + public void registerListener(Object listner) { + tagsEventBus.register(listner); + } + + /** + * unregister an object from receiving CategoryChangeEvents + * + * @param listener + */ + public void unregisterListener(Object listener) { + tagsEventBus.unregister(listener); + } + + public void fireTagAddedEvent(ContentTagAddedEvent event) { + tagsEventBus.post(event); + } + + public void fireTagDeletedEvent(ContentTagDeletedEvent event) { + tagsEventBus.post(event); + } + /** * assign a new TagsManager to back this one, ie when the current case * changes @@ -82,24 +108,6 @@ public class DrawableTagsManager { } } - /** - * register an object to receive CategoryChangeEvents - * - * @param listner - */ - public void registerListener(Object listner) { - tagsEventBus.register(listner); - } - - /** - * unregister an object from receiving CategoryChangeEvents - * - * @param listener - */ - public void unregisterListener(Object listener) { - tagsEventBus.unregister(listener); - } - /** * get the (cached) follow up TagName * @@ -120,7 +128,7 @@ public class DrawableTagsManager { synchronized (autopsyTagsManagerLock) { try { return autopsyTagsManager.getAllTagNames().stream() - .filter(Category::isCategoryTagName) + .filter(CategoryManager::isCategoryTagName) .collect(Collectors.toSet()); } catch (TskCoreException | IllegalStateException ex) { Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); @@ -173,12 +181,10 @@ public class DrawableTagsManager { } } - public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { - ContentTag addContentTag; + public ContentTag addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { synchronized (autopsyTagsManagerLock) { - addContentTag = autopsyTagsManager.addContentTag(file, tagName, comment); + return autopsyTagsManager.addContentTag(file, tagName, comment); } - fireTagAdded(addContentTag); } public List getContentTagsByTagName(TagName t) throws TskCoreException { @@ -187,21 +193,6 @@ public class DrawableTagsManager { } } - /** - * Fire the ModuleDataEvent that we use as a place holder for a real Tag - * Event. This is used to refresh the autopsy tag tree and the ui in - * ImageGallery - * - * - * Note: this is a hack. In an ideal world, TagsManager would fire - * events so that the directory tree would refresh. But, we haven't - * had a chance to add that so, we fire these events and the tree - * refreshes based on them. - */ - static public void refreshTagsInAutopsy() { - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - } - public List getAllTagNames() throws TskCoreException { synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getAllTagNames(); @@ -214,18 +205,9 @@ public class DrawableTagsManager { } } - public void fireTagAdded(ContentTag newTag) { - tagsEventBus.post(new TagsChangeEvent(Collections.singleton(newTag.getContent().getId()))); - } - - public void fireTagDeleted(ContentTag oldTag) { - tagsEventBus.post(new TagsChangeEvent(Collections.singleton(oldTag.getContent().getId()))); - } - public void deleteContentTag(ContentTag ct) throws TskCoreException { synchronized (autopsyTagsManagerLock) { autopsyTagsManager.deleteContentTag(ct); } - fireTagDeleted(ct); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index d4649dc09c..de1b0a399f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.imagegallery; import java.beans.PropertyChangeEvent; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.BlockingQueue; @@ -58,10 +57,9 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.History; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; @@ -74,7 +72,6 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase; @@ -365,6 +362,8 @@ public final class ImageGalleryController { categoryManager.setDb(db); tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); tagsManager.registerListener(groupManager); + tagsManager.registerListener(categoryManager); + } else { reset(); } @@ -383,6 +382,7 @@ public final class ImageGalleryController { }); tagsManager.clearFollowUpTagName(); tagsManager.unregisterListener(groupManager); + tagsManager.unregisterListener(categoryManager); Toolbar.getDefault(this).reset(); groupManager.clear(); @@ -489,23 +489,15 @@ public final class ImageGalleryController { } break; case CONTENT_TAG_ADDED: - ContentTag newTag = (ContentTag) evt.getNewValue(); - if (Category.isCategoryTagName(newTag.getName())) { - new CategorizeAction(ImageGalleryController.this).addTag(newTag.getName(), ""); - } else { - getTagsManager().fireTagAdded(newTag); + final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt; + if (getDatabase().isInDB((tagAddedEvent).getAddedTag().getContent().getId())) { + getTagsManager().fireTagAddedEvent(tagAddedEvent); } break; case CONTENT_TAG_DELETED: - ContentTag oldTag = (ContentTag) evt.getOldValue(); - final long fileID = oldTag.getContent().getId(); - if (getDatabase().isInDB(fileID)) { - if (Category.isCategoryTagName(oldTag.getName())) { - getCategoryManager().decrementCategoryCount(Category.fromTagName(oldTag.getName())); - getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); - } else { - getTagsManager().fireTagDeleted(oldTag); - } + final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) evt; + if (getDatabase().isInDB((tagDeletedEvent).getDeletedTag().getContent().getId())) { + getTagsManager().fireTagDeletedEvent(tagDeletedEvent); } break; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java deleted file mode 100644 index 0647a18456..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery; - -import java.util.Collection; -import java.util.Collections; -import javax.annotation.concurrent.Immutable; - -/** - * - */ -@Immutable -public class TagsChangeEvent { - - private final Collection fileIDs; - - public Collection getFileIDs() { - return Collections.unmodifiableCollection(fileIDs); - } - - public TagsChangeEvent(Collection fileIDs) { - this.fileIDs = fileIDs; - } - -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index e88c51f12b..be9343f4de 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -28,11 +27,8 @@ import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.openide.util.Utilities; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TagName; @@ -87,10 +83,9 @@ public class AddDrawableTagAction extends AddTagAction { JOptionPane.showMessageDialog(null, "Unable to tag " + fileID + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); } - //make sure rest of ui hears category change. - controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); +// //make sure rest of ui hears category change. +// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } - DrawableTagsManager.refreshTagsInAutopsy(); return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 4e8f9b827f..1383cdcd8c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -33,7 +33,7 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -97,11 +97,10 @@ abstract class AddTagAction { // a tag with the associated tag name. if (null != tagNames && !tagNames.isEmpty()) { for (final TagName tagName : tagNames) { - if (Category.isNotCategoryTagName(tagName)) { + if (CategoryManager.isNotCategoryTagName(tagName)) { MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); tagNameItem.setOnAction((ActionEvent t) -> { addTag(tagName, NO_COMMENT); - DrawableTagsManager.refreshTagsInAutopsy(); }); quickTagMenu.getItems().add(tagNameItem); } @@ -123,7 +122,6 @@ abstract class AddTagAction { TagName tagName = GetTagNameDialog.doDialog(); if (tagName != null) { addTag(tagName, NO_COMMENT); - DrawableTagsManager.refreshTagsInAutopsy(); } }); } catch (InterruptedException | InvocationTargetException ex) { @@ -141,12 +139,11 @@ abstract class AddTagAction { SwingUtilities.invokeAndWait(() -> { GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); if (null != tagNameAndComment) { - if (Category.isCategoryTagName(tagNameAndComment.getTagName())) { + if (CategoryManager.isCategoryTagName(tagNameAndComment.getTagName())) { new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } else { new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } - DrawableTagsManager.refreshTagsInAutopsy(); } }); } catch (InterruptedException | InvocationTargetException ex) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 8918934a6e..067a5cf967 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -32,7 +31,6 @@ import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; @@ -41,7 +39,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -87,6 +84,10 @@ public class CategorizeAction extends AddTagAction { } } + public void enforceOneCat(TagName name, String string) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + /** * Instances of this class implement a context menu user interface for * selecting a category @@ -127,8 +128,8 @@ public class CategorizeAction extends AddTagAction { @Override public void run() { final GroupManager groupManager = controller.getGroupManager(); - final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); final CategoryManager categoryManager = controller.getCategoryManager(); + final DrawableTagsManager tagsManager = controller.getTagsManager(); try { DrawableFile file = controller.getFileFromId(fileID); //drawable db @@ -138,27 +139,27 @@ public class CategorizeAction extends AddTagAction { groupManager.removeFromGroup(new GroupKey(DrawableAttribute.CATEGORY, oldCat), fileID); //memory //remove old category tag if necessary - List allContentTags = sleuthKitCase.getContentTagsByContent(file); //tsk db + List allContentTags = tagsManager.getContentTagsByContent(file); //tsk db + //JMTODO: move this to CategoryManager for (ContentTag ct : allContentTags) { - if (Category.isCategoryTagName(ct.getName())) { - sleuthKitCase.deleteContentTag(ct); //tsk db - categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db + if (CategoryManager.isCategoryTagName(ct.getName())) { + tagsManager.deleteContentTag(ct); //tsk db +// categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db } } - categoryManager.incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db +// categoryManager.incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db if (tagName != categoryManager.getTagName(Category.ZERO)) { // no tags for cat-0 - controller.getTagsManager().addContentTag(file, tagName, comment); //tsk db + tagsManager.addContentTag(file, tagName, comment); //tsk db } - //make sure rest of ui hears category change. - groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui +// //make sure rest of ui hears category change. +// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error categorizing result", ex); JOptionPane.showMessageDialog(null, "Unable to categorize " + fileID + ".", "Categorizing Error", JOptionPane.ERROR_MESSAGE); } - DrawableTagsManager.refreshTagsInAutopsy(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 98fdc316ad..aab8a9c827 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.util.Collections; import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; @@ -26,14 +25,12 @@ import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -53,7 +50,6 @@ public class DeleteFollowUpTagAction extends Action { @Override protected Void doInBackground() throws Exception { - final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); final GroupManager groupManager = controller.getGroupManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); @@ -69,9 +65,8 @@ public class DeleteFollowUpTagAction extends Action { } } - DrawableTagsManager.refreshTagsInAutopsy(); //make sure rest of ui hears category change. - groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); +// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 00750c4ba9..8999fff2f1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -23,7 +23,6 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import javafx.scene.paint.Color; -import org.sleuthkit.datamodel.TagName; /** * Enum to represent the six categories in the DHs image categorization scheme. @@ -49,17 +48,6 @@ public enum Category { public static Category fromDisplayName(String displayName) { return nameMap.get(displayName); } - public static Category fromTagName(TagName tagName) { - return nameMap.get(tagName.getDisplayName()); - } - - public static boolean isCategoryTagName(TagName tName) { - return isCategoryName(tName.getDisplayName()); - } - - public static boolean isNotCategoryTagName(TagName tName) { - return isNotCategoryName(tName.getDisplayName()); - } public static boolean isCategoryName(String tName) { return nameMap.containsKey(tName); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java index 9896325e09..3868864737 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java @@ -30,6 +30,16 @@ import javax.annotation.concurrent.Immutable; public class CategoryChangeEvent { private final Collection fileIDs; + private final Category newCategory; + + public CategoryChangeEvent(Collection fileIDs, Category newCategory) { + this.fileIDs = fileIDs; + this.newCategory = newCategory; + } + + public Category getNewCategory() { + return newCategory; + } /** * @return the fileIDs of the files whose categories have changed @@ -37,8 +47,4 @@ public class CategoryChangeEvent { public Collection getFileIDs() { return Collections.unmodifiableCollection(fileIDs); } - - public CategoryChangeEvent(Collection fileIDs) { - this.fileIDs = fileIDs; - } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index f8b0e6beb1..b6a11d2b25 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -24,11 +24,17 @@ import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; /** * Provides a cached view of the number of files per category, and fires @@ -94,13 +100,13 @@ public class CategoryManager { this.db = db; categoryCounts.invalidateAll(); catTagNameMap.invalidateAll(); - fireChange(Collections.singleton(-1L)); + fireChange(Collections.emptyList(), null); } synchronized public void invalidateCaches() { categoryCounts.invalidateAll(); catTagNameMap.invalidateAll(); - fireChange(Collections.singleton(-1L)); + fireChange(Collections.emptyList(), null); } /** @@ -173,8 +179,8 @@ public class CategoryManager { * * @param fileIDs */ - public void fireChange(Collection fileIDs) { - categoryEventBus.post(new CategoryChangeEvent(fileIDs)); + public void fireChange(Collection fileIDs, Category newCategory) { + categoryEventBus.post(new CategoryChangeEvent(fileIDs, newCategory)); } /** @@ -204,4 +210,59 @@ public class CategoryManager { return catTagNameMap.getUnchecked(cat); } + + public static Category fromTagName(TagName tagName) { + return Category.fromDisplayName(tagName.getDisplayName()); + } + + public static boolean isCategoryTagName(TagName tName) { + return Category.isCategoryName(tName.getDisplayName()); + } + + public static boolean isNotCategoryTagName(TagName tName) { + return Category.isNotCategoryName(tName.getDisplayName()); + + } + + public void handleTagAdded(ContentTagAddedEvent event) { + ContentTag addedTag = event.getAddedTag(); + if (isCategoryTagName(addedTag.getName())) { + final DrawableTagsManager tagsManager = controller.getTagsManager(); + try { + //remove old category tag(s) if necessary + List allContentTags = tagsManager.getContentTagsByContent(addedTag.getContent()); + + for (ContentTag ct : allContentTags) { + if (ct.getId() != addedTag.getId() + && CategoryManager.isCategoryTagName(ct.getName())) { + try { + tagsManager.deleteContentTag(ct); + } catch (TskCoreException tskException) { + LOGGER.log(Level.SEVERE, "Failed to delete content tag. Unable to maintain categories in a consistent state.", tskException); + } + } + } + } catch (TskCoreException tskException) { + LOGGER.log(Level.SEVERE, "Failed to get content tags for content. Unable to maintain category in a consistent state.", tskException); + } + Category newCat = CategoryManager.fromTagName(addedTag.getName()); + if (newCat != Category.ZERO) { + incrementCategoryCount(newCat); + } + + fireChange(Collections.singleton(addedTag.getId()), newCat); + } + } + + public void handleTagDeleted(ContentTagDeletedEvent event) { + ContentTag deleted = event.getDeletedTag(); + if (isCategoryTagName(deleted.getName())) { + + Category deletedCat = CategoryManager.fromTagName(deleted.getName()); + if (deletedCat != Category.ZERO) { + decrementCategoryCount(deletedCat); + } + fireChange(Collections.singleton(deleted.getId()), null); + } + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 3890ca577a..79ea49f879 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -272,7 +272,7 @@ public abstract class DrawableFile extends AbstractFile private void updateCategory() { try { category.set(getSleuthkitCase().getContentTagsByContent(this).stream() - .map(Tag::getName).filter(Category::isCategoryTagName) + .map(Tag::getName).filter(CategoryManager::isCategoryTagName) .map(TagName::getDisplayName) .map(Category::fromDisplayName) .sorted().findFirst() //sort by severity and take the first diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 51a99bd5f7..733baf2813 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -60,12 +60,14 @@ import org.sleuthkit.autopsy.coreutils.LoggedTask; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; -import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -161,7 +163,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { Set> resultSet = new HashSet<>(); for (Comparable val : groupBy.getValue(file)) { if (groupBy == DrawableAttribute.TAGS) { - if (Category.isNotCategoryTagName((TagName) val)) { + if (CategoryManager.isNotCategoryTagName((TagName) val)) { resultSet.add(new GroupKey(groupBy, val)); } } else { @@ -282,6 +284,10 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { }); } } + } else { //group == null + // It may be that this was the last unanalyzed file in the group, so test + // whether the group is now fully analyzed. + popuplateIfAnalyzed(groupKey, null); } return group; @@ -360,7 +366,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { break; case TAGS: values = (List) controller.getTagsManager().getTagNamesInUse().stream() - .filter(Category::isNotCategoryTagName) + .filter(CategoryManager::isNotCategoryTagName) .collect(Collectors.toList()); break; case ANALYZED: @@ -528,14 +534,31 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } @Subscribe - public void handleAutopsyTagChange(TagsChangeEvent evt) { - if (groupBy == DrawableAttribute.TAGS - && evt.getFileIDs().size() == 1 - && evt.getFileIDs().contains(-1L)) { - regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); + public void handleTagAdded(ContentTagAddedEvent evt) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + final long fileID = evt.getAddedTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); + + } + + private void addFileToGroup(DrawableGroup g, final GroupKey groupKey, final long fileID) { + if (g == null) { + //if there wasn't already a group check if there should be one now + popuplateIfAnalyzed(groupKey, null); + } else { + //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. + g.addFile(fileID); } } + @Subscribe + public void handleTagDeleted(ContentTagDeletedEvent evt) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); + final long fileID = evt.getDeletedTag().getContent().getId(); + DrawableGroup g = removeFromGroup(groupKey, fileID); + } + @Override synchronized public void handleFileRemoved(FileUpdateEvent evt) { Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.REMOVE); @@ -545,13 +568,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { Set> groupsForFile = getGroupKeysForFileID(fileId); for (GroupKey gk : groupsForFile) { - DrawableGroup g = removeFromGroup(gk, fileId); - - if (g == null) { - // It may be that this was the last unanalyzed file in the group, so test - // whether the group is now fully analyzed. - popuplateIfAnalyzed(gk, null); - } + removeFromGroup(gk, fileId); } } } @@ -578,29 +595,21 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { //get grouping(s) this file would be in Set> groupsForFile = getGroupKeysForFileID(fileId); - for (GroupKey gk : groupsForFile) { DrawableGroup g = getGroupForKey(gk); - - if (g == null) { - //if there wasn't already a group check if there should be one now - popuplateIfAnalyzed(gk, null); - } else { - //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. - g.addFile(fileId); - } + addFileToGroup(g, gk, fileId); } } //we fire this event for all files so that the category counts get updated during initial db population - controller.getCategoryManager().fireChange(fileIDs); + controller.getCategoryManager().fireChange(fileIDs, null); // if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { // controller.getTagsManager().fireChange(fileIDs); // } } - private void popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { + private DrawableGroup popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { if (Objects.nonNull(task) && (task.isCancelled())) { /* if this method call is part of a ReGroupTask and that task is @@ -609,6 +618,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * this allows us to stop if a regroup task has been cancelled (e.g. * the user picked a different group by attribute, while the * current task was still running) */ + } else { // no task or un-cancelled task if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { /* for attributes other than path we can't be sure a group is @@ -639,12 +649,14 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } markGroupSeen(group, groupSeen); }); + return group; } } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); } } } + return null; } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 99d8671a63..9b442273d1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -12,8 +12,9 @@ import javafx.scene.layout.Region; import javafx.scene.paint.Color; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; @@ -68,7 +69,10 @@ public interface DrawableView { void handleCategoryChanged(CategoryChangeEvent evt); @Subscribe - void handleTagsChanged(TagsChangeEvent evt); + void handleTagAdded(ContentTagAddedEvent evt); + + @Subscribe + void handleTagDeleted(ContentTagDeletedEvent evt); ImageGalleryController getController(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 93026d688d..ea88d2dfbb 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -61,10 +61,11 @@ import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; -import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; @@ -378,16 +379,21 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override - synchronized public void handleTagsChanged(TagsChangeEvent evnt) { - if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { - updateFollowUpIcon(); - } + public void handleTagAdded(ContentTagAddedEvent evt) { + + updateFollowUpIcon(); + } + + @Subscribe + @Override + public void handleTagDeleted(ContentTagDeletedEvent evt) { + updateFollowUpIcon(); } @Subscribe @Override synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { - if (evt.getFileIDs().contains(getFileID()) || evt.getFileIDs().contains(-1L)) { + if (fileID != null && evt.getFileIDs().contains(getFileID())) { updateCategoryBorder(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index 4f4cace550..0681d29eb9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -44,8 +44,9 @@ import javafx.scene.text.Text; import javafx.util.Pair; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -225,16 +226,23 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @Subscribe @Override public void handleCategoryChanged(CategoryChangeEvent evt) { - if (getFile() != null && (evt.getFileIDs().contains(-1L) || evt.getFileIDs().contains(getFileID()))) { + if (getFile() != null && evt.getFileIDs().contains(getFileID())) { updateUI(); } } @Override - @Subscribe - public void handleTagsChanged(TagsChangeEvent evt) { - if (getFile() != null && (evt.getFileIDs().contains(-1L) || evt.getFileIDs().contains(getFileID()))) { + public void handleTagAdded(ContentTagAddedEvent evt) { + if (getFile() != null && evt.getAddedTag().getContent().getId() == getFileID()) { updateUI(); } } + + @Override + public void handleTagDeleted(ContentTagDeletedEvent evt) { + if (getFile() != null && evt.getDeletedTag().getContent().getId() == getFileID()) { + updateUI(); + } + } + } From 3337e6a880f36b453efe1ae1093442e29c2c2f15 Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 17:20:35 -0400 Subject: [PATCH 067/198] remove uneeded notification code; let event handlers do it all. optionalize DrawableView --- Core/nbproject/project.xml | 1 + .../actions/AddDrawableTagAction.java | 3 - .../actions/CategorizeAction.java | 33 +- .../actions/DeleteFollowUpTagAction.java | 11 +- .../datamodel/CategoryManager.java | 3 +- .../imagegallery/grouping/GroupManager.java | 26 +- .../imagegallery/gui/DrawableTile.java | 16 +- .../imagegallery/gui/DrawableView.java | 13 +- .../imagegallery/gui/DrawableViewBase.java | 301 ++++++++++-------- .../imagegallery/gui/MetaDataPane.java | 114 ++++--- .../imagegallery/gui/SlideShowView.java | 81 +++-- 11 files changed, 341 insertions(+), 261 deletions(-) diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index ac5f32a1ac..463e1c1903 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -192,6 +192,7 @@ org.sleuthkit.autopsy.coreutils org.sleuthkit.autopsy.datamodel org.sleuthkit.autopsy.directorytree + org.sleuthkit.autopsy.events org.sleuthkit.autopsy.externalresults org.sleuthkit.autopsy.filesearch org.sleuthkit.autopsy.ingest diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index be9343f4de..3c115d9134 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -82,9 +82,6 @@ public class AddDrawableTagAction extends AddTagAction { LOGGER.log(Level.SEVERE, "Error tagging result", ex); JOptionPane.showMessageDialog(null, "Unable to tag " + fileID + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); } - -// //make sure rest of ui hears category change. -// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 067a5cf967..afe2b3bb5d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.logging.Level; import javafx.event.ActionEvent; @@ -34,11 +33,7 @@ import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -127,33 +122,25 @@ public class CategorizeAction extends AddTagAction { @Override public void run() { - final GroupManager groupManager = controller.getGroupManager(); final CategoryManager categoryManager = controller.getCategoryManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); try { DrawableFile file = controller.getFileFromId(fileID); //drawable db - Category oldCat = file.getCategory(); - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.CATEGORY, oldCat), fileID); //memory - - //remove old category tag if necessary - List allContentTags = tagsManager.getContentTagsByContent(file); //tsk db - - //JMTODO: move this to CategoryManager - for (ContentTag ct : allContentTags) { - if (CategoryManager.isCategoryTagName(ct.getName())) { - tagsManager.deleteContentTag(ct); //tsk db -// categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db - } - } -// categoryManager.incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db if (tagName != categoryManager.getTagName(Category.ZERO)) { // no tags for cat-0 tagsManager.addContentTag(file, tagName, comment); //tsk db + } else { + tagsManager.getContentTagsByContent(file).stream() + .filter(tag -> CategoryManager.isCategoryTagName(tag.getName())) + .forEach((ct) -> { + try { + tagsManager.deleteContentTag(ct); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error removing old categories result", ex); + } + }); } -// //make sure rest of ui hears category change. -// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error categorizing result", ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index aab8a9c827..74082fcd1c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -26,10 +26,7 @@ import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -50,23 +47,17 @@ public class DeleteFollowUpTagAction extends Action { @Override protected Void doInBackground() throws Exception { - final GroupManager groupManager = controller.getGroupManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); try { final TagName followUpTagName = tagsManager.getFollowUpTagName(); - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); - + List contentTagsByContent = tagsManager.getContentTagsByContent(file); for (ContentTag ct : contentTagsByContent) { if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { tagsManager.deleteContentTag(ct); } } - - //make sure rest of ui hears category change. -// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index b6a11d2b25..466278f588 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -224,6 +224,7 @@ public class CategoryManager { } + @Subscribe public void handleTagAdded(ContentTagAddedEvent event) { ContentTag addedTag = event.getAddedTag(); if (isCategoryTagName(addedTag.getName())) { @@ -253,7 +254,7 @@ public class CategoryManager { fireChange(Collections.singleton(addedTag.getId()), newCat); } } - + @Subscribe public void handleTagDeleted(ContentTagDeletedEvent event) { ContentTag deleted = event.getDeletedTag(); if (isCategoryTagName(deleted.getName())) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 733baf2813..9ac899742c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -279,8 +279,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { if (groupKey.getAttribute() != DrawableAttribute.CATEGORY) { if (group.fileIds().isEmpty()) { Platform.runLater(() -> { - analyzedGroups.remove(group); - unSeenGroups.remove(group); + if (analyzedGroups.contains(group)) { + analyzedGroups.remove(group); + } + if (unSeenGroups.contains(group)) { + unSeenGroups.remove(group); + } }); } } @@ -535,10 +539,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); - final long fileID = evt.getAddedTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); + if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + final long fileID = evt.getAddedTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); + } } @@ -554,9 +560,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagDeleted(ContentTagDeletedEvent evt) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); - final long fileID = evt.getDeletedTag().getContent().getId(); - DrawableGroup g = removeFromGroup(groupKey, fileID); + if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); + final long fileID = evt.getDeletedTag().getContent().getId(); + DrawableGroup g = removeFromGroup(groupKey, fileID); + } } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java index 75332ba158..96f05dd9c1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java @@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableViewBase.globalSelectionModel; +import org.sleuthkit.datamodel.AbstractContent; /** * GUI component that represents a single image as a tile with an icon, a label, @@ -109,15 +110,20 @@ public class DrawableTile extends DrawableViewBase { @Override protected Runnable getContentUpdateRunnable() { - Image image = getFile().getThumbnail(); + if (getFile().isPresent()) { + Image image = getFile().get().getThumbnail(); - return () -> { - imageView.setImage(image); - }; + return () -> { + imageView.setImage(image); + }; + } else { + return () -> { //no-op + }; + } } @Override protected String getTextForLabel() { - return getFile().getName(); + return getFile().map(AbstractContent::getName).orElse(""); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 9b442273d1..e4e6faf1de 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -1,6 +1,8 @@ package org.sleuthkit.autopsy.imagegallery.gui; import com.google.common.eventbus.Subscribe; +import java.util.Collection; +import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; import javafx.scene.layout.Border; @@ -51,11 +53,11 @@ public interface DrawableView { Region getCategoryBorderRegion(); - DrawableFile getFile(); + Optional> getFile(); void setFile(final Long fileID); - Long getFileID(); + Optional getFileID(); /** * update the visual representation of the category of the assigned file. @@ -78,7 +80,10 @@ public interface DrawableView { default boolean hasHashHit() { try { - return getFile().getHashHitSetNames().isEmpty() == false; + return getFile().map(DrawableFile::getHashHitSetNames) + .map((Collection t) -> t.isEmpty() == false) + .orElse(false); + } catch (NullPointerException ex) { // I think this happens when we're in the process of removing images from the view while // also trying to update it? @@ -113,7 +118,7 @@ public interface DrawableView { @ThreadConfined(type = ThreadConfined.ThreadType.ANY) default Category updateCategoryBorder() { if (getFile() != null) { - final Category category = getFile().getCategory(); + final Category category = getFile().map(DrawableFile::getCategory).orElse(Category.ZERO); final Border border = hasHashHit() && (category == Category.ZERO) ? HASH_BORDER : getCategoryBorder(category); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index ea88d2dfbb..a1ee32a108 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -23,6 +23,8 @@ import com.google.common.eventbus.Subscribe; import java.util.ArrayList; import java.util.Collection; import java.util.Objects; +import static java.util.Objects.nonNull; +import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; import javafx.beans.Observable; @@ -130,9 +132,33 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie static private ContextMenu contextMenu; - private DrawableFile file; + volatile private Optional> fileOpt = Optional.empty(); - private Long fileID; + volatile private Optional fileIDOpt = Optional.empty(); + + @Override + public Optional getFileID() { + return fileIDOpt; + } + + @Override + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + try { + fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); + } catch (TskCoreException ex) { + Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); + fileOpt = Optional.empty(); + } + return fileOpt; + } + } else { + return Optional.empty(); + } + } /** * the groupPane this {@link DrawableViewBase} is embedded in @@ -158,43 +184,44 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Override public void handle(MouseEvent t) { + getFile().ifPresent(file -> { + final long fileID = file.getId(); + switch (t.getButton()) { + case PRIMARY: + if (t.getClickCount() == 1) { + if (t.isControlDown()) { - switch (t.getButton()) { - case PRIMARY: - if (t.getClickCount() == 1) { - if (t.isControlDown()) { - globalSelectionModel.toggleSelection(fileID); - } else { - groupPane.makeSelection(t.isShiftDown(), fileID); + globalSelectionModel.toggleSelection(fileID); + } else { + groupPane.makeSelection(t.isShiftDown(), fileID); + } + } else if (t.getClickCount() > 1) { + groupPane.activateSlideShowViewer(fileID); } - } else if (t.getClickCount() > 1) { - groupPane.activateSlideShowViewer(fileID); - } - break; - case SECONDARY: - - if (t.getClickCount() == 1) { - if (globalSelectionModel.isSelected(fileID) == false) { - groupPane.makeSelection(false, fileID); + break; + case SECONDARY: + if (t.getClickCount() == 1) { + if (globalSelectionModel.isSelected(fileID) == false) { + groupPane.makeSelection(false, fileID); + } } - } + if (contextMenu != null) { + contextMenu.hide(); + } + final ContextMenu groupContextMenu = groupPane.getContextMenu(); + if (groupContextMenu != null) { + groupContextMenu.hide(); + } + contextMenu = buildContextMenu(file); + contextMenu.show(DrawableViewBase.this, t.getScreenX(), t.getScreenY()); + break; + } + }); - if (contextMenu != null) { - contextMenu.hide(); - } - final ContextMenu groupContextMenu = groupPane.getContextMenu(); - if (groupContextMenu != null) { - groupContextMenu.hide(); - } - contextMenu = buildContextMenu(); - contextMenu.show(DrawableViewBase.this, t.getScreenX(), t.getScreenY()); - - break; - } t.consume(); } - private ContextMenu buildContextMenu() { + private ContextMenu buildContextMenu(DrawableFile file) { final ArrayList menuItems = new ArrayList<>(); menuItems.add(new CategorizeAction(controller).getPopupMenu()); @@ -213,13 +240,13 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie MenuItem contentViewer = new MenuItem("Show Content Viewer"); contentViewer.setOnAction((ActionEvent t) -> { SwingUtilities.invokeLater(() -> { - new NewWindowViewAction("Show Content Viewer", new FileNode(getFile().getAbstractFile())).actionPerformed(null); + new NewWindowViewAction("Show Content Viewer", new FileNode(file.getAbstractFile())).actionPerformed(null); }); }); menuItems.add(contentViewer); MenuItem externalViewer = new MenuItem("Open in External Viewer"); - final ExternalViewerAction externalViewerAction = new ExternalViewerAction("Open in External Viewer", new FileNode(getFile().getAbstractFile())); + final ExternalViewerAction externalViewerAction = new ExternalViewerAction("Open in External Viewer", new FileNode(file.getAbstractFile())); externalViewer.setDisable(externalViewerAction.isEnabled() == false); externalViewer.setOnAction((ActionEvent t) -> { @@ -259,116 +286,106 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @SuppressWarnings("deprecation") protected void initialize() { followUpToggle.setOnAction((ActionEvent event) -> { - if (followUpToggle.isSelected() == true) { - try { - final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); - globalSelectionModel.clearAndSelect(fileID); - new AddDrawableTagAction(controller).addTag(followUpTagName, ""); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); + getFile().ifPresent(file -> { + if (followUpToggle.isSelected() == true) { + try { + final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); + globalSelectionModel.clearAndSelect(file.getId()); + new AddDrawableTagAction(controller).addTag(followUpTagName, ""); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); + } + } else { + new DeleteFollowUpTagAction(controller, file).handle(event); } - } else { - new DeleteFollowUpTagAction(controller, file).handle(event); - } + }); }); } - @Override - public DrawableFile getFile() { - if (fileID != null) { - if (file == null || file.getId() != fileID) { - try { - file = ImageGalleryController.getDefault().getFileFromId(fileID); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileID, ex); - file = null; - } - } - return file; - } else { - return null; - } - } - - protected boolean hasFollowUp() throws TskCoreException { - String followUpTagName = getController().getTagsManager().getFollowUpTagName().getDisplayName(); - Collection tagNames = DrawableAttribute.TAGS.getValue(getFile()); - return tagNames.stream().anyMatch((tn) -> tn.getDisplayName().equals(followUpTagName)); - } - - @Override - synchronized public Long getFileID() { - return fileID; - } - - synchronized protected void updateFollowUpIcon() { - if (file != null) { + protected boolean hasFollowUp() { + if (getFile().isPresent()) { try { - boolean hasFollowUp = hasFollowUp(); - Platform.runLater(() -> { - followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray); - followUpToggle.setSelected(hasFollowUp); - }); + TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); + Collection tagNames = DrawableAttribute.TAGS.getValue(getFile().get()); + return tagNames.stream().anyMatch((tn) -> tn.equals(followUpTagName)); } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + LOGGER.log(Level.WARNING, "failed to get follow up tag name ", ex); + return true; } + } else { + return false; } } @Override - synchronized public void setFile(final Long fileID) { - if (Objects.equals(fileID, this.fileID) == false) { - this.fileID = fileID; - disposeContent(); - - if (this.fileID == null || Case.isCaseOpen() == false) { - if (registered == true) { - getController().getCategoryManager().unregisterListener(this); - getController().getTagsManager().unregisterListener(this); - registered = false; - } - file = null; - Platform.runLater(() -> { - clearContent(); - }); - } else { - if (registered == false) { - getController().getCategoryManager().registerListener(this); - getController().getTagsManager().registerListener(this); - registered = true; - } - file = null; - getFile(); - updateSelectionState(); - updateCategoryBorder(); - updateFollowUpIcon(); - updateUI(); - Platform.runLater(getContentUpdateRunnable()); + public void setFile(final Long newFileID) { + if (fileIDOpt.isPresent()) { + if (Objects.equals(newFileID, fileIDOpt.get()) == false) { + setFileHelper(newFileID); } + } else { + if (nonNull(newFileID)) { + setFileHelper(newFileID); + } + } + } + + private void setFileHelper(final Long newFileID) { + fileIDOpt = Optional.ofNullable(newFileID); + disposeContent(); + + if (fileIDOpt.isPresent() == false || Case.isCaseOpen() == false) { + if (registered == true) { + getController().getCategoryManager().unregisterListener(this); + getController().getTagsManager().unregisterListener(this); + registered = false; + } + fileOpt = Optional.empty(); + Platform.runLater(() -> { + clearContent(); + }); + } else { + if (registered == false) { + getController().getCategoryManager().registerListener(this); + getController().getTagsManager().registerListener(this); + registered = true; + } + fileOpt = Optional.empty(); + + updateSelectionState(); + updateCategoryBorder(); + updateFollowUpIcon(); + updateUI(); + Platform.runLater(getContentUpdateRunnable()); } } private void updateUI() { - final boolean isVideo = getFile().isVideo(); - final boolean hasHashSetHits = hasHashHit(); - final String text = getTextForLabel(); + getFile().ifPresent(file -> { + final boolean isVideo = file.isVideo(); + final boolean hasHashSetHits = hasHashHit(); + final String text = getTextForLabel(); - Platform.runLater(() -> { - fileTypeImageView.setImage(isVideo ? videoIcon : null); - hashHitImageView.setImage(hasHashSetHits ? hashHitIcon : null); - nameLabel.setText(text); - nameLabel.setTooltip(new Tooltip(text)); + Platform.runLater(() -> { + fileTypeImageView.setImage(isVideo ? videoIcon : null); + hashHitImageView.setImage(hasHashSetHits ? hashHitIcon : null); + nameLabel.setText(text); + nameLabel.setTooltip(new Tooltip(text)); + }); }); + } /** * update the visual representation of the selection state of this * DrawableView */ - synchronized protected void updateSelectionState() { - final boolean selected = globalSelectionModel.isSelected(getFileID()); - Platform.runLater(() -> { - setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER); + protected void updateSelectionState() { + getFile().ifPresent(file -> { + final boolean selected = globalSelectionModel.isSelected(file.getId()); + Platform.runLater(() -> { + setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER); + }); }); } @@ -380,22 +397,54 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { + fileIDOpt.ifPresent(fileID -> { + try { + if (fileID == evt.getAddedTag().getContent().getId() + && evt.getAddedTag().getName() == getController().getTagsManager().getFollowUpTagName()) { - updateFollowUpIcon(); + Platform.runLater(() -> { + followUpImageView.setImage(followUpIcon); + followUpToggle.setSelected(true); + }); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + } + }); } @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - updateFollowUpIcon(); + + fileIDOpt.ifPresent(fileID -> { + try { + if (fileID == evt.getDeletedTag().getContent().getId() + && evt.getDeletedTag().getName() == controller.getTagsManager().getFollowUpTagName()) { + updateFollowUpIcon(); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + } + }); + } + + private void updateFollowUpIcon() { + boolean hasFollowUp = hasFollowUp(); + Platform.runLater(() -> { + followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray); + followUpToggle.setSelected(hasFollowUp); + }); } @Subscribe @Override - synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { - if (fileID != null && evt.getFileIDs().contains(getFileID())) { - updateCategoryBorder(); - } + public void handleCategoryChanged(CategoryChangeEvent evt) { + fileIDOpt.ifPresent(fileID -> { + if (evt.getFileIDs().contains(fileID)) { + updateCategoryBorder(); + } + }); } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index 0681d29eb9..87bd64491f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -22,6 +22,9 @@ import com.google.common.eventbus.Subscribe; import java.io.IOException; import java.util.Arrays; import java.util.Collection; +import java.util.Objects; +import static java.util.Objects.nonNull; +import java.util.Optional; import java.util.logging.Level; import java.util.stream.Collectors; import javafx.application.Platform; @@ -68,8 +71,6 @@ public class MetaDataPane extends AnchorPane implements DrawableView { return controller; } - private Long fileID; - @FXML private ImageView imageView; @@ -85,13 +86,6 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @FXML private BorderPane imageBorder; - private DrawableFile file; - - @Override - public Long getFileID() { - return fileID; - } - @FXML @SuppressWarnings("unchecked") void initialize() { @@ -152,29 +146,52 @@ public class MetaDataPane extends AnchorPane implements DrawableView { }); } + volatile private Optional> fileOpt = Optional.empty(); + + volatile private Optional fileIDOpt = Optional.empty(); + @Override - public DrawableFile getFile() { - if (fileID != null) { - if (file == null || file.getId() != fileID) { - try { - file = controller.getFileFromId(fileID); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileID, ex); - return null; - } - } - } else { - return null; - } - return file; + public Optional getFileID() { + return fileIDOpt; } @Override - public void setFile(Long fileID) { - this.fileID = fileID; + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + try { + fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); + } catch (TskCoreException ex) { + Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); + fileOpt = Optional.empty(); + } + return fileOpt; + } + } else { + return Optional.empty(); + } + } - if (fileID == null) { + @Override + public void setFile(Long newFileID) { + if (fileIDOpt.isPresent()) { + if (Objects.equals(newFileID, fileIDOpt.get()) == false) { + setFileHelper(newFileID); + } + } else { + if (nonNull(newFileID)) { + setFileHelper(newFileID); + } + } + setFileHelper(newFileID); + } + + private void setFileHelper(Long newFileID) { + fileIDOpt = Optional.of(newFileID); + if (newFileID == null) { Platform.runLater(() -> { imageView.setImage(null); tableView.getItems().clear(); @@ -182,12 +199,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { }); } else { - try { - file = controller.getFileFromId(fileID); - updateUI(); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Failed to get drawable file from ID", ex); - } + updateUI(); } } @@ -206,15 +218,18 @@ public class MetaDataPane extends AnchorPane implements DrawableView { } public void updateUI() { - final Image icon = getFile().getThumbnail(); - final ObservableList, ? extends Object>> attributesList = getFile().getAttributesList(); + getFile().ifPresent(file -> { + final Image icon = file.getThumbnail(); + final ObservableList, ? extends Object>> attributesList = file.getAttributesList(); - Platform.runLater(() -> { - imageView.setImage(icon); - tableView.getItems().setAll(attributesList); + Platform.runLater(() -> { + imageView.setImage(icon); + tableView.getItems().setAll(attributesList); + }); + + updateCategoryBorder(); }); - updateCategoryBorder(); } @Override @@ -226,23 +241,28 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @Subscribe @Override public void handleCategoryChanged(CategoryChangeEvent evt) { - if (getFile() != null && evt.getFileIDs().contains(getFileID())) { - updateUI(); - } + getFileID().ifPresent(fileID -> { + if (evt.getFileIDs().contains(fileID)) { + updateUI(); + } + }); } @Override public void handleTagAdded(ContentTagAddedEvent evt) { - if (getFile() != null && evt.getAddedTag().getContent().getId() == getFileID()) { - updateUI(); - } + handleTagChanged(evt.getAddedTag().getContent().getId()); } @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - if (getFile() != null && evt.getDeletedTag().getContent().getId() == getFileID()) { - updateUI(); - } + handleTagChanged(evt.getDeletedTag().getContent().getId()); } + private void handleTagChanged(Long tagFileID) { + getFileID().ifPresent(fileID -> { + if (Objects.equals(tagFileID, fileID)) { + updateUI(); + } + }); + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index 7977eb0219..ab74554b39 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.imagegallery.gui; import java.util.ArrayList; +import java.util.function.Function; import java.util.logging.Level; import javafx.application.Platform; import javafx.beans.Observable; @@ -48,14 +49,15 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.ImageFile; import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile; +import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.CAT_BORDER_WIDTH; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.HASH_BORDER; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.getCategoryBorder; import org.sleuthkit.datamodel.TagName; @@ -235,9 +237,9 @@ public class SlideShowView extends DrawableViewBase { @Override synchronized public void setFile(final Long fileID) { super.setFile(fileID); - if (this.getFileID() != null) { - getGroupPane().makeSelection(false, this.getFileID()); - } + getFileID().ifPresent((Long id) -> { + getGroupPane().makeSelection(false, id); + }); } @Override @@ -254,24 +256,33 @@ public class SlideShowView extends DrawableViewBase { @Override protected Runnable getContentUpdateRunnable() { - if (getFile().isVideo()) { - return () -> { - imageBorder.setCenter(MediaControl.create((VideoFile) getFile())); - }; - } else { - ImageView imageView = new ImageView(((ImageFile) getFile()).getFullSizeImage()); - imageView.setPreserveRatio(true); - imageView.fitWidthProperty().bind(imageBorder.widthProperty().subtract(CAT_BORDER_WIDTH * 2)); - imageView.fitHeightProperty().bind(this.heightProperty().subtract(CAT_BORDER_WIDTH * 4).subtract(footer.heightProperty()).subtract(toolBar.heightProperty())); - return () -> { - imageBorder.setCenter(imageView); - }; - } + + return getFile().map(new Function, Runnable>() { + + @Override + public Runnable apply(DrawableFile file) { + + if (file.isVideo()) { + return () -> { + imageBorder.setCenter(MediaControl.create((VideoFile) file)); + }; + } else { + ImageView imageView = new ImageView(((ImageFile) file).getFullSizeImage()); + imageView.setPreserveRatio(true); + imageView.fitWidthProperty().bind(imageBorder.widthProperty().subtract(CAT_BORDER_WIDTH * 2)); + imageView.fitHeightProperty().bind(heightProperty().subtract(CAT_BORDER_WIDTH * 4).subtract(footer.heightProperty()).subtract(toolBar.heightProperty())); + return () -> { + imageBorder.setCenter(imageView); + }; + } + } + }).orElse(() -> { + }); } @Override protected String getTextForLabel() { - return getFile().getName() + " " + getSupplementalText(); + return getFile().map(file -> file.getName() + " " + getSupplementalText()).orElse(""); } @ThreadConfined(type = ThreadType.JFX) @@ -302,18 +313,19 @@ public class SlideShowView extends DrawableViewBase { @Override @ThreadConfined(type = ThreadType.ANY) public Category updateCategoryBorder() { - final Category category = getFile().getCategory(); - final Border border = hasHashHit() && (category == Category.ZERO) - ? HASH_BORDER - : getCategoryBorder(category); - ToggleButton toggleForCategory = getToggleForCategory(category); + return getFile().map(file -> { + final Category category = file.getCategory(); + final Border border1 = hasHashHit() && (category == Category.ZERO) + ? HASH_BORDER + : getCategoryBorder(category); + ToggleButton toggleForCategory = getToggleForCategory(category); + Platform.runLater(() -> { + getCategoryBorderRegion().setBorder(border1); + toggleForCategory.setSelected(true); + }); + return category; + }).orElse(Category.ZERO); - Platform.runLater(() -> { - getCategoryBorderRegion().setBorder(border); - toggleForCategory.setSelected(true); - }); - - return category; } private ToggleButton getToggleForCategory(Category category) { @@ -345,10 +357,13 @@ public class SlideShowView extends DrawableViewBase { @Override public void changed(ObservableValue ov, Boolean t, Boolean t1) { - if (t1) { - FileIDSelectionModel.getInstance().clearAndSelect(getFileID()); - new CategorizeAction(getController()).addTag(getController().getTagsManager().getTagName(cat), ""); - } + getFileID().ifPresent(fileID -> { + if (t1) { + FileIDSelectionModel.getInstance().clearAndSelect(fileID); + new CategorizeAction(getController()).addTag(getController().getTagsManager().getTagName(cat), ""); + } + }); + } } } From aad652a7a78ce6f57bc51996ff1c5a00e8cdf091 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Mon, 22 Jun 2015 13:27:33 -0400 Subject: [PATCH 068/198] Unused fields removed. Potential NPE checked in SevenZipExtractor --- .../embeddedfileextractor/SevenZipExtractor.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 1dc6bbb5a4..12e184c961 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -311,7 +311,6 @@ class SevenZipExtractor { NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ArchiveExtractor.moduleName")); int processedItems = 0; - String compressMethod = null; boolean progressStarted = false; try { stream = new SevenZipContentReadStream(new ReadContentInputStream(archiveFile)); @@ -402,10 +401,6 @@ class SevenZipExtractor { //update progress bar progress.progress(archiveFile.getName() + ": " + fileName, processedItems); - if (compressMethod == null) { - compressMethod = item.getMethod(); - } - final boolean isEncrypted = item.isEncrypted(); final boolean isDir = item.isFolder(); @@ -417,7 +412,13 @@ class SevenZipExtractor { fullEncryption = false; } - final long size = item.getSize(); + final Long size = item.getSize(); + if (size == null) { + // If the size property cannot be determined, out-of-disk-space + // situations cannot be ascertained. + // Hence skip this file. + continue; + } //check if unpacking this file will result in out of disk space //this is additional to zip bomb prevention mechanism From d19dbbeaba4781910caef03699d530ad4c62031b Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 13:33:07 -0400 Subject: [PATCH 069/198] fix bugs updating tags/categpries in slideshowview and metadata pane make new abstract base calss DrawableUIBase and move fileid and file object access to it. --- .../actions/DeleteFollowUpTagAction.java | 2 - .../datamodel/CategoryManager.java | 4 +- .../imagegallery/gui/DrawableTile.java | 7 +- ...bleViewBase.java => DrawableTileBase.java} | 121 +++++------------- .../imagegallery/gui/DrawableUIBase.java | 97 ++++++++++++++ .../imagegallery/gui/DrawableView.java | 18 +-- .../imagegallery/gui/MetaDataPane.java | 70 ++-------- .../imagegallery/gui/SlideShowView.java | 23 ++-- 8 files changed, 161 insertions(+), 181 deletions(-) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{DrawableViewBase.java => DrawableTileBase.java} (79%) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 74082fcd1c..934a3fb258 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -37,11 +37,9 @@ import org.sleuthkit.datamodel.TskCoreException; public class DeleteFollowUpTagAction extends Action { private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTagAction.class.getName()); - private final long fileID; public DeleteFollowUpTagAction(final ImageGalleryController controller, final DrawableFile file) { super("Delete Follow Up Tag"); - this.fileID = file.getId(); setEventHandler((ActionEvent t) -> { new SwingWorker() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 466278f588..4d2591aa1e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -251,7 +251,7 @@ public class CategoryManager { incrementCategoryCount(newCat); } - fireChange(Collections.singleton(addedTag.getId()), newCat); + fireChange(Collections.singleton(addedTag.getContent().getId()), newCat); } } @Subscribe @@ -263,7 +263,7 @@ public class CategoryManager { if (deletedCat != Category.ZERO) { decrementCategoryCount(deletedCat); } - fireChange(Collections.singleton(deleted.getId()), null); + fireChange(Collections.singleton(deleted.getContent().getId()), null); } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java index 96f05dd9c1..86a0b2ddee 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java @@ -32,7 +32,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableViewBase.globalSelectionModel; +import static org.sleuthkit.autopsy.imagegallery.gui.DrawableTileBase.globalSelectionModel; import org.sleuthkit.datamodel.AbstractContent; /** @@ -43,7 +43,7 @@ import org.sleuthkit.datamodel.AbstractContent; * * TODO: refactor this to extend from {@link Control}? -jm */ -public class DrawableTile extends DrawableViewBase { +public class DrawableTile extends DrawableTileBase { private static final DropShadow LAST_SELECTED_EFFECT = new DropShadow(10, Color.BLUE); @@ -67,7 +67,6 @@ public class DrawableTile extends DrawableViewBase { assert imageBorder != null : "fx:id=\"imageAnchor\" was not injected: check your FXML file 'DrawableTile.fxml'."; assert imageView != null : "fx:id=\"imageView\" was not injected: check your FXML file 'DrawableTile.fxml'."; assert nameLabel != null : "fx:id=\"nameLabel\" was not injected: check your FXML file 'DrawableTile.fxml'."; - //set up properties and binding setCache(true); setCacheHint(CacheHint.SPEED); @@ -87,9 +86,11 @@ public class DrawableTile extends DrawableViewBase { public DrawableTile(GroupPane gp) { super(gp); + FXMLConstructor.construct(this, "DrawableTile.fxml"); } + @Override @ThreadConfined(type = ThreadType.JFX) protected void clearContent() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java similarity index 79% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java index a1ee32a108..80c73b1ae9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java @@ -22,8 +22,6 @@ package org.sleuthkit.autopsy.imagegallery.gui; import com.google.common.eventbus.Subscribe; import java.util.ArrayList; import java.util.Collection; -import java.util.Objects; -import static java.util.Objects.nonNull; import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; @@ -39,7 +37,6 @@ import javafx.scene.control.Tooltip; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; -import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Border; import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderStroke; @@ -66,13 +63,11 @@ import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.TagName; @@ -84,9 +79,9 @@ import org.sleuthkit.datamodel.TskCoreException; * of {@link DrawableView}s should implement the interface directly * */ -public abstract class DrawableViewBase extends AnchorPane implements DrawableView { +public abstract class DrawableTileBase extends DrawableUIBase { - private static final Logger LOGGER = Logger.getLogger(DrawableViewBase.class.getName()); + private static final Logger LOGGER = Logger.getLogger(DrawableTileBase.class.getName()); private static final Border UNSELECTED_BORDER = new Border(new BorderStroke(Color.GRAY, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3))); @@ -99,6 +94,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie protected static final Image followUpGray = new Image("org/sleuthkit/autopsy/imagegallery/images/flag_gray.png"); protected static final FileIDSelectionModel globalSelectionModel = FileIDSelectionModel.getInstance(); + private static ContextMenu contextMenu; /** * displays the icon representing video files @@ -130,50 +126,16 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @FXML protected BorderPane imageBorder; - static private ContextMenu contextMenu; - - volatile private Optional> fileOpt = Optional.empty(); - - volatile private Optional fileIDOpt = Optional.empty(); - - @Override - public Optional getFileID() { - return fileIDOpt; - } - - @Override - public Optional> getFile() { - if (fileIDOpt.isPresent()) { - if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { - return fileOpt; - } else { - try { - fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); - } catch (TskCoreException ex) { - Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); - fileOpt = Optional.empty(); - } - return fileOpt; - } - } else { - return Optional.empty(); - } - } - /** - * the groupPane this {@link DrawableViewBase} is embedded in + * the groupPane this {@link DrawableTileBase} is embedded in */ final private GroupPane groupPane; - private boolean registered = false; - private final ImageGalleryController controller; + volatile private boolean registered = false; - GroupPane getGroupPane() { - return groupPane; - } + protected DrawableTileBase(GroupPane groupPane) { + super(groupPane.getController()); - protected DrawableViewBase(GroupPane groupPane) { this.groupPane = groupPane; - this.controller = groupPane.getController(); globalSelectionModel.getSelected().addListener((Observable observable) -> { updateSelectionState(); }); @@ -213,7 +175,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie groupContextMenu.hide(); } contextMenu = buildContextMenu(file); - contextMenu.show(DrawableViewBase.this, t.getScreenX(), t.getScreenY()); + contextMenu.show(DrawableTileBase.this, t.getScreenX(), t.getScreenY()); break; } }); @@ -224,9 +186,9 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie private ContextMenu buildContextMenu(DrawableFile file) { final ArrayList menuItems = new ArrayList<>(); - menuItems.add(new CategorizeAction(controller).getPopupMenu()); + menuItems.add(new CategorizeAction(getController()).getPopupMenu()); - menuItems.add(new AddDrawableTagAction(controller).getPopupMenu()); + menuItems.add(new AddDrawableTagAction(getController()).getPopupMenu()); final MenuItem extractMenuItem = new MenuItem("Extract File(s)"); extractMenuItem.setOnAction((ActionEvent t) -> { @@ -274,6 +236,10 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie }); } + GroupPane getGroupPane() { + return groupPane; + } + @ThreadConfined(type = ThreadType.UI) protected abstract void clearContent(); @@ -283,31 +249,29 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie protected abstract String getTextForLabel(); - @SuppressWarnings("deprecation") protected void initialize() { followUpToggle.setOnAction((ActionEvent event) -> { getFile().ifPresent(file -> { if (followUpToggle.isSelected() == true) { try { - final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); globalSelectionModel.clearAndSelect(file.getId()); - new AddDrawableTagAction(controller).addTag(followUpTagName, ""); + new AddDrawableTagAction(getController()).addTag(getController().getTagsManager().getFollowUpTagName(), ""); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); } } else { - new DeleteFollowUpTagAction(controller, file).handle(event); + new DeleteFollowUpTagAction(getController(), file).handle(event); } }); }); } protected boolean hasFollowUp() { - if (getFile().isPresent()) { + if (getFileID().isPresent()) { try { TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); - Collection tagNames = DrawableAttribute.TAGS.getValue(getFile().get()); - return tagNames.stream().anyMatch((tn) -> tn.equals(followUpTagName)); + return DrawableAttribute.TAGS.getValue(getFile().get()).stream() + .anyMatch(followUpTagName::equals); } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "failed to get follow up tag name ", ex); return true; @@ -318,29 +282,17 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie } @Override - public void setFile(final Long newFileID) { - if (fileIDOpt.isPresent()) { - if (Objects.equals(newFileID, fileIDOpt.get()) == false) { - setFileHelper(newFileID); - } - } else { - if (nonNull(newFileID)) { - setFileHelper(newFileID); - } - } - } - - private void setFileHelper(final Long newFileID) { - fileIDOpt = Optional.ofNullable(newFileID); + protected void setFileHelper(final Long newFileID) { + setFileIDOpt(Optional.ofNullable(newFileID)); disposeContent(); - if (fileIDOpt.isPresent() == false || Case.isCaseOpen() == false) { + if (getFileID().isPresent() == false || Case.isCaseOpen() == false) { if (registered == true) { getController().getCategoryManager().unregisterListener(this); getController().getTagsManager().unregisterListener(this); registered = false; } - fileOpt = Optional.empty(); + setFileOpt(Optional.empty()); Platform.runLater(() -> { clearContent(); }); @@ -350,10 +302,10 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie getController().getTagsManager().registerListener(this); registered = true; } - fileOpt = Optional.empty(); + setFileOpt(Optional.empty()); updateSelectionState(); - updateCategoryBorder(); + updateCategory(); updateFollowUpIcon(); updateUI(); Platform.runLater(getContentUpdateRunnable()); @@ -397,10 +349,10 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { - fileIDOpt.ifPresent(fileID -> { + getFileID().ifPresent(fileID -> { try { if (fileID == evt.getAddedTag().getContent().getId() - && evt.getAddedTag().getName() == getController().getTagsManager().getFollowUpTagName()) { + && evt.getAddedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { Platform.runLater(() -> { followUpImageView.setImage(followUpIcon); @@ -417,10 +369,10 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - fileIDOpt.ifPresent(fileID -> { + getFileID().ifPresent(fileID -> { try { if (fileID == evt.getDeletedTag().getContent().getId() - && evt.getDeletedTag().getName() == controller.getTagsManager().getFollowUpTagName()) { + && evt.getDeletedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { updateFollowUpIcon(); } } catch (TskCoreException ex) { @@ -436,19 +388,4 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie followUpToggle.setSelected(hasFollowUp); }); } - - @Subscribe - @Override - public void handleCategoryChanged(CategoryChangeEvent evt) { - fileIDOpt.ifPresent(fileID -> { - if (evt.getFileIDs().contains(fileID)) { - updateCategoryBorder(); - } - }); - } - - @Override - public ImageGalleryController getController() { - return controller; - } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java new file mode 100644 index 0000000000..ec794eabae --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java @@ -0,0 +1,97 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery.gui; + +import java.util.Objects; +import static java.util.Objects.nonNull; +import java.util.Optional; +import java.util.logging.Level; +import javafx.scene.layout.AnchorPane; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * + */ +abstract public class DrawableUIBase extends AnchorPane implements DrawableView { + + private final ImageGalleryController controller; + + volatile private Optional> fileOpt = Optional.empty(); + + volatile private Optional fileIDOpt = Optional.empty(); + + public DrawableUIBase(ImageGalleryController controller) { + this.controller = controller; + } + + @Override + public ImageGalleryController getController() { + return controller; + } + + @Override + public Optional getFileID() { + return fileIDOpt; + } + + void setFileIDOpt(Optional fileIDOpt) { + this.fileIDOpt = fileIDOpt; + } + + void setFileOpt(Optional> fileOpt) { + this.fileOpt = fileOpt; + } + + @Override + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + try { + fileOpt = Optional.of(getController().getFileFromId(fileIDOpt.get())); + } catch (TskCoreException ex) { + Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); + fileOpt = Optional.empty(); + } + return fileOpt; + } + } else { + return Optional.empty(); + } + } + + protected abstract void setFileHelper(Long newFileID); + + @Override + public void setFile(Long newFileID) { + if (getFileID().isPresent()) { + if (Objects.equals(newFileID, getFileID().get()) == false) { + setFileHelper(newFileID); + } + } else if (nonNull(newFileID)) { + setFileHelper(newFileID); + } + } + + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index e4e6faf1de..709679173e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -68,7 +68,13 @@ public interface DrawableView { * @param evt the CategoryChangeEvent to handle */ @Subscribe - void handleCategoryChanged(CategoryChangeEvent evt); + default void handleCategoryChanged(CategoryChangeEvent evt) { + getFileID().ifPresent(fileID -> { + if (evt.getFileIDs().contains(fileID)) { + updateCategory(); + } + }); + } @Subscribe void handleTagAdded(ContentTagAddedEvent evt); @@ -116,16 +122,12 @@ public interface DrawableView { } @ThreadConfined(type = ThreadConfined.ThreadType.ANY) - default Category updateCategoryBorder() { - if (getFile() != null) { + default Category updateCategory() { + if (getFile().isPresent()) { final Category category = getFile().map(DrawableFile::getCategory).orElse(Category.ZERO); - final Border border = hasHashHit() && (category == Category.ZERO) - ? HASH_BORDER - : getCategoryBorder(category); - + final Border border = hasHashHit() && (category == Category.ZERO) ? HASH_BORDER : getCategoryBorder(category); Platform.runLater(() -> { getCategoryBorderRegion().setBorder(border); - getCategoryBorderRegion().requestLayout(); }); return category; } else { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index 87bd64491f..d89db4116c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -23,9 +23,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.Objects; -import static java.util.Objects.nonNull; import java.util.Optional; -import java.util.logging.Level; import java.util.stream.Collectors; import javafx.application.Platform; import javafx.beans.property.SimpleObjectProperty; @@ -39,7 +37,6 @@ import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.image.Image; import javafx.scene.image.ImageView; -import javafx.scene.layout.AnchorPane; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Region; import static javafx.scene.layout.Region.USE_COMPUTED_SIZE; @@ -53,24 +50,15 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; /** * Shows details of the selected file. */ -public class MetaDataPane extends AnchorPane implements DrawableView { +public class MetaDataPane extends DrawableUIBase { private static final Logger LOGGER = Logger.getLogger(MetaDataPane.class.getName()); - private final ImageGalleryController controller; - - @Override - public ImageGalleryController getController() { - return controller; - } - @FXML private ImageView imageView; @@ -141,56 +129,14 @@ public class MetaDataPane extends AnchorPane implements DrawableView { tableView.getColumns().setAll(Arrays.asList(attributeColumn, valueColumn)); //listen for selection change - controller.getSelectionModel().lastSelectedProperty().addListener((observable, oldFileID, newFileID) -> { + getController().getSelectionModel().lastSelectedProperty().addListener((observable, oldFileID, newFileID) -> { setFile(newFileID); }); } - volatile private Optional> fileOpt = Optional.empty(); - - volatile private Optional fileIDOpt = Optional.empty(); - @Override - public Optional getFileID() { - return fileIDOpt; - } - - @Override - public Optional> getFile() { - if (fileIDOpt.isPresent()) { - if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { - return fileOpt; - } else { - try { - fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); - } catch (TskCoreException ex) { - Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); - fileOpt = Optional.empty(); - } - return fileOpt; - } - } else { - return Optional.empty(); - } - } - - @Override - public void setFile(Long newFileID) { - - if (fileIDOpt.isPresent()) { - if (Objects.equals(newFileID, fileIDOpt.get()) == false) { - setFileHelper(newFileID); - } - } else { - if (nonNull(newFileID)) { - setFileHelper(newFileID); - } - } - setFileHelper(newFileID); - } - - private void setFileHelper(Long newFileID) { - fileIDOpt = Optional.of(newFileID); + synchronized protected void setFileHelper(Long newFileID) { + setFileIDOpt(Optional.ofNullable(newFileID)); if (newFileID == null) { Platform.runLater(() -> { imageView.setImage(null); @@ -204,7 +150,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { } public MetaDataPane(ImageGalleryController controller) { - this.controller = controller; + super(controller); FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MetaDataPane.fxml")); fxmlLoader.setRoot(this); @@ -224,12 +170,12 @@ public class MetaDataPane extends AnchorPane implements DrawableView { Platform.runLater(() -> { imageView.setImage(icon); + tableView.getItems().clear(); tableView.getItems().setAll(attributesList); }); - updateCategoryBorder(); + updateCategory(); }); - } @Override @@ -248,11 +194,13 @@ public class MetaDataPane extends AnchorPane implements DrawableView { }); } + @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { handleTagChanged(evt.getAddedTag().getContent().getId()); } + @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { handleTagChanged(evt.getDeletedTag().getContent().getId()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index ab74554b39..99944d6d19 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -58,8 +58,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.ImageFile; import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.CAT_BORDER_WIDTH; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.HASH_BORDER; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.getCategoryBorder; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -68,7 +66,7 @@ import org.sleuthkit.datamodel.TskCoreException; * GroupPane. TODO: Extract a subclass for video files in slideshow mode-jm * TODO: reduce coupling to GroupPane */ -public class SlideShowView extends DrawableViewBase { +public class SlideShowView extends DrawableTileBase { private static final Logger LOGGER = Logger.getLogger(SlideShowView.class.getName()); @@ -223,6 +221,7 @@ public class SlideShowView extends DrawableViewBase { SlideShowView(GroupPane gp) { super(gp); + FXMLConstructor.construct(this, "SlideShow.fxml"); } @@ -237,6 +236,7 @@ public class SlideShowView extends DrawableViewBase { @Override synchronized public void setFile(final Long fileID) { super.setFile(fileID); + getFileID().ifPresent((Long id) -> { getGroupPane().makeSelection(false, id); }); @@ -288,7 +288,7 @@ public class SlideShowView extends DrawableViewBase { @ThreadConfined(type = ThreadType.JFX) private void cycleSlideShowImage(int d) { stopVideo(); - if (getFileID() != null) { + if (getFileID().isPresent()) { int index = getGroupPane().getGrouping().fileIds().indexOf(getFileID()); final int size = getGroupPane().getGrouping().fileIds().size(); index = (index + d) % size; @@ -312,20 +312,17 @@ public class SlideShowView extends DrawableViewBase { @Override @ThreadConfined(type = ThreadType.ANY) - public Category updateCategoryBorder() { - return getFile().map(file -> { - final Category category = file.getCategory(); - final Border border1 = hasHashHit() && (category == Category.ZERO) - ? HASH_BORDER - : getCategoryBorder(category); + public Category updateCategory() { + if (getFile().isPresent()) { + final Category category = super.updateCategory(); ToggleButton toggleForCategory = getToggleForCategory(category); Platform.runLater(() -> { - getCategoryBorderRegion().setBorder(border1); toggleForCategory.setSelected(true); }); return category; - }).orElse(Category.ZERO); - + } else { + return Category.ZERO; + } } private ToggleButton getToggleForCategory(Category category) { From 09be261f89eca0a224261f8512653539da02d705 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Mon, 22 Jun 2015 13:27:33 -0400 Subject: [PATCH 070/198] Unused fields removed. Potential NPE checked in SevenZipExtractor --- .../embeddedfileextractor/SevenZipExtractor.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 1dc6bbb5a4..12e184c961 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -311,7 +311,6 @@ class SevenZipExtractor { NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ArchiveExtractor.moduleName")); int processedItems = 0; - String compressMethod = null; boolean progressStarted = false; try { stream = new SevenZipContentReadStream(new ReadContentInputStream(archiveFile)); @@ -402,10 +401,6 @@ class SevenZipExtractor { //update progress bar progress.progress(archiveFile.getName() + ": " + fileName, processedItems); - if (compressMethod == null) { - compressMethod = item.getMethod(); - } - final boolean isEncrypted = item.isEncrypted(); final boolean isDir = item.isFolder(); @@ -417,7 +412,13 @@ class SevenZipExtractor { fullEncryption = false; } - final long size = item.getSize(); + final Long size = item.getSize(); + if (size == null) { + // If the size property cannot be determined, out-of-disk-space + // situations cannot be ascertained. + // Hence skip this file. + continue; + } //check if unpacking this file will result in out of disk space //this is additional to zip bomb prevention mechanism From 3c3584b23d948a615d600fea71e0dff3165e5f8a Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Mon, 22 Jun 2015 14:00:01 -0400 Subject: [PATCH 071/198] files skipped due to unknown size logged --- .../autopsy/modules/embeddedfileextractor/SevenZipExtractor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 12e184c961..953d138fb7 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -417,6 +417,7 @@ class SevenZipExtractor { // If the size property cannot be determined, out-of-disk-space // situations cannot be ascertained. // Hence skip this file. + logger.log(Level.WARNING, "Size cannot be determined. Skipping file in archive: {0}", pathInArchive); //NON-NLS continue; } From 4fdac3a8be747f684fcb87d9024caf4c84bae40e Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 14:11:44 -0400 Subject: [PATCH 072/198] rename method in CategoryManager to be more descriptive; fix tag and category grouping when tags aer added / removed --- .../datamodel/CategoryManager.java | 6 ++-- .../imagegallery/grouping/GroupManager.java | 35 +++++++++++-------- .../imagegallery/gui/SlideShowView.java | 28 +++++++-------- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 4d2591aa1e..3a1a81e72d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -211,7 +211,7 @@ public class CategoryManager { } - public static Category fromTagName(TagName tagName) { + public static Category categoryFromTagName(TagName tagName) { return Category.fromDisplayName(tagName.getDisplayName()); } @@ -246,7 +246,7 @@ public class CategoryManager { } catch (TskCoreException tskException) { LOGGER.log(Level.SEVERE, "Failed to get content tags for content. Unable to maintain category in a consistent state.", tskException); } - Category newCat = CategoryManager.fromTagName(addedTag.getName()); + Category newCat = CategoryManager.categoryFromTagName(addedTag.getName()); if (newCat != Category.ZERO) { incrementCategoryCount(newCat); } @@ -259,7 +259,7 @@ public class CategoryManager { ContentTag deleted = event.getDeletedTag(); if (isCategoryTagName(deleted.getName())) { - Category deletedCat = CategoryManager.fromTagName(deleted.getName()); + Category deletedCat = CategoryManager.categoryFromTagName(deleted.getName()); if (deletedCat != Category.ZERO) { decrementCategoryCount(deletedCat); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 9ac899742c..90adfa76b8 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -539,20 +539,25 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { - if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); - final long fileID = evt.getAddedTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); + GroupKey groupKey = null; + if (groupBy == DrawableAttribute.TAGS) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + } else if (groupBy == DrawableAttribute.CATEGORY) { + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getAddedTag().getName())); } + final long fileID = evt.getAddedTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); } + @SuppressWarnings("AssignmentToMethodParameter") private void addFileToGroup(DrawableGroup g, final GroupKey groupKey, final long fileID) { if (g == null) { //if there wasn't already a group check if there should be one now - popuplateIfAnalyzed(groupKey, null); - } else { + g = popuplateIfAnalyzed(groupKey, null); + } + if (g != null) { //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. g.addFile(fileID); } @@ -560,11 +565,14 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagDeleted(ContentTagDeletedEvent evt) { - if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); - final long fileID = evt.getDeletedTag().getContent().getId(); - DrawableGroup g = removeFromGroup(groupKey, fileID); + GroupKey groupKey = null; + if (groupBy == DrawableAttribute.TAGS) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); + } else if (groupBy == DrawableAttribute.CATEGORY) { + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getDeletedTag().getName())); } + final long fileID = evt.getDeletedTag().getContent().getId(); + DrawableGroup g = removeFromGroup(groupKey, fileID); } @Override @@ -631,7 +639,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { /* for attributes other than path we can't be sure a group is * fully analyzed because we don't know all the files that - * will be a part of that group */ + * will be a part of that group,. just show them no matter what. */ try { Set fileIDs = getFileIDsInGroup(groupKey); @@ -643,9 +651,8 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { group = groupMap.get(groupKey); group.setFiles(ObjectUtils.defaultIfNull(fileIDs, Collections.emptySet())); } else { - group = new DrawableGroup(groupKey, fileIDs, groupSeen); - group.seenProperty().addListener((observable, oldSeen, newSeen) -> { + group.seenProperty().addListener((o, oldSeen, newSeen) -> { markGroupSeen(group, newSeen); }); groupMap.put(groupKey, group); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index 99944d6d19..d7d0f684ed 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -25,6 +25,7 @@ import javafx.application.Platform; import javafx.beans.Observable; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; +import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; @@ -282,24 +283,20 @@ public class SlideShowView extends DrawableTileBase { @Override protected String getTextForLabel() { - return getFile().map(file -> file.getName() + " " + getSupplementalText()).orElse(""); + return getFile().map(file -> file.getName()).orElse("") + " " + getSupplementalText(); } @ThreadConfined(type = ThreadType.JFX) - private void cycleSlideShowImage(int d) { + private void cycleSlideShowImage(int direction) { stopVideo(); - if (getFileID().isPresent()) { - int index = getGroupPane().getGrouping().fileIds().indexOf(getFileID()); - final int size = getGroupPane().getGrouping().fileIds().size(); - index = (index + d) % size; - if (index < 0) { - index += size; - } - setFile(getGroupPane().getGrouping().fileIds().get(index)); + final int groupSize = getGroupPane().getGrouping().fileIds().size(); + final Integer nextIndex = getFileID().map(fileID -> { + final int currentIndex = getGroupPane().getGrouping().fileIds().indexOf(fileID); + return (currentIndex + direction + groupSize) % groupSize; + }).orElse(0); + setFile(getGroupPane().getGrouping().fileIds().get(nextIndex) + ); - } else { - setFile(getGroupPane().getGrouping().fileIds().get(0)); - } } /** @@ -307,7 +304,10 @@ public class SlideShowView extends DrawableTileBase { * of y" */ private String getSupplementalText() { - return " ( " + (getGroupPane().getGrouping().fileIds().indexOf(getFileID()) + 1) + " of " + getGroupPane().getGrouping().fileIds().size() + " in group )"; + final ObservableList fileIds = getGroupPane().getGrouping().fileIds(); + return getFileID().map(fileID -> " ( " + (fileIds.indexOf(fileID) + 1) + " of " + fileIds.size() + " in group )") + .orElse(""); + } @Override From 05b53ca5f40996b6d0a962e979bea4a2154f344f Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Mon, 22 Jun 2015 14:00:01 -0400 Subject: [PATCH 073/198] files skipped due to unknown size logged --- .../autopsy/modules/embeddedfileextractor/SevenZipExtractor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 12e184c961..953d138fb7 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -417,6 +417,7 @@ class SevenZipExtractor { // If the size property cannot be determined, out-of-disk-space // situations cannot be ascertained. // Hence skip this file. + logger.log(Level.WARNING, "Size cannot be determined. Skipping file in archive: {0}", pathInArchive); //NON-NLS continue; } From 3fa996d6fc7c3f2b4d6414df19616167e3bd1c69 Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 10:22:18 -0400 Subject: [PATCH 074/198] Tag Events - created new Case.Event enum values for BlackBoard/Content tags added/deleted - created new PropertyChangeEvent subclasses for BlackBoard/Content tags added/deleted - replaced ModuleDataEvent hack with new Tag Events - removed [in] from javadocs, other minor cleanup --- .../autopsy/actions/AddTagAction.java | 38 +- .../sleuthkit/autopsy/actions/TagAction.java | 35 +- .../sleuthkit/autopsy/casemodule/Case.java | 113 ++++- .../casemodule/services/TagsManager.java | 392 +++++++++++------- .../org/sleuthkit/autopsy/datamodel/Tags.java | 15 +- .../autopsy/events/AutopsyEvent.java | 19 + .../BlackBoardArtifactTagAddedEvent.java | 33 ++ .../BlackBoardArtifactTagDeletedEvent.java | 32 ++ .../autopsy/events/ContentTagAddedEvent.java | 35 ++ .../events/ContentTagDeletedEvent.java | 34 ++ .../autopsy/events/TagAddedEvent.java | 46 ++ .../autopsy/events/TagDeletedEvent.java | 45 ++ .../sleuthkit/autopsy/events/TagEvent.java | 26 ++ 13 files changed, 625 insertions(+), 238 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/events/AutopsyEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagAddedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagDeletedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/ContentTagAddedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/ContentTagDeletedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/TagEvent.java diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index b051fa2238..9c552247fd 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,20 +19,18 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.Collections; import java.util.List; import java.util.logging.Level; import javax.swing.JMenu; import javax.swing.JMenuItem; - import org.openide.util.NbBundle; import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.coreutils.Logger; /** * An abstract base class for Actions that allow users to tag SleuthKit data @@ -98,12 +96,8 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { if (null != tagNames && !tagNames.isEmpty()) { for (final TagName tagName : tagNames) { JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName()); - tagNameItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - addTag(tagName, NO_COMMENT); - refreshDirectoryTree(); - } + tagNameItem.addActionListener((ActionEvent e) -> { + addTag(tagName, NO_COMMENT); }); quickTagMenu.add(tagNameItem); } @@ -120,14 +114,10 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { // Selecting this item initiates a dialog that can be used to create // or select a tag name and adds a tag with the resulting name. JMenuItem newTagMenuItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.newTag")); - newTagMenuItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - TagName tagName = GetTagNameDialog.doDialog(); - if (tagName != null) { - addTag(tagName, NO_COMMENT); - refreshDirectoryTree(); - } + newTagMenuItem.addActionListener((ActionEvent e) -> { + TagName tagName = GetTagNameDialog.doDialog(); + if (null != tagName) { + addTag(tagName, NO_COMMENT); } }); quickTagMenu.add(newTagMenuItem); @@ -137,14 +127,10 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { // optional comment and adds a tag with the resulting name. JMenuItem tagAndCommentItem = new JMenuItem( NbBundle.getMessage(this.getClass(), "AddTagAction.tagAndComment")); - tagAndCommentItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); - if (null != tagNameAndComment) { - addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); - refreshDirectoryTree(); - } + tagAndCommentItem.addActionListener((ActionEvent e) -> { + GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); + if (null != tagNameAndComment) { + addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } }); add(tagAndCommentItem); diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagAction.java b/Core/src/org/sleuthkit/autopsy/actions/TagAction.java index a540ce878a..ed53af2c6f 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/TagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/TagAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,41 +20,26 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; /** * Abstract base class for Actions involving tags. */ - abstract class TagAction extends AbstractAction { +abstract class TagAction extends AbstractAction { + public TagAction(String menuText) { super(menuText); } - + @Override public void actionPerformed(ActionEvent event) { doAction(event); - refreshDirectoryTree(); - } - + } + /** - * Derived classes must implement this Template Method for actionPerformed(). - * @param event ActionEvent object passed to actionPerformed() + * Derived classes must implement this Template Method for + * actionPerformed(). + * + * @param event ActionEvent object passed to actionPerformed() */ abstract protected void doAction(ActionEvent event); - - /** - * Derived classes should call this method any time a tag is created, updated - * or deleted outside of an actionPerformed() call. - */ - @SuppressWarnings("deprecation") - protected void refreshDirectoryTree() { - - /* Note: this is a hack. In an ideal world, TagsManager would fire events so - * that the directory tree would refresh. But, we haven't had a chance to add - * that so, we fire these events and the tree refreshes based on them. - */ - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index db1250ebf7..19ec87e3cc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.Frame; +import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.BufferedInputStream; @@ -49,8 +50,19 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.Version; -import org.sleuthkit.datamodel.*; +import org.sleuthkit.autopsy.events.BlackBoardArtifactTagAddedEvent; +import org.sleuthkit.autopsy.events.BlackBoardArtifactTagDeletedEvent; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.Report; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitJNI.CaseDbHandle.AddImageProcess; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskException; /** * Stores all information for a given case. Only a single case can currently be @@ -126,7 +138,19 @@ public class Case implements SleuthkitCase.ErrorObserver { * case. The old value supplied by the event object is null and the new * value is a reference to a Report object representing the new report. */ - REPORT_ADDED; + REPORT_ADDED, + /** Property name for the event when a new BlackBoardArtifactTag is + * added. The new value is tag added, the old value is empty */ + BLACKBOARD_ARTIFACT_TAG_ADDED, + /** Property name for the event when a new BlackBoardArtifactTag is + * deleted. The new value is empty, the old value is the deleted tag */ + BLACKBOARD_ARTIFACT_TAG_DELETED, + /** Property name for the event when a new ContentTag is + * added. The new value is tag added, the old value is empty */ + CONTENT_TAG_ADDED, + /** Property name for the event when a new ContentTag is + * deleted. The new value is empty, the old value is the deleted tag */ + CONTENT_TAG_DELETED; }; private String name; @@ -267,12 +291,13 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Creates a new case (create the XML config file and database) * - * @param caseDir The directory to store case data in. Will be created if it - * doesn't already exist. If it exists, it should have all of the needed sub - * dirs that createCaseDirectory() will create. - * @param caseName the name of case + * @param caseDir The directory to store case data in. Will be created if + * it + * doesn't already exist. If it exists, it should have all of the needed sub + * dirs that createCaseDirectory() will create. + * @param caseName the name of case * @param caseNumber the case number - * @param examiner the examiner for this case + * @param examiner the examiner for this case */ public static void create(String caseDir, String caseName, String caseNumber, String examiner) throws CaseActionException { logger.log(Level.INFO, "Creating new case.\ncaseDir: {0}\ncaseName: {1}", new Object[]{caseDir, caseName}); //NON-NLS @@ -418,7 +443,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Sends out event and reopens windows if needed. * * @param imgPaths the paths of the image that being added - * @param imgId the ID of the image that being added + * @param imgId the ID of the image that being added * @param timeZone the timeZone of the image where it's added */ @Deprecated @@ -476,6 +501,59 @@ public class Case implements SleuthkitCase.ErrorObserver { CoreComponentControl.openCoreWindows(); } + /** + * Notifies the UI that a new ContentTag has been added. + * + * @param newTag new ContentTag added + */ + public void notifyContentTagAdded(ContentTag newTag) { + notify(new ContentTagAddedEvent(newTag)); + } + + /** + * Notifies the UI that a ContentTag has been deleted. + * + * @param deletedTag ContentTag deleted + */ + public void notifyContentTagDeleted(ContentTag deletedTag) { + notify(new ContentTagDeletedEvent(deletedTag)); + } + + /** + * Notifies the UI that a new BlackboardArtifactTag has been added. + * + * @param newTag new BlackboardArtifactTag added + */ + public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) { + notify(new BlackBoardArtifactTagAddedEvent(newTag)); + } + + /** + * Notifies the UI that a BlackboardArtifactTag has been. + * + * @param deletedTag BlackboardArtifactTag deleted + */ + public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { + notify(new BlackBoardArtifactTagDeletedEvent(deletedTag)); + } + + /** + * Notifies the UI about a Case level event. + * + * @param propertyChangeEvent the event to distribute + */ + private void notify(final PropertyChangeEvent propertyChangeEvent) { + try { + pcs.firePropertyChange(propertyChangeEvent); + } catch (Exception e) { + logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS + MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), + NbBundle.getMessage(this.getClass(), + "Case.changeCase.errListenToCaseUpdates.msg"), + MessageNotifyUtil.MessageType.ERROR); + } + } + /** * @return The Services object for this case. */ @@ -540,9 +618,9 @@ public class Case implements SleuthkitCase.ErrorObserver { * Updates the case name. * * @param oldCaseName the old case name that wants to be updated - * @param oldPath the old path that wants to be updated + * @param oldPath the old path that wants to be updated * @param newCaseName the new case name - * @param newPath the new path + * @param newPath the new path */ void updateCaseName(String oldCaseName, String oldPath, String newCaseName, String newPath) throws CaseActionException { try { @@ -801,6 +879,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Get the data model Content objects in the root of this case's hierarchy. * * @return a list of the root objects + * * @throws org.sleuthkit.datamodel.TskCoreException */ public List getDataSources() throws TskCoreException { @@ -934,7 +1013,7 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * to create the case directory * - * @param caseDir Path to the case directory (typically base + case name) + * @param caseDir Path to the case directory (typically base + case name) * @param caseName the case name (used only for error messages) * * @throws CaseActionException throw if could not create the case dir @@ -1154,12 +1233,14 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Adds a report to the case. * - * @param [in] localPath The path of the report file, must be in the case - * directory or one of its subdirectories. - * @param [in] sourceModuleName The name of the module that created the - * report. - * @param [in] reportName The report name, may be empty. + * @param localPath The path of the report file, must be in the case + * directory or one of its subdirectories. + * @param sourceModuleName The name of the module that created the + * report. + * @param reportName The report name, may be empty. + * * @return A Report data transfer object (DTO) for the new row. + * * @throws TskCoreException */ public void addReport(String localPath, String srcModuleName, String reportName) throws TskCoreException { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 6be8439029..123238c4e3 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,9 +24,9 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; - import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; @@ -37,28 +37,32 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** - * A per case instance of this class functions as an Autopsy service that - * manages the creation, updating, and deletion of tags applied to content and - * blackboard artifacts by users. + * A per case instance of this class functions as an Autopsy service that + * manages the creation, updating, and deletion of tags applied to content and + * blackboard artifacts by users. */ public class TagsManager implements Closeable { + private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS - private final SleuthkitCase tskCase; + private final SleuthkitCase tskCase; private final HashMap uniqueTagNames = new HashMap<>(); private boolean tagNamesInitialized = false; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized. - - // Use this exception and the member hash map to manage uniqueness of hash - // names. This is deemed more proactive and informative than leaving this to - // the UNIQUE constraint on the display_name field of the tag_names table in - // the case database. - public class TagNameAlreadyExistsException extends Exception { - } - + /** - * Package-scope constructor for use of the Services class. An instance of + * Use this exception and the member hash map to manage uniqueness of hash + * names. This is deemed more proactive and informative than leaving this to + * the UNIQUE constraint on the display_name field of the tag_names table in + * the case database. + */ + public static class TagNameAlreadyExistsException extends Exception { + } + + /** + * Package-scope constructor for use of the Services class. An instance of * TagsManager should be created for each case that is opened. - * @param [in] tskCase The SleuthkitCase object for the current case. + * + * @param tskCase The SleuthkitCase object for the current case. */ TagsManager(SleuthkitCase tskCase) { this.tskCase = tskCase; @@ -67,38 +71,44 @@ public class TagsManager implements Closeable { } /** - * Gets a list of all tag names currently available for tagging content or + * Gets a list of all tag names currently available for tagging content or * blackboard artifacts. - * @return A list, possibly empty, of TagName data transfer objects (DTOs). - * @throws TskCoreException + * + * @return A list, possibly empty, of TagName data transfer objects (DTOs). + * + * @throws TskCoreException */ - public synchronized List getAllTagNames() throws TskCoreException { + public synchronized List getAllTagNames() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + return tskCase.getAllTagNames(); } /** - * Gets a list of all tag names currently used for tagging content or + * Gets a list of all tag names currently used for tagging content or * blackboard artifacts. - * @return A list, possibly empty, of TagName data transfer objects (DTOs). - * @throws TskCoreException + * + * @return A list, possibly empty, of TagName data transfer objects (DTOs). + * + * @throws TskCoreException */ - public synchronized List getTagNamesInUse() throws TskCoreException { + public synchronized List getTagNamesInUse() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + return tskCase.getTagNamesInUse(); } - + /** * Checks whether a tag name with a given display name exists. - * @param [in] tagDisplayName The display name for which to check. + * + * @param tagDisplayName The display name for which to check. + * * @return True if the tag name exists, false otherwise. */ public synchronized boolean tagNameExists(String tagDisplayName) { @@ -106,15 +116,19 @@ public class TagsManager implements Closeable { if (!tagNamesInitialized) { getExistingTagNames(); } - + return uniqueTagNames.containsKey(tagDisplayName); } - + /** * Adds a new tag name to the current case and to the tags settings. - * @param [in] displayName The display name for the new tag name. - * @return A TagName data transfer object (DTO) representing the new tag name. - * @throws TagNameAlreadyExistsException, TskCoreException + * + * @param displayName The display name for the new tag name. + * + * @return A TagName data transfer object (DTO) representing the new tag + * name. + * + * @throws TagNameAlreadyExistsException, TskCoreException */ public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, "", TagName.HTML_COLOR.NONE); @@ -122,10 +136,14 @@ public class TagsManager implements Closeable { /** * Adds a new tag name to the current case and to the tags settings. - * @param [in] displayName The display name for the new tag name. - * @param [in] description The description for the new tag name. - * @return A TagName data transfer object (DTO) representing the new tag name. - * @throws TagNameAlreadyExistsException, TskCoreException + * + * @param displayName The display name for the new tag name. + * @param description The description for the new tag name. + * + * @return A TagName data transfer object (DTO) representing the new tag + * name. + * + * @throws TagNameAlreadyExistsException, TskCoreException */ public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, description, TagName.HTML_COLOR.NONE); @@ -133,82 +151,95 @@ public class TagsManager implements Closeable { /** * Adds a new tag name to the current case and to the tags settings. - * @param [in] displayName The display name for the new tag name. - * @param [in] description The description for the new tag name. - * @param [in] color The HTML color to associate with the new tag name. - * @return A TagName data transfer object (DTO) representing the new tag name. - * @throws TagNameAlreadyExistsException, TskCoreException + * + * @param displayName The display name for the new tag name. + * @param description The description for the new tag name. + * @param color The HTML color to associate with the new tag name. + * + * @return A TagName data transfer object (DTO) representing the new tag + * name. + * + * @throws TagNameAlreadyExistsException, TskCoreException */ public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + if (uniqueTagNames.containsKey(displayName)) { throw new TagNameAlreadyExistsException(); } // Add the tag name to the case. - TagName newTagName = tskCase.addTagName(displayName, description, color); + TagName newTagName = tskCase.addTagName(displayName, description, color); // Add the tag name to the tags settings. uniqueTagNames.put(newTagName.getDisplayName(), newTagName); - saveTagNamesToTagsSettings(); + saveTagNamesToTagsSettings(); return newTagName; } - + /** * Tags a content object. - * @param [in] content The content to tag. - * @param [in] tagName The name to use for the tag. - * @return A ContentTag data transfer object (DTO) representing the new tag. - * @throws TskCoreException + * + * @param content The content to tag. + * @param tagName The name to use for the tag. + * + * @return A ContentTag data transfer object (DTO) representing the new tag. + * + * @throws TskCoreException */ public ContentTag addContentTag(Content content, TagName tagName) throws TskCoreException { return addContentTag(content, tagName, "", -1, -1); - } - + } + /** * Tags a content object. - * @param [in] content The content to tag. - * @param [in] tagName The name to use for the tag. - * @param [in] comment A comment to store with the tag. - * @return A ContentTag data transfer object (DTO) representing the new tag. - * @throws TskCoreException + * + * @param content The content to tag. + * @param tagName The name to use for the tag. + * @param comment A comment to store with the tag. + * + * @return A ContentTag data transfer object (DTO) representing the new tag. + * + * @throws TskCoreException */ public ContentTag addContentTag(Content content, TagName tagName, String comment) throws TskCoreException { return addContentTag(content, tagName, comment, -1, -1); - } - + } + /** * Tags a content object or a section of a content object. - * @param [in] content The content to tag. - * @param [in] tagName The name to use for the tag. - * @param [in] comment A comment to store with the tag. - * @param [in] beginByteOffset Designates the beginning of a tagged section. - * @param [in] endByteOffset Designates the end of a tagged section. - * @return A ContentTag data transfer object (DTO) representing the new tag. - * @throws IllegalArgumentException, TskCoreException + * + * @param content The content to tag. + * @param tagName The name to use for the tag. + * @param comment A comment to store with the tag. + * @param beginByteOffset Designates the beginning of a tagged section. + * @param endByteOffset Designates the end of a tagged section. + * + * @return A ContentTag data transfer object (DTO) representing the new tag. + * + * @throws IllegalArgumentException, TskCoreException */ public synchronized ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + if (beginByteOffset >= 0 && endByteOffset >= 1) { if (beginByteOffset > content.getSize() - 1) { throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), - "TagsManager.addContentTag.exception.beginByteOffsetOOR.msg", - beginByteOffset, content.getSize() - 1)); + "TagsManager.addContentTag.exception.beginByteOffsetOOR.msg", + beginByteOffset, content.getSize() - 1)); } if (endByteOffset > content.getSize() - 1) { throw new IllegalArgumentException( NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endByteOffsetOOR.msg", - endByteOffset, content.getSize() - 1)); + endByteOffset, content.getSize() - 1)); } if (endByteOffset < beginByteOffset) { @@ -216,28 +247,34 @@ public class TagsManager implements Closeable { NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endLTbegin.msg")); } } - - return tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); + final ContentTag newContentTag = tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); + Case.getCurrentCase().notifyContentTagAdded(newContentTag); + return newContentTag; } - + /** * Deletes a content tag. - * @param [in] tag The tag to delete. - * @throws TskCoreException + * + * @param tag The tag to delete. + * + * @throws TskCoreException */ public synchronized void deleteContentTag(ContentTag tag) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + tskCase.deleteContentTag(tag); + Case.getCurrentCase().notifyContentTagDeleted(tag); } /** * Gets all content tags for the current case. + * * @return A list, possibly empty, of content tags. - * @throws TskCoreException + * + * @throws TskCoreException */ public List getAllContentTags() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. @@ -245,100 +282,126 @@ public class TagsManager implements Closeable { getExistingTagNames(); } - return tskCase.getAllContentTags(); + return tskCase.getAllContentTags(); } - + /** * Gets content tags count by tag name. - * @param [in] tagName The tag name of interest. + * + * @param tagName The tag name of interest. + * * @return A count of the content tags with the specified tag name. - * @throws TskCoreException + * + * @throws TskCoreException */ public synchronized long getContentTagsCountByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getContentTagsCountByTagName(tagName); + + return tskCase.getContentTagsCountByTagName(tagName); } - + /** * Gets content tags by tag name. - * @param [in] tagName The tag name of interest. - * @return A list, possibly empty, of the content tags with the specified tag name. - * @throws TskCoreException + * + * @param tagName The tag name of interest. + * + * @return A list, possibly empty, of the content tags with the specified + * tag name. + * + * @throws TskCoreException */ public synchronized List getContentTagsByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getContentTagsByTagName(tagName); + + return tskCase.getContentTagsByTagName(tagName); } - + /** * Gets content tags count by content. - * @param [in] content The content of interest. - * @return A list, possibly empty, of the tags that have been applied to the artifact. - * @throws TskCoreException + * + * @param content The content of interest. + * + * @return A list, possibly empty, of the tags that have been applied to the + * artifact. + * + * @throws TskCoreException */ public synchronized List getContentTagsByContent(Content content) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getContentTagsByContent(content); + + return tskCase.getContentTagsByContent(content); } - + /** * Tags a blackboard artifact object. - * @param [in] artifact The blackboard artifact to tag. - * @param [in] tagName The name to use for the tag. - * @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag. - * @throws TskCoreException + * + * @param artifact The blackboard artifact to tag. + * @param tagName The name to use for the tag. + * + * @return A BlackboardArtifactTag data transfer object (DTO) representing + * the new tag. + * + * @throws TskCoreException */ public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException { - return addBlackboardArtifactTag(artifact, tagName, ""); + return addBlackboardArtifactTag(artifact, tagName, ""); } - + /** * Tags a blackboard artifact object. - * @param [in] artifact The blackboard artifact to tag. - * @param [in] tagName The name to use for the tag. - * @param [in] comment A comment to store with the tag. - * @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag. - * @throws TskCoreException + * + * @param artifact The blackboard artifact to tag. + * @param tagName The name to use for the tag. + * @param comment A comment to store with the tag. + * + * @return A BlackboardArtifactTag data transfer object (DTO) representing + * the new tag. + * + * @throws TskCoreException */ public synchronized BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.addBlackboardArtifactTag(artifact, tagName, comment); + + BlackboardArtifactTag addBlackboardArtifactTag = tskCase.addBlackboardArtifactTag(artifact, tagName, comment); + Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(addBlackboardArtifactTag); + return addBlackboardArtifactTag; } /** * Deletes a blackboard artifact tag. - * @param [in] tag The tag to delete. - * @throws TskCoreException + * + * @param tag The tag to delete. + * + * @throws TskCoreException */ public synchronized void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + tskCase.deleteBlackboardArtifactTag(tag); + Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); } - + /** * Gets all blackboard artifact tags for the current case. + * * @return A list, possibly empty, of blackboard artifact tags. - * @throws TskCoreException + * + * @throws TskCoreException */ public List getAllBlackboardArtifactTags() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. @@ -346,100 +409,110 @@ public class TagsManager implements Closeable { getExistingTagNames(); } - return tskCase.getAllBlackboardArtifactTags(); + return tskCase.getAllBlackboardArtifactTags(); } - + /** * Gets blackboard artifact tags count by tag name. - * @param [in] tagName The tag name of interest. - * @return A count of the blackboard artifact tags with the specified tag name. - * @throws TskCoreException + * + * @param tagName The tag name of interest. + * + * @return A count of the blackboard artifact tags with the specified tag + * name. + * + * @throws TskCoreException */ public synchronized long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getBlackboardArtifactTagsCountByTagName(tagName); + + return tskCase.getBlackboardArtifactTagsCountByTagName(tagName); } - + /** * Gets blackboard artifact tags by tag name. - * @param [in] tagName The tag name of interest. - * @return A list, possibly empty, of the blackboard artifact tags with the specified tag name. - * @throws TskCoreException + * + * @param tagName The tag name of interest. + * + * @return A list, possibly empty, of the blackboard artifact tags with the + * specified tag name. + * + * @throws TskCoreException */ - public synchronized List getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException { + public synchronized List getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getBlackboardArtifactTagsByTagName(tagName); + + return tskCase.getBlackboardArtifactTagsByTagName(tagName); } /** * Gets blackboard artifact tags for a particular blackboard artifact. - * @param [in] artifact The blackboard artifact of interest. - * @return A list, possibly empty, of the tags that have been applied to the artifact. - * @throws TskCoreException + * + * @param artifact The blackboard artifact of interest. + * + * @return A list, possibly empty, of the tags that have been applied to the + * artifact. + * + * @throws TskCoreException */ - public synchronized List getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException { + public synchronized List getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getBlackboardArtifactTagsByArtifact(artifact); + + return tskCase.getBlackboardArtifactTagsByArtifact(artifact); } - + @Override - public void close() throws IOException { - saveTagNamesToTagsSettings(); - } - + public void close() throws IOException { + saveTagNamesToTagsSettings(); + } + private void getExistingTagNames() { getTagNamesFromCurrentCase(); getTagNamesFromTagsSettings(); getPredefinedTagNames(); - saveTagNamesToTagsSettings(); + saveTagNamesToTagsSettings(); tagNamesInitialized = true; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized. } - + private void getTagNamesFromCurrentCase() { try { List currentTagNames = tskCase.getAllTagNames(); for (TagName tagName : currentTagNames) { uniqueTagNames.put(tagName.getDisplayName(), tagName); } - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); //NON-NLS - } + } } - + private void getTagNamesFromTagsSettings() { String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); - if (null != setting && !setting.isEmpty()) { + if (null != setting && !setting.isEmpty()) { // Read the tag name setting and break it into tag name tuples. - List tagNameTuples = Arrays.asList(setting.split(";")); - + List tagNameTuples = Arrays.asList(setting.split(";")); + // Parse each tuple and add the tag names to the current case, one // at a time to gracefully discard any duplicates or corrupt tuples. - for (String tagNameTuple : tagNameTuples) { + for (String tagNameTuple : tagNameTuples) { String[] tagNameAttributes = tagNameTuple.split(","); - if (!uniqueTagNames.containsKey(tagNameAttributes[0])) { + if (!uniqueTagNames.containsKey(tagNameAttributes[0])) { try { TagName tagName = tskCase.addTagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2])); uniqueTagNames.put(tagName.getDisplayName(), tagName); - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + tagNameAttributes[0], ex); //NON-NLS } } } - } + } } private void getPredefinedTagNames() { @@ -448,13 +521,12 @@ public class TagsManager implements Closeable { TagName tagName = tskCase.addTagName( NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"), "", TagName.HTML_COLOR.NONE); uniqueTagNames.put(tagName.getDisplayName(), tagName); - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add predefined 'Bookmark' tag name", ex); //NON-NLS } } - } - + } + private void saveTagNamesToTagsSettings() { if (!uniqueTagNames.isEmpty()) { StringBuilder setting = new StringBuilder(); @@ -466,7 +538,7 @@ public class TagsManager implements Closeable { setting.append(tagName.getDescription()).append(","); setting.append(tagName.getColor().name()); } - ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); + ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); } - } + } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index cc7958355e..5dccc5252d 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -35,8 +35,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -119,19 +117,14 @@ public class Tags implements AutopsyVisitableItem { private final PropertyChangeListener pcl = new PropertyChangeListener() { @Override - @SuppressWarnings("deprecation") public void propertyChange(PropertyChangeEvent evt) { String eventType = evt.getPropertyName(); - if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { - /* Note: this is a hack. In an ideal world, TagsManager - * would fire events so that the directory tree would - * refresh. But, we haven't had a chance to add that so, we - * fire these events and the tree refreshes based on them. */ - if ((((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT) - || ((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { + if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString()) + || eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString()) + || eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString()) + || eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) { refresh(true); tagResults.update(); - } } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { refresh(true); tagResults.update(); diff --git a/Core/src/org/sleuthkit/autopsy/events/AutopsyEvent.java b/Core/src/org/sleuthkit/autopsy/events/AutopsyEvent.java new file mode 100644 index 0000000000..fdaf727867 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/AutopsyEvent.java @@ -0,0 +1,19 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.events; + +import java.beans.PropertyChangeEvent; + +/** + * This is a place holder class to be overwritten by the version in the + * Collaborative branch. + */ +abstract class AutopsyEvent extends PropertyChangeEvent { + + AutopsyEvent(Object source, String propertyName, Object oldValue, Object newValue) { + super(source, propertyName, oldValue, newValue); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagAddedEvent.java b/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagAddedEvent.java new file mode 100644 index 0000000000..d50bd2237b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagAddedEvent.java @@ -0,0 +1,33 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.BlackboardArtifactTag; + +/** + * + */ +public class BlackBoardArtifactTagAddedEvent extends TagAddedEvent { + + public BlackBoardArtifactTagAddedEvent(BlackboardArtifactTag newTag) { + super(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString(), newTag + ); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagDeletedEvent.java b/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagDeletedEvent.java new file mode 100644 index 0000000000..b2901ac5dc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagDeletedEvent.java @@ -0,0 +1,32 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.BlackboardArtifactTag; + +/** + * + */ +public class BlackBoardArtifactTagDeletedEvent extends TagDeletedEvent { + + public BlackBoardArtifactTagDeletedEvent(BlackboardArtifactTag oldValue) { + super(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString(), oldValue); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/events/ContentTagAddedEvent.java b/Core/src/org/sleuthkit/autopsy/events/ContentTagAddedEvent.java new file mode 100644 index 0000000000..ffd196a4c7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/ContentTagAddedEvent.java @@ -0,0 +1,35 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.ContentTag; + +/** + * An event that is fired when a ContentTag is added. + */ +@Immutable +public class ContentTagAddedEvent extends TagAddedEvent { + + public ContentTagAddedEvent(ContentTag newTag) { + super(Case.Events.CONTENT_TAG_ADDED.toString(), newTag); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/events/ContentTagDeletedEvent.java b/Core/src/org/sleuthkit/autopsy/events/ContentTagDeletedEvent.java new file mode 100644 index 0000000000..6c6d11745f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/ContentTagDeletedEvent.java @@ -0,0 +1,34 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.ContentTag; + +/** + * An event that is fired when a ContentTag is deleted. + */ +@Immutable +public class ContentTagDeletedEvent extends TagDeletedEvent { + + public ContentTagDeletedEvent(ContentTag deletedTag) { + super(Case.Events.CONTENT_TAG_DELETED.toString(), deletedTag); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java b/Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java new file mode 100644 index 0000000000..217af496cc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java @@ -0,0 +1,46 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.Tag; + +/** + * Base Class for events that are fired when a Tag is added + */ +@Immutable +abstract class TagAddedEvent extends TagEvent { + + protected TagAddedEvent(String propertyName, T newValue) { + super(Case.class, propertyName, null, newValue); + } + + /** + * get the Tag that was added + * + * @return the tTag + */ + @SuppressWarnings("unchecked") + @Override + public T getTag() { + return (T) getNewValue(); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java b/Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java new file mode 100644 index 0000000000..6a0a1c5668 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java @@ -0,0 +1,45 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.Tag; + +/** + * Base Class for events that are fired when a Tag is deleted + */ +@Immutable +abstract class TagDeletedEvent extends TagEvent { + + protected TagDeletedEvent(String propertyName, T oldValue) { + super(Case.class, propertyName, oldValue, null); + } + + /** + * get the Tag that was deleted + * + * @return the Tag + */ + @SuppressWarnings("unchecked") + @Override + public T getTag() { + return (T) getOldValue(); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/events/TagEvent.java b/Core/src/org/sleuthkit/autopsy/events/TagEvent.java new file mode 100644 index 0000000000..b80725782d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/TagEvent.java @@ -0,0 +1,26 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.events; + +import org.sleuthkit.datamodel.Tag; + +/** + * + */ +abstract public class TagEvent extends AutopsyEvent { + + public TagEvent(Object source, String propertyName, Object oldValue, Object newValue) { + super(source, propertyName, oldValue, newValue); + } + + /** + * get the Tag that this event is for + * + * @return the Tag + */ + public abstract T getTag(); + +} From b8f22991a4eba4fe0afa11373ed7570b32f4580f Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:11:16 -0400 Subject: [PATCH 075/198] reduce duplicate code --- .../imagegallery/ImageGalleryController.java | 4 +-- .../datamodel/CategoryManager.java | 4 +-- .../imagegallery/grouping/GroupManager.java | 12 +++---- .../imagegallery/gui/DrawableTileBase.java | 34 ++++++++++--------- .../imagegallery/gui/MetaDataPane.java | 17 +++++++--- 5 files changed, 40 insertions(+), 31 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index de1b0a399f..820e70e0e5 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -490,13 +490,13 @@ public final class ImageGalleryController { break; case CONTENT_TAG_ADDED: final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt; - if (getDatabase().isInDB((tagAddedEvent).getAddedTag().getContent().getId())) { + if (getDatabase().isInDB((tagAddedEvent).getTag().getContent().getId())) { getTagsManager().fireTagAddedEvent(tagAddedEvent); } break; case CONTENT_TAG_DELETED: final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) evt; - if (getDatabase().isInDB((tagDeletedEvent).getDeletedTag().getContent().getId())) { + if (getDatabase().isInDB((tagDeletedEvent).getTag().getContent().getId())) { getTagsManager().fireTagDeletedEvent(tagDeletedEvent); } break; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 3a1a81e72d..309173f153 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -226,7 +226,7 @@ public class CategoryManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent event) { - ContentTag addedTag = event.getAddedTag(); + ContentTag addedTag = event.getTag(); if (isCategoryTagName(addedTag.getName())) { final DrawableTagsManager tagsManager = controller.getTagsManager(); try { @@ -256,7 +256,7 @@ public class CategoryManager { } @Subscribe public void handleTagDeleted(ContentTagDeletedEvent event) { - ContentTag deleted = event.getDeletedTag(); + ContentTag deleted = event.getTag(); if (isCategoryTagName(deleted.getName())) { Category deletedCat = CategoryManager.categoryFromTagName(deleted.getName()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 90adfa76b8..d7819c6d5e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -541,11 +541,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public void handleTagAdded(ContentTagAddedEvent evt) { GroupKey groupKey = null; if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } else if (groupBy == DrawableAttribute.CATEGORY) { - groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getAddedTag().getName())); + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); } - final long fileID = evt.getAddedTag().getContent().getId(); + final long fileID = evt.getTag().getContent().getId(); DrawableGroup g = getGroupForKey(groupKey); addFileToGroup(g, groupKey, fileID); @@ -567,11 +567,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public void handleTagDeleted(ContentTagDeletedEvent evt) { GroupKey groupKey = null; if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } else if (groupBy == DrawableAttribute.CATEGORY) { - groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getDeletedTag().getName())); + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); } - final long fileID = evt.getDeletedTag().getContent().getId(); + final long fileID = evt.getTag().getContent().getId(); DrawableGroup g = removeFromGroup(groupKey, fileID); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java index 80c73b1ae9..428bd0b5f4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java @@ -62,6 +62,7 @@ import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.events.TagEvent; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; @@ -70,6 +71,7 @@ import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -349,36 +351,36 @@ public abstract class DrawableTileBase extends DrawableUIBase { @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { - getFileID().ifPresent(fileID -> { - try { - if (fileID == evt.getAddedTag().getContent().getId() - && evt.getAddedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { - Platform.runLater(() -> { - followUpImageView.setImage(followUpIcon); - followUpToggle.setSelected(true); - }); - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); - } + handleTagEvent(evt, () -> { + Platform.runLater(() -> { + followUpImageView.setImage(followUpIcon); + followUpToggle.setSelected(true); + }); }); } @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { + handleTagEvent(evt, this::updateFollowUpIcon); + } + void handleTagEvent(TagEvent evt, Runnable runnable) { getFileID().ifPresent(fileID -> { try { - if (fileID == evt.getDeletedTag().getContent().getId() - && evt.getDeletedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { - updateFollowUpIcon(); + final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); + final ContentTag deletedTag = evt.getTag(); + + if (fileID == deletedTag.getContent().getId() + && deletedTag.getName().equals(followUpTagName)) { + runnable.run(); } } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + LOGGER.log(Level.SEVERE, "Failed to get followup tag name. Unable to update follow up status for file. ", ex); } }); + } private void updateFollowUpIcon() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index d89db4116c..780513d16a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -46,10 +46,12 @@ import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.events.TagEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; /** @@ -197,19 +199,24 @@ public class MetaDataPane extends DrawableUIBase { @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { - handleTagChanged(evt.getAddedTag().getContent().getId()); + handleTagEvent(evt, this::updateUI); } @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - handleTagChanged(evt.getDeletedTag().getContent().getId()); + handleTagEvent(evt, this::updateUI); } - private void handleTagChanged(Long tagFileID) { + /** + * + * @param tagFileID the value of tagEvent + * @param runnable the value of runnable + */ + void handleTagEvent(TagEvent tagEvent, final Runnable runnable) { getFileID().ifPresent(fileID -> { - if (Objects.equals(tagFileID, fileID)) { - updateUI(); + if (Objects.equals(tagEvent.getTag().getContent().getId(), fileID)) { + runnable.run(); } }); } From 05cefa388aca1bb042f3aa020a4d89b45df829f3 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:22:14 -0400 Subject: [PATCH 076/198] move DrawableView and GroupPane to a new package --- .../ImageGalleryTopComponent.java | 4 +- .../autopsy/imagegallery/gui/GroupView.java | 8 --- .../gui/{ => drawableviews}/DrawableTile.fxml | 0 .../gui/{ => drawableviews}/DrawableTile.java | 5 +- .../{ => drawableviews}/DrawableTileBase.java | 2 +- .../{ => drawableviews}/DrawableUIBase.java | 2 +- .../gui/{ => drawableviews}/DrawableView.java | 2 +- .../gui/{ => drawableviews}/GroupPane.fxml | 0 .../gui/{ => drawableviews}/GroupPane.java | 6 +- .../gui/{ => drawableviews}/MetaDataPane.fxml | 0 .../gui/{ => drawableviews}/MetaDataPane.java | 32 +++++----- .../gui/{ => drawableviews}/SlideShow.fxml | 0 .../{ => drawableviews}/SlideShowView.java | 63 ++++++++++--------- 13 files changed, 62 insertions(+), 62 deletions(-) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupView.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableTile.fxml (100%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableTile.java (95%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableTileBase.java (99%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableUIBase.java (97%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableView.java (98%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/GroupPane.fxml (100%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/GroupPane.java (99%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/MetaDataPane.fxml (100%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/MetaDataPane.java (98%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/SlideShow.fxml (100%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/SlideShowView.java (95%) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java index 850230cb88..658e523be9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java @@ -35,8 +35,8 @@ import org.openide.windows.Mode; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.gui.GroupPane; -import org.sleuthkit.autopsy.imagegallery.gui.MetaDataPane; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.GroupPane; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.MetaDataPane; import org.sleuthkit.autopsy.imagegallery.gui.StatusBar; import org.sleuthkit.autopsy.imagegallery.gui.SummaryTablePane; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupView.java deleted file mode 100644 index 73d2f3373c..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupView.java +++ /dev/null @@ -1,8 +0,0 @@ - -package org.sleuthkit.autopsy.imagegallery.gui; - - - -public interface GroupView { - -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml similarity index 100% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.fxml rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.java similarity index 95% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.java index 86a0b2ddee..86eed0a814 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import java.util.Objects; import java.util.logging.Level; @@ -32,7 +32,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableTileBase.globalSelectionModel; +import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; +import static org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableTileBase.globalSelectionModel; import org.sleuthkit.datamodel.AbstractContent; /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java similarity index 99% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index 428bd0b5f4..ed12891589 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.eventbus.Subscribe; import java.util.ArrayList; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java similarity index 97% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java index ec794eabae..0657385aff 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import java.util.Objects; import static java.util.Objects.nonNull; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java similarity index 98% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java index 709679173e..6b9a532e86 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java @@ -1,4 +1,4 @@ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.eventbus.Subscribe; import java.util.Collection; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml similarity index 100% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.fxml rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java similarity index 99% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 09042abaf4..266b578f46 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -16,8 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.SlideShowView; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableTile; import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.Arrays; @@ -116,6 +118,8 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewMode; import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils; +import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.fxml similarity index 100% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.fxml rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.fxml diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java similarity index 98% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index 780513d16a..4814357a68 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.eventbus.Subscribe; import java.io.IOException; @@ -76,6 +76,20 @@ public class MetaDataPane extends DrawableUIBase { @FXML private BorderPane imageBorder; + public MetaDataPane(ImageGalleryController controller) { + super(controller); + + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MetaDataPane.fxml")); + fxmlLoader.setRoot(this); + fxmlLoader.setController(this); + + try { + fxmlLoader.load(); + } catch (IOException exception) { + throw new RuntimeException(exception); + } + } + @FXML @SuppressWarnings("unchecked") void initialize() { @@ -137,7 +151,7 @@ public class MetaDataPane extends DrawableUIBase { } @Override - synchronized protected void setFileHelper(Long newFileID) { + protected synchronized void setFileHelper(Long newFileID) { setFileIDOpt(Optional.ofNullable(newFileID)); if (newFileID == null) { Platform.runLater(() -> { @@ -151,20 +165,6 @@ public class MetaDataPane extends DrawableUIBase { } } - public MetaDataPane(ImageGalleryController controller) { - super(controller); - - FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MetaDataPane.fxml")); - fxmlLoader.setRoot(this); - fxmlLoader.setController(this); - - try { - fxmlLoader.load(); - } catch (IOException exception) { - throw new RuntimeException(exception); - } - } - public void updateUI() { getFile().ifPresent(file -> { final Image icon = file.getThumbnail(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShow.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml similarity index 100% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShow.fxml rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java similarity index 95% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java index d7d0f684ed..2b29e57d39 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import java.util.ArrayList; import java.util.function.Function; @@ -58,13 +58,16 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.ImageFile; import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.CAT_BORDER_WIDTH; +import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils; +import org.sleuthkit.autopsy.imagegallery.gui.MediaControl; +import static org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableView.CAT_BORDER_WIDTH; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** * Displays the files of a group one at a time. Designed to be embedded in a * GroupPane. TODO: Extract a subclass for video files in slideshow mode-jm + * * TODO: reduce coupling to GroupPane */ public class SlideShowView extends DrawableTileBase { @@ -73,40 +76,36 @@ public class SlideShowView extends DrawableTileBase { @FXML private ToggleButton cat0Toggle; - + @FXML + private ToggleButton cat1Toggle; @FXML private ToggleButton cat2Toggle; + @FXML + private ToggleButton cat3Toggle; + @FXML + private ToggleButton cat4Toggle; + @FXML + private ToggleButton cat5Toggle; @FXML private SplitMenuButton tagSplitButton; - @FXML - private ToggleButton cat3Toggle; - @FXML private Region spring; - @FXML private Button leftButton; - - @FXML - private ToggleButton cat4Toggle; - - @FXML - private ToggleButton cat5Toggle; - - @FXML - private ToggleButton cat1Toggle; - @FXML private Button rightButton; - @FXML private ToolBar toolBar; - @FXML private BorderPane footer; + SlideShowView(GroupPane gp) { + super(gp); + FXMLConstructor.construct(this, "SlideShow.fxml"); + } + @FXML @Override protected void initialize() { @@ -145,6 +144,8 @@ public class SlideShowView extends DrawableTileBase { tagSplitButton.getItems().setAll(selTagMenues); } }); + + //configure category toggles cat0Toggle.setBorder(new Border(new BorderStroke(Category.ZERO.getColor(), BorderStrokeStyle.SOLID, new CornerRadii(1), new BorderWidths(1)))); cat1Toggle.setBorder(new Border(new BorderStroke(Category.ONE.getColor(), BorderStrokeStyle.SOLID, new CornerRadii(1), new BorderWidths(1)))); cat2Toggle.setBorder(new Border(new BorderStroke(Category.TWO.getColor(), BorderStrokeStyle.SOLID, new CornerRadii(1), new BorderWidths(1)))); @@ -176,9 +177,7 @@ public class SlideShowView extends DrawableTileBase { //set up key listener equivalents of buttons addEventFilter(KeyEvent.KEY_PRESSED, (KeyEvent t) -> { - if (t.getEventType() == KeyEvent.KEY_PRESSED) { - switch (t.getCode()) { case LEFT: cycleSlideShowImage(-1); @@ -220,20 +219,14 @@ public class SlideShowView extends DrawableTileBase { } } - SlideShowView(GroupPane gp) { - super(gp); - - FXMLConstructor.construct(this, "SlideShow.fxml"); - - } - - @ThreadConfined(type = ThreadType.UI) + @ThreadConfined(type = ThreadType.JFX) public void stopVideo() { if (imageBorder.getCenter() instanceof MediaControl) { ((MediaControl) imageBorder.getCenter()).stopVideo(); } } + /** {@inheritDoc } */ @Override synchronized public void setFile(final Long fileID) { super.setFile(fileID); @@ -255,6 +248,7 @@ public class SlideShowView extends DrawableTileBase { imageBorder.setCenter(null); } + /** {@inheritDoc } */ @Override protected Runnable getContentUpdateRunnable() { @@ -281,11 +275,20 @@ public class SlideShowView extends DrawableTileBase { }); } + /** {@inheritDoc } */ @Override protected String getTextForLabel() { return getFile().map(file -> file.getName()).orElse("") + " " + getSupplementalText(); } + /** + * cycle the image displayed in thes SlideShowview, to the next/previous one + * in the group. + * + * @param direction the direction to cycle: + * -1 => left / back + * 1 => right / forward + */ @ThreadConfined(type = ThreadType.JFX) private void cycleSlideShowImage(int direction) { stopVideo(); @@ -296,7 +299,6 @@ public class SlideShowView extends DrawableTileBase { }).orElse(0); setFile(getGroupPane().getGrouping().fileIds().get(nextIndex) ); - } /** @@ -310,6 +312,7 @@ public class SlideShowView extends DrawableTileBase { } + /** {@inheritDoc } */ @Override @ThreadConfined(type = ThreadType.ANY) public Category updateCategory() { From e21ad201ffe75e03acd71f85c32ca42b70e7c911 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:23:36 -0400 Subject: [PATCH 077/198] remove unneeded interface --- .../imagegallery/gui/drawableviews/GroupPane.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 266b578f46..b95e5d51f6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -18,8 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; -import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.SlideShowView; -import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableTile; import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.Arrays; @@ -102,7 +100,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.directorytree.ExtractAction; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -130,13 +127,13 @@ import org.sleuthkit.datamodel.TskCoreException; * * * TODO: Extract the The GridView instance to a separate class analogous to the - * SlideShow. Move selection model into controlsfx GridView and submit pull + * SlideShow. + * + * TODO: Move selection model into controlsfx GridView and submit pull * request to them. * https://bitbucket.org/controlsfx/controlsfx/issue/4/add-a-multipleselectionmodel-to-gridview - * - * */ -public class GroupPane extends BorderPane implements GroupView { +public class GroupPane extends BorderPane { private static final Logger LOGGER = Logger.getLogger(GroupPane.class.getName()); From 567abf79483bf7da38fd1280b684f11f1a4a8ccb Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:42:48 -0400 Subject: [PATCH 078/198] move classes to better packages; remove FileUpdateEvent --- .../autopsy/imagegallery/FileUpdateEvent.java | 93 ------------------- .../imagegallery/ImageGalleryController.java | 5 +- .../imagegallery/actions/AddTagAction.java | 2 +- .../actions/CategorizeAction.java | 2 +- .../actions/DeleteFollowUpTagAction.java | 2 +- .../imagegallery/actions/NextUnseenGroup.java | 2 +- .../datamodel/CategoryChangeEvent.java | 50 ---------- .../datamodel/CategoryManager.java | 34 ++++++- .../imagegallery/datamodel/DrawableDB.java | 39 ++------ .../{ => datamodel}/DrawableTagsManager.java | 3 +- .../datamodel/HashSetManager.java | 1 + .../grouping/DrawableGroup.java | 2 +- .../{ => datamodel}/grouping/GroupKey.java | 2 +- .../grouping/GroupManager.java | 30 ++---- .../{ => datamodel}/grouping/GroupSortBy.java | 2 +- .../datamodel/grouping/GroupViewMode.java | 7 ++ .../grouping/GroupViewState.java | 2 +- .../imagegallery/grouping/GroupViewMode.java | 7 -- .../imagegallery/gui/SortByListCell.java | 2 +- .../imagegallery/gui/SummaryTablePane.java | 3 +- .../autopsy/imagegallery/gui/Toolbar.java | 4 +- .../gui/drawableviews/DrawableView.java | 3 +- .../gui/drawableviews/GroupPane.java | 6 +- .../gui/drawableviews/MetaDataPane.java | 4 +- .../gui/navpanel/GroupTreeCell.java | 2 +- .../gui/navpanel/GroupTreeItem.java | 2 +- .../imagegallery/gui/navpanel/NavPanel.java | 4 +- .../imagegallery/gui/navpanel/TreeNode.java | 2 +- 28 files changed, 88 insertions(+), 229 deletions(-) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/DrawableTagsManager.java (98%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/DrawableGroup.java (98%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/GroupKey.java (97%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/GroupManager.java (96%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/GroupSortBy.java (99%) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewMode.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/GroupViewState.java (97%) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewMode.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java deleted file mode 100644 index c2803a5090..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery; - -import java.util.Collection; -import java.util.Collections; -import java.util.EventListener; -import java.util.HashSet; -import java.util.Set; -import javax.annotation.concurrent.Immutable; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; - -/** represents a change in the database for one or more files. */ -@Immutable -public class FileUpdateEvent { - - /** the obj_ids of affected files */ - private final Set fileIDs; - - /** the attribute that was modified */ - private final DrawableAttribute changedAttribute; - - /** the type of update ( updated/removed) */ - private final UpdateType updateType; - - public UpdateType getUpdateType() { - return updateType; - } - - public Collection getFileIDs() { - return Collections.unmodifiableCollection(fileIDs); - } - - public DrawableAttribute getChangedAttribute() { - return changedAttribute; - } - - public static FileUpdateEvent newRemovedEvent(Collection updatedFiles) { - return new FileUpdateEvent(updatedFiles, UpdateType.REMOVE, null); - } - - /** - * - * @param updatedFiles the files that have been added or changed in the - * database - * @param changedAttribute the attribute that was changed for the files, or - * null if this represents new files - * - * @return a new FileUpdateEvent - */ - public static FileUpdateEvent newUpdateEvent(Collection updatedFiles, DrawableAttribute changedAttribute) { - return new FileUpdateEvent(updatedFiles, UpdateType.UPDATE, changedAttribute); - } - - private FileUpdateEvent(Collection updatedFiles, UpdateType updateType, DrawableAttribute changedAttribute) { - this.fileIDs = new HashSet<>(updatedFiles); - this.updateType = updateType; - this.changedAttribute = changedAttribute; - } - - static public enum UpdateType { - - /** files have been added or updated in the db */ - UPDATE, - /** files have been removed - * from the db */ - REMOVE; - } - - /** Interface for listening to FileUpdateEvents */ - public static interface FileUpdateListener extends EventListener { - - public void handleFileUpdate(FileUpdateEvent evt); - - public void handleFileRemoved(FileUpdateEvent evt); - } -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 820e70e0e5..178c9dd725 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import java.beans.PropertyChangeEvent; import java.util.ArrayList; import java.util.List; @@ -63,8 +64,8 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 1383cdcd8c..49c1e2951f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -31,7 +31,7 @@ import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.datamodel.TagName; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index afe2b3bb5d..518a49b87a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -28,7 +28,7 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 934a3fb258..fb729807c0 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -24,7 +24,7 @@ import javafx.event.ActionEvent; import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.ContentTag; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java index 550581d8b2..6a68810457 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java @@ -28,7 +28,7 @@ import javafx.scene.image.ImageView; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; /** * Marks the currently fisplayed group as "seen" and advances to the next unseen diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java deleted file mode 100644 index 3868864737..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery.datamodel; - -import java.util.Collection; -import java.util.Collections; -import javax.annotation.concurrent.Immutable; - -/** - * Event broadcast to various UI componenets when one or more files' category - * has been changed - */ -@Immutable -public class CategoryChangeEvent { - - private final Collection fileIDs; - private final Category newCategory; - - public CategoryChangeEvent(Collection fileIDs, Category newCategory) { - this.fileIDs = fileIDs; - this.newCategory = newCategory; - } - - public Category getNewCategory() { - return newCategory; - } - - /** - * @return the fileIDs of the files whose categories have changed - */ - public Collection getFileIDs() { - return Collections.unmodifiableCollection(fileIDs); - } -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 309173f153..f84f759d37 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -27,11 +27,13 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; +import javax.annotation.concurrent.Immutable; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -254,6 +256,7 @@ public class CategoryManager { fireChange(Collections.singleton(addedTag.getContent().getId()), newCat); } } + @Subscribe public void handleTagDeleted(ContentTagDeletedEvent event) { ContentTag deleted = event.getTag(); @@ -266,4 +269,33 @@ public class CategoryManager { fireChange(Collections.singleton(deleted.getContent().getId()), null); } } + + /** + * Event broadcast to various UI componenets when one or more files' + * category + * has been changed + */ + @Immutable + public static class CategoryChangeEvent { + + private final Collection fileIDs; + private final Category newCategory; + + public CategoryChangeEvent(Collection fileIDs, Category newCategory) { + super(); + this.fileIDs = fileIDs; + this.newCategory = newCategory; + } + + public Category getNewCategory() { + return newCategory; + } + + /** + * @return the fileIDs of the files whose categories have changed + */ + public Collection getFileIDs() { + return Collections.unmodifiableCollection(fileIDs); + } + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 9dfbbdc239..87fa001827 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -46,13 +46,12 @@ import org.apache.commons.lang3.StringUtils; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupSortBy; -import static org.sleuthkit.autopsy.imagegallery.grouping.GroupSortBy.GROUP_BY_VALUE; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupKey; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy; +import static org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy.GROUP_BY_VALUE; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -125,11 +124,6 @@ public final class DrawableDB { */ private final Map, PreparedStatement> groupStatementMap = new HashMap<>(); - /** - * list of observers to be notified if the database changes - */ - private final HashSet updateListeners = new HashSet<>(); - private GroupManager groupManager; private final Path dbPath; @@ -201,6 +195,7 @@ public final class DrawableDB { this.dbPath = dbPath; this.controller = controller; this.tskCase = controller.getSleuthKitCase(); + this.groupManager = controller.getGroupManager(); Files.createDirectories(dbPath.getParent()); if (initializeDBSchema()) { updateFileStmt = prepareStatement( @@ -644,22 +639,6 @@ public final class DrawableDB { tr.commit(notify); } - public void addUpdatedFileListener(FileUpdateEvent.FileUpdateListener l) { - updateListeners.add(l); - } - - private void fireUpdatedFiles(Collection fileIDs) { - for (FileUpdateEvent.FileUpdateListener listener : updateListeners) { - listener.handleFileUpdate(FileUpdateEvent.newUpdateEvent(fileIDs, null)); - } - } - - private void fireRemovedFiles(Collection fileIDs) { - for (FileUpdateEvent.FileUpdateListener listener : updateListeners) { - listener.handleFileRemoved(FileUpdateEvent.newRemovedEvent(fileIDs)); - } - } - public Boolean isFileAnalyzed(DrawableFile f) { return isFileAnalyzed(f.getId()); } @@ -1149,7 +1128,7 @@ public final class DrawableDB { * in the drawable db? */ @Nonnull - Set getHashSetsForFile(long fileID) { + public Set getHashSetsForFile(long fileID) { try { Set hashNames = new HashSet<>(); List arts = tskCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, fileID); @@ -1312,8 +1291,10 @@ public final class DrawableDB { close(); if (notify) { - fireUpdatedFiles(updatedFiles); - fireRemovedFiles(removedFiles); + if (groupManager != null) { + groupManager.handleFileUpdate(updatedFiles); + groupManager.handleFileRemoved(removedFiles); + } } } catch (SQLException ex) { if (Case.isCaseOpen()) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java similarity index 98% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index 0bbc4b9d5a..57d7152967 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery; +package org.sleuthkit.autopsy.imagegallery.datamodel; import com.google.common.eventbus.EventBus; import java.util.Collection; @@ -30,7 +30,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java index 1ca547c81e..1071a6ee0a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java @@ -4,6 +4,7 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.util.Set; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; /** * Manages a cache of hashset hits as a map from fileID to hashset names. diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java similarity index 98% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java index 0ad8b2640e..ac0493d75e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import java.util.Objects; import java.util.Set; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupKey.java similarity index 97% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupKey.java index cd41534078..ce64bebaa3 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupKey.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import java.util.Map; import java.util.Objects; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java similarity index 96% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index d7819c6d5e..ad99d94407 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import com.google.common.eventbus.Subscribe; import java.sql.ResultSet; @@ -50,7 +50,6 @@ import javax.annotation.concurrent.GuardedBy; import javax.swing.SortOrder; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; @@ -62,8 +61,6 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; @@ -71,6 +68,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -84,7 +82,7 @@ import org.sleuthkit.datamodel.TskCoreException; * extent {@link SleuthkitCase} ) to facilitate creation, retrieval, updating, * and sorting of {@link DrawableGroup}s. */ -public class GroupManager implements FileUpdateEvent.FileUpdateListener { +public class GroupManager { private static final Logger LOGGER = Logger.getLogger(GroupManager.class.getName()); @@ -123,7 +121,6 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public void setDB(DrawableDB db) { this.db = db; - db.addUpdatedFileListener(this); regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); } @@ -575,11 +572,10 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { DrawableGroup g = removeFromGroup(groupKey, fileID); } - @Override - synchronized public void handleFileRemoved(FileUpdateEvent evt) { - Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.REMOVE); + @Subscribe + synchronized public void handleFileRemoved(Collection removedFileIDs) { - for (final long fileId : evt.getFileIDs()) { + for (final long fileId : removedFileIDs) { //get grouping(s) this file would be in Set> groupsForFile = getGroupKeysForFileID(fileId); @@ -595,17 +591,15 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * * @param evt */ - @Override - synchronized public void handleFileUpdate(FileUpdateEvent evt) { - Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.UPDATE); - Collection fileIDs = evt.getFileIDs(); + @Subscribe + synchronized public void handleFileUpdate(Collection updatedFileIDs) { /** * TODO: is there a way to optimize this to avoid quering to db * so much. the problem is that as a new files are analyzed they * might be in new groups( if we are grouping by say make or * model) -jm */ - for (long fileId : fileIDs) { + for (long fileId : updatedFileIDs) { controller.getHashSetManager().invalidateHashSetsForFile(fileId); @@ -618,11 +612,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } //we fire this event for all files so that the category counts get updated during initial db population - controller.getCategoryManager().fireChange(fileIDs, null); - -// if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { -// controller.getTagsManager().fireChange(fileIDs); -// } + controller.getCategoryManager().fireChange(updatedFileIDs, null); } private DrawableGroup popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupSortBy.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java similarity index 99% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupSortBy.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java index fa2b3e88d0..a7bdbb342e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupSortBy.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import java.util.Arrays; import java.util.Comparator; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewMode.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewMode.java new file mode 100644 index 0000000000..17a970ca13 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewMode.java @@ -0,0 +1,7 @@ +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; + +public enum GroupViewMode { + + TILE, SLIDE_SHOW + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewState.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewState.java similarity index 97% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewState.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewState.java index 4d4905a80a..86679340ab 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewState.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewState.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import java.util.Objects; import java.util.Optional; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewMode.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewMode.java deleted file mode 100644 index 5506223429..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewMode.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.sleuthkit.autopsy.imagegallery.grouping; - -public enum GroupViewMode { - - TILE, SLIDE_SHOW - -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortByListCell.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortByListCell.java index 22985ff341..c9845fff3a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortByListCell.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortByListCell.java @@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.imagegallery.gui; import javafx.scene.control.ListCell; import javafx.scene.image.ImageView; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupSortBy; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy; public class SortByListCell extends ListCell { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java index 955cf0760f..6fe4ce9b44 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java @@ -36,7 +36,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; /** * Displays summary statistics (counts) for each group @@ -88,7 +87,7 @@ public class SummaryTablePane extends AnchorPane { * listen to Category updates and rebuild the table */ @Subscribe - public void handleCategoryChanged(CategoryChangeEvent evt) { + public void handleCategoryChanged(org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager.CategoryChangeEvent evt) { final ObservableList> data = FXCollections.observableArrayList(); if (Case.isCaseOpen()) { for (Category cat : Category.values()) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index 2131ff73fc..33083c45b4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -41,7 +41,7 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javax.swing.SortOrder; import org.openide.util.Exceptions; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -49,7 +49,7 @@ import org.sleuthkit.autopsy.imagegallery.ThumbnailCache; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupSortBy; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java index 6b9a532e86..4d7f31a52a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java @@ -18,7 +18,6 @@ import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -68,7 +67,7 @@ public interface DrawableView { * @param evt the CategoryChangeEvent to handle */ @Subscribe - default void handleCategoryChanged(CategoryChangeEvent evt) { + default void handleCategoryChanged(org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager.CategoryChangeEvent evt) { getFileID().ifPresent(fileID -> { if (evt.getFileIDs().contains(fileID)) { updateCategory(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index b95e5d51f6..4c2a056d46 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -112,9 +112,9 @@ import org.sleuthkit.autopsy.imagegallery.actions.NextUnseenGroup; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewMode; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewMode; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.datamodel.TagName; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index 4814357a68..5ebc6c1984 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -49,8 +49,8 @@ import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.events.TagEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -188,7 +188,7 @@ public class MetaDataPane extends DrawableUIBase { /** {@inheritDoc } */ @Subscribe @Override - public void handleCategoryChanged(CategoryChangeEvent evt) { + public void handleCategoryChanged(CategoryManager.CategoryChangeEvent evt) { getFileID().ifPresent(fileID -> { if (evt.getFileIDs().contains(fileID)) { updateUI(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java index 5deaf88aa8..8103a55cf6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java @@ -31,7 +31,7 @@ import javafx.scene.image.ImageView; import javax.annotation.Nonnull; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; /** * A cell in the NavPanel tree that listens to its associated group's fileids diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java index 37925b47bb..3bd5ff72bf 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java @@ -27,7 +27,7 @@ import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.scene.control.TreeItem; import org.apache.commons.lang3.StringUtils; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; /** * A node in the nav/hash tree. Manages inserts and removals. Has parents and diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java index efc855e8ca..64aa5a681e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java @@ -45,8 +45,8 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; /** * Display two trees. one shows all folders (groups) and calls out folders with diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/TreeNode.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/TreeNode.java index 0c7b2c2806..b230409075 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/TreeNode.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/TreeNode.java @@ -18,7 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.gui.navpanel; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; /** * From 1c16f9e4051471fe4f1fa75eada839f722b6a46d Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 16:42:44 -0400 Subject: [PATCH 079/198] better handling of exceptions in event bus eventhandlers --- .../datamodel/CategoryManager.java | 11 ++++++-- .../datamodel/DrawableTagsManager.java | 18 ++++++++---- .../datamodel/grouping/GroupManager.java | 28 +++++++++++-------- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index f84f759d37..31be08e71a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -20,20 +20,21 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.google.common.eventbus.AsyncEventBus; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.concurrent.Executors; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import javax.annotation.concurrent.Immutable; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -66,7 +67,11 @@ public class CategoryManager { /** * Used to distribute {@link CategoryChangeEvent}s */ - private final EventBus categoryEventBus = new EventBus("Category Event Bus"); + private final EventBus categoryEventBus = new AsyncEventBus(Executors.newSingleThreadExecutor( + new BasicThreadFactory.Builder().namingPattern("Category Event Bus").uncaughtExceptionHandler((Thread t, Throwable e) -> { + LOGGER.log(Level.SEVERE, "uncaught exception in event bus handler", e); + }).build() + )); /** * For performance reasons, keep current category counts in memory. All of diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index 57d7152967..af5a0ebced 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -18,19 +18,20 @@ */ package org.sleuthkit.autopsy.imagegallery.datamodel; +import com.google.common.eventbus.AsyncEventBus; import com.google.common.eventbus.EventBus; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -42,13 +43,20 @@ import org.sleuthkit.datamodel.TskCoreException; */ public class DrawableTagsManager { + private static final Logger LOGGER = Logger.getLogger(DrawableTagsManager.class.getName()); + private static final String FOLLOW_UP = "Follow Up"; final private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; /** Used to distribute {@link TagsChangeEvent}s */ - private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); + private final EventBus tagsEventBus = new AsyncEventBus( + Executors.newSingleThreadExecutor( + new BasicThreadFactory.Builder().namingPattern("Tags Event Bus").uncaughtExceptionHandler((Thread t, Throwable e) -> { + LOGGER.log(Level.SEVERE, "uncaught exception in event bus handler", e); + }).build() + )); /** The tag name corresponding to the "built-in" tag "Follow Up" */ private TagName followUpTagName; @@ -130,7 +138,7 @@ public class DrawableTagsManager { .filter(CategoryManager::isCategoryTagName) .collect(Collectors.toSet()); } catch (TskCoreException | IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + LOGGER.log(Level.WARNING, "couldn't access case", ex); } return Collections.emptySet(); } @@ -166,7 +174,7 @@ public class DrawableTagsManager { throw new TskCoreException("tagame exists but wasn't found", ex); } } catch (IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); + LOGGER.log(Level.SEVERE, "Case was closed out from underneath", ex); throw new TskCoreException("Case was closed out from underneath", ex); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index ad99d94407..dc27ac136b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -537,15 +537,16 @@ public class GroupManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { GroupKey groupKey = null; - if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); - } else if (groupBy == DrawableAttribute.CATEGORY) { + if (groupBy == DrawableAttribute.CATEGORY && CategoryManager.isCategoryTagName(evt.getTag().getName())) { groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); + } + if (groupKey != null) { + final long fileID = evt.getTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); } - final long fileID = evt.getTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); - } @SuppressWarnings("AssignmentToMethodParameter") @@ -563,13 +564,16 @@ public class GroupManager { @Subscribe public void handleTagDeleted(ContentTagDeletedEvent evt) { GroupKey groupKey = null; - if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); - } else if (groupBy == DrawableAttribute.CATEGORY) { + if (groupBy == DrawableAttribute.CATEGORY && CategoryManager.isCategoryTagName(evt.getTag().getName())) { groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); + } + + if (groupKey != null) { + final long fileID = evt.getTag().getContent().getId(); + DrawableGroup g = removeFromGroup(groupKey, fileID); } - final long fileID = evt.getTag().getContent().getId(); - DrawableGroup g = removeFromGroup(groupKey, fileID); } @Subscribe From 85ea8bc90d75d8fe826816a761c66ea6f62559c0 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Tue, 23 Jun 2015 09:16:23 -0400 Subject: [PATCH 080/198] update_versions.py does not execute if javadoc cannot be executed --- update_versions.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/update_versions.py b/update_versions.py index 507419d688..58f3a74a43 100755 --- a/update_versions.py +++ b/update_versions.py @@ -218,10 +218,15 @@ def compare_xml(module, apiname_tag, apiname_cur): "-newapi", newapi, "-script", null_file] - jdiff = subprocess.Popen(cmd, stdout=log, stderr=log) - jdiff.wait() + try: + jdiff = subprocess.Popen(cmd, stdout=log, stderr=log) + jdiff.wait() + code = jdiff.returncode + except Exception: + printt("Javadoc not found. Exiting...") + exit(1) log.close() - code = jdiff.returncode + print("Compared XML for " + module.name) if code == NO_CHANGES: print(" No API changes") @@ -257,8 +262,12 @@ def gen_xml(path, modules, name): "-apiname", xml_out, # leaving it in just in case it's needed once again "-sourcepath", fix_path(src)] cmd = cmd + get_packages(src) - jdiff = subprocess.Popen(cmd, stdout=log, stderr=log) - jdiff.wait() + try: + jdiff = subprocess.Popen(cmd, stdout=log, stderr=log) + jdiff.wait() + except Exception: + printt("Javadoc not found. Exiting...") + exit(1) log.close() print("Generated XML for " + name + " " + module.name) sys.stdout.flush() @@ -633,16 +642,16 @@ def print_version_updates(modules): output = (module.name + ":\n") output += ("\tMajor Release:\tNo Change.\n") output += ("\tSpecification:\t" + str(versions[0]) + "\t->\t" + str(versions[0].increment()) + "\n") - output += ("\tImplementation:\t" + str(versions[1]) + "\t->\t" + str(versions[1] + 1) + "\n") + output += ("\tImplementation:\t" + str(versions[1]) + "\t->\t" + str(float(versions[1]) + 1) + "\n") output += ("\n") print(output) sys.stdout.flush() f.write(output) elif module.ret == NON_COMPATIBLE: output = (module.name + ":\n") - output += ("\Major Release:\t" + str(versions[2]) + "\t->\t" + str(versions[2] + 1) + "\n") + output += ("\Major Release:\t" + str(versions[2]) + "\t->\t" + str(float(versions[2]) + 1) + "\n") output += ("\tSpecification:\t" + str(versions[0]) + "\t->\t" + str(versions[0].overflow()) + "\n") - output += ("\tImplementation:\t" + str(versions[1]) + "\t->\t" + str(versions[1] + 1) + "\n") + output += ("\tImplementation:\t" + str(versions[1]) + "\t->\t" + str(float(versions[1]) + 1) + "\n") output += ("\n") print(output) sys.stdout.flush() @@ -662,7 +671,7 @@ def print_version_updates(modules): if versions[1] is None: output += ("\tImplementation: None\n") else: - output += ("\tImplementation:\t" + str(versions[1]) + "\t->\t" + str(versions[1] + 1) + "\n") + output += ("\tImplementation:\t" + str(versions[1]) + "\t->\t" + str(float(versions[1]) + 1) + "\n") output += ("\n") print(output) sys.stdout.flush() From 4b1ba5925748d23c5c4a91dbb886e4f96a770d12 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Tue, 23 Jun 2015 09:38:22 -0400 Subject: [PATCH 081/198] early exit if jdiff or javadoc not found --- update_versions.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/update_versions.py b/update_versions.py index 58f3a74a43..d7d7951b5e 100755 --- a/update_versions.py +++ b/update_versions.py @@ -223,7 +223,7 @@ def compare_xml(module, apiname_tag, apiname_cur): jdiff.wait() code = jdiff.returncode except Exception: - printt("Javadoc not found. Exiting...") + printt("Error executing javadoc. Exiting...") exit(1) log.close() @@ -266,7 +266,7 @@ def gen_xml(path, modules, name): jdiff = subprocess.Popen(cmd, stdout=log, stderr=log) jdiff.wait() except Exception: - printt("Javadoc not found. Exiting...") + printt("Error executing javadoc. Exiting...") exit(1) log.close() print("Generated XML for " + name + " " + module.name) @@ -860,6 +860,16 @@ def main(): return 0 printinfo() + # Check if javadoc and jdiff are present. + jdiff = fix_path(os.path.abspath("./thirdparty/jdiff/v-custom/jdiff.jar")) + if(not os.path.isdir(jdiff)): + printt("jdiff not found. Exiting...") + return 1 + try: + subprocess.call(["javadoc"], stdout=open(os.devnull, "w"), stderr=subprocess.STDOUT) + except Exception: + printt("javadoc not found. Exiting...") + return 1 # ----------------------------------------------- # 1) Clone Autopsy, checkout to given tag/commit # 2) Get the modules in the clone and the source From 0f47400d3a06e56645e2b5c48202da2af7d551ed Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Tue, 23 Jun 2015 10:30:33 -0400 Subject: [PATCH 082/198] Hand copied changes from collab branch to this branch. Did not copy the time out terminator because that is not in tdevelop yet. --- .../modules/photoreccarver/Bundle.properties | 14 +++-- .../PhotoRecCarverFileIngestModule.java | 52 +++++++++++-------- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties index b9a9d6c609..41acbcf61d 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/Bundle.properties @@ -3,10 +3,14 @@ OpenIDE-Module-Display-Category=Ingest Module OpenIDE-Module-Long-Description=PhotoRec Carver ingest module. \n\n Carves unallocated space and feeds the resulting carved files back into the system for processing. OpenIDE-Module-Short-Description=Carves unallocated space and feeds carved files back into the system for processing. moduleDisplayName.text=PhotoRec Carver -moduleDescription.text=Runs PhotoRec carver against unallocated space on the system. +moduleDescription.text=Runs PhotoRec carver against unallocated space in the data source. -unallocatedSpaceProcessingSettingsError.message="Process Unallocated Space" is not checked. This module is designed to carve unallocated space. Either allow processing of unallocated space, or do not use this module. -unsupportedOS.message=Module is not supported for other than Windows platforms -missingExecutable.message=Unable to locate unallocated carver executable. -cannotRunExecutable.message=Unable to execute unallocated carver +unallocatedSpaceProcessingSettingsError.message="Process Unallocated Space" is not checked. The PhotoRec module is designed to carve unallocated space. Either enable processing of unallocated space or disable this module. +unsupportedOS.message=PhotoRec Module is supported only on Windows platforms +missingExecutable.message=Unable to locate PhotoRec executable. +cannotRunExecutable.message=Unable to execute PhotoRec cannotCreateOutputDir.message=Unable to create output directory: {0} +PhotoRecIngestModule.processTerminated=PhotoRec Carver ingest module was terminated due to exceeding max allowable run time when scanning +PhotoRecIngestModule.moduleError=PhotoRec Carver Module Error +PhotoRecIngestModule.UnableToCarve=Unable to carve file: {0} +PhotoRecIngestModule.NotEnoughDiskSpace=Not enough disk space to save unallocated file. Carving will be skipped. \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java index ec4beae595..f168d20e84 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/photoreccarver/PhotoRecCarverFileIngestModule.java @@ -26,10 +26,10 @@ import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.text.SimpleDateFormat; -import java.util.Date; import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -38,12 +38,18 @@ import org.openide.modules.InstalledFileLocator; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.ExecUtil; +import org.sleuthkit.autopsy.coreutils.FileUtil; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.ingest.FileIngestModule; +import org.sleuthkit.autopsy.ingest.FileIngestModuleProcessTerminator; import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestModule; import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter; +import org.sleuthkit.autopsy.ingest.IngestServices; +import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Image; @@ -51,10 +57,6 @@ import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.Volume; -import org.sleuthkit.autopsy.coreutils.FileUtil; -import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.ingest.FileIngestModuleProcessTerminator; -import org.sleuthkit.autopsy.ingest.IngestServices; /** * A file ingest module that runs the Unallocated Carver executable with unallocated space files as input. @@ -74,6 +76,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { private IngestJobContext context; private Path rootOutputDirPath; private File executableFile; + private IngestServices services; /** * @inheritDoc @@ -81,6 +84,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { @Override public void startUp(IngestJobContext context) throws IngestModule.IngestModuleException { this.context = context; + this.services = IngestServices.getInstance(); // If the global unallocated space processing setting and the module // process unallocated space only setting are not in sych, throw an @@ -143,9 +147,15 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { // Check that we have roughly enough disk space left to complete the operation long freeDiskSpace = IngestServices.getInstance().getFreeDiskSpace(); - if ((file.getSize() * 2) > freeDiskSpace) { - logger.log(Level.SEVERE, "PhotoRec error processing {0} with {1} Not enough space on primary disk to carve unallocated space.", // NON-NLS + // Some network drives always return -1 for free disk space. + // In this case, expect enough space and move on. + + if ((freeDiskSpace != -1) && ((file.getSize() * 1.2) > freeDiskSpace)) { + logger.log(Level.SEVERE, "PhotoRec error processing {0} with {1} Not enough space on primary disk to save unallocated space.", // NON-NLS new Object[]{file.getName(), PhotoRecCarverIngestModuleFactory.getModuleName()}); // NON-NLS + MessageNotifyUtil.Notify.error(NbBundle.getMessage(this.getClass(), "PhotoRecIngestModule.UnableToCarve", file.getName()), + NbBundle.getMessage(this.getClass(), "PhotoRecIngestModule.NotEnoughDiskSpace")); + return IngestModule.ProcessResult.ERROR; } @@ -177,22 +187,12 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { if (this.context.fileIngestIsCancelled() == true) { // if it was cancelled by the user, result is OK - // cleanup the output path - FileUtil.deleteDir(new File(outputDirPath.toString())); - if (null != tempFilePath && Files.exists(tempFilePath)) { - tempFilePath.toFile().delete(); - } + cleanup(outputDirPath, tempFilePath); logger.log(Level.INFO, "PhotoRec cancelled by user"); // NON-NLS return IngestModule.ProcessResult.OK; - } - - else if (0 != exitValue) { + } else if (0 != exitValue) { // if it failed or was cancelled by timeout, result is ERROR - // cleanup the output path - FileUtil.deleteDir(new File(outputDirPath.toString())); - if (null != tempFilePath && Files.exists(tempFilePath)) { - tempFilePath.toFile().delete(); - } + cleanup(outputDirPath, tempFilePath); logger.log(Level.SEVERE, "PhotoRec carver returned error exit value = {0} when scanning {1}", // NON-NLS new Object[]{exitValue, file.getName()}); // NON-NLS return IngestModule.ProcessResult.ERROR; @@ -217,6 +217,7 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { List theList = parser.parse(newAuditFile, id, file); if (theList != null) { // if there were any results from carving, add the unallocated carving event to the reports list. context.addFilesToJob(new ArrayList<>(theList)); + services.fireModuleContentEvent(new ModuleContentEvent(theList.get(0))); // fire an event to update the tree } } catch (IOException ex) { @@ -233,6 +234,15 @@ final class PhotoRecCarverFileIngestModule implements FileIngestModule { return IngestModule.ProcessResult.OK; } + + private void cleanup(Path outputDirPath, Path tempFilePath) { + // cleanup the output path + FileUtil.deleteDir(new File(outputDirPath.toString())); + if (null != tempFilePath && Files.exists(tempFilePath)) { + tempFilePath.toFile().delete(); + } + } + /** * @inheritDoc From 880a5be15a5a77d7fc7777687f8cf62a20eef737 Mon Sep 17 00:00:00 2001 From: Sidhesh Mhatre Date: Tue, 23 Jun 2015 10:35:13 -0400 Subject: [PATCH 083/198] Update update_versions.py --- update_versions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update_versions.py b/update_versions.py index d7d7951b5e..2f96480556 100755 --- a/update_versions.py +++ b/update_versions.py @@ -868,7 +868,7 @@ def main(): try: subprocess.call(["javadoc"], stdout=open(os.devnull, "w"), stderr=subprocess.STDOUT) except Exception: - printt("javadoc not found. Exiting...") + printt("javadoc not found in path. Exiting...") return 1 # ----------------------------------------------- # 1) Clone Autopsy, checkout to given tag/commit From 964679ad9a4d0f52c99c896a150672317ca8327b Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 10:37:31 -0400 Subject: [PATCH 084/198] only prompt that the events db is out of date, when the timeline window is open --- .../autopsy/timeline/TimeLineController.java | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java index e57dddb509..2ebaba9d93 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/TimeLineController.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -257,7 +257,7 @@ public class TimeLineController { LOGGER.log(Level.INFO, "Beginning generation of timeline"); // NON-NLS try { SwingUtilities.invokeLater(() -> { - if (mainFrame != null) { + if (isWindowOpen()) { mainFrame.close(); } }); @@ -311,7 +311,8 @@ public class TimeLineController { } } - /** show the timeline window and prompt for rebuilding database */ + /** show the timeline window and prompt for rebuilding database if + * necessary. */ synchronized void openTimeLine() { // listen for case changes (specifically images being added, and case changes). @@ -636,12 +637,21 @@ public class TimeLineController { /** * prompt the user to rebuild and then rebuild if the user chooses to */ - synchronized public boolean outOfDatePromptAndRebuild() { + synchronized private boolean outOfDatePromptAndRebuild() { return showOutOfDateConfirmation() == JOptionPane.YES_OPTION ? rebuildRepo() : false; } + /** + * is the timeline window open. + * + * @return true if the timeline window is open + */ + synchronized private boolean isWindowOpen() { + return mainFrame != null && mainFrame.isOpened() && mainFrame.isVisible(); + } + synchronized int showLastPopulatedWhileIngestingConfirmation() { return JOptionPane.showConfirmDialog(mainFrame, DO_REPOPULATE_MESSAGE, @@ -703,7 +713,9 @@ public class TimeLineController { case CANCELLED: case COMPLETED: //if we are doing incremental updates, drop this - outOfDatePromptAndRebuild(); + if (isWindowOpen()) { + outOfDatePromptAndRebuild(); + } break; } } @@ -718,7 +730,9 @@ public class TimeLineController { case DATA_SOURCE_ADDED: // Content content = (Content) evt.getNewValue(); //if we are doing incremental updates, drop this - outOfDatePromptAndRebuild(); + if (isWindowOpen()) { + outOfDatePromptAndRebuild(); + } break; case CURRENT_CASE: OpenTimelineAction.invalidateController(); From dac18bf6da9f8dce69a4c357758fa1490f116052 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 13:17:53 -0400 Subject: [PATCH 085/198] fix npe by optionalizing getCachefile --- .../autopsy/imagegallery/ThumbnailCache.java | 71 +++++++++++-------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java index a9d3042e5b..2d60cc819e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java @@ -119,28 +119,29 @@ public enum ThumbnailCache { /** * load a thumbnail from the disk based cache for the given file, or - * generate and save a new thumnbail if one doesn't already exist + * generate and save a new thumbnail if one doesn't already exist * - * @param file the file to load a thumbnail of + * @param file the DrawableFile to load a thumbnail of * - * @return an optional containing a thumbnail, or null if a thumbnail - * couldn't be loaded or generated + * @return an (possibly empty) optional containing a thumbnail */ private Optional load(DrawableFile file) { - Image thumbnail = null; - File cacheFile; - try {// try to load the thumbnail from disk - cacheFile = getCacheFile(file.getId()); + Image thumbnail; - if (cacheFile.exists()) { - // If a thumbnail file is already saved locally, load it - try { - int dim = iconSize.get(); - thumbnail = new Image(Utilities.toURI(cacheFile).toURL().toString(), dim, dim, true, false, true); - } catch (MalformedURLException ex) { - Exceptions.printStackTrace(ex); + try { + thumbnail = getCacheFile(file.getId()).map((File cachFile) -> { + if (cachFile.exists()) { + // If a thumbnail file is already saved locally, load it + try { + int dim = iconSize.get(); + return new Image(Utilities.toURI(cachFile).toURL().toString(), dim, dim, true, false, true); + } catch (MalformedURLException ex) { + LOGGER.log(Level.WARNING, "Unable to parse cache file path.."); + } } - } + return null; + }).orElse(null); + } catch (IllegalStateException e) { LOGGER.log(Level.WARNING, "can't load icon when no case is open"); return Optional.empty(); @@ -153,9 +154,23 @@ public enum ThumbnailCache { return Optional.ofNullable(thumbnail); //return icon, or null if generation failed } - private static File getCacheFile(long id) { - // @@@ should use ImageUtils.getFile(); - return new File(Case.getCurrentCase().getCacheDirectory() + File.separator + id + ".png"); + /** + * get a File to store the cached icon in. + * + * @param id the obj id of the file to get a cache file for + * + * @return a Optional containing a File to store the cahced icon in or an + * empty optional if there was a + * problem. + */ + private static Optional getCacheFile(long id) { + try { + // @@@ should use ImageUtils.getFile(); + return Optional.of(new File(Case.getCurrentCase().getCacheDirectory() + File.separator + id + ".png")); + } catch (IllegalStateException e) { + LOGGER.log(Level.WARNING, "Failed to create cache file.{0}", e.getLocalizedMessage()); + return Optional.empty(); + } } /** @@ -255,15 +270,15 @@ public enum ThumbnailCache { * @param bi the thumbnail to save for the given DrawableFile */ private void saveIcon(final DrawableFile file, final Image bi) { - try { - if (bi != null) { - File f = getCacheFile(file.getId()); - //convert back to swing to save - ImageIO.write(SwingFXUtils.fromFXImage(bi, null), FORMAT, f); - } - } catch (IllegalArgumentException | IOException ex) { - //LOGGER.log(Level.WARNING, "failed to save generated icon ", ex); - LOGGER.log(Level.WARNING, "failed to save generated icon"); + if (bi != null) { + getCacheFile(file.getId()).ifPresent((File cacheFile) -> { + try { + //convert back to swing to save + ImageIO.write(SwingFXUtils.fromFXImage(bi, null), FORMAT, cacheFile); + } catch (IllegalArgumentException | IOException ex) { + LOGGER.log(Level.WARNING, "failed to save generated icon"); + } + }); } } } From 4db34a412ae404a37de3be5b5ad871648a2a70b2 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 14:19:55 -0400 Subject: [PATCH 086/198] use SwingUtilities.invokeLater rather than invokeandWait so that showing the swing dialog does not block hiding the fx menu. --- .../imagegallery/actions/AddTagAction.java | 44 +++++++------------ 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 85894cc661..42cd0ecfd1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.Set; import java.util.logging.Level; @@ -26,7 +25,6 @@ import javafx.event.ActionEvent; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; import javax.swing.SwingUtilities; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; import org.sleuthkit.autopsy.casemodule.Case; @@ -130,17 +128,13 @@ abstract class AddTagAction { // or select a tag name and adds a tag with the resulting name. MenuItem newTagMenuItem = new MenuItem("New Tag..."); newTagMenuItem.setOnAction((ActionEvent t) -> { - try { - SwingUtilities.invokeAndWait(() -> { - TagName tagName = GetTagNameDialog.doDialog(); - if (tagName != null) { - addTag(tagName, NO_COMMENT); - refreshDirectoryTree(); - } - }); - } catch (InterruptedException | InvocationTargetException ex) { - Exceptions.printStackTrace(ex); - } + SwingUtilities.invokeLater(() -> { + TagName tagName = GetTagNameDialog.doDialog(); + if (tagName != null) { + addTag(tagName, NO_COMMENT); + refreshDirectoryTree(); + } + }); }); quickTagMenu.getItems().add(newTagMenuItem); @@ -149,21 +143,17 @@ abstract class AddTagAction { // optional comment and adds a tag with the resulting name. MenuItem tagAndCommentItem = new MenuItem("Tag and Comment..."); tagAndCommentItem.setOnAction((ActionEvent t) -> { - try { - SwingUtilities.invokeAndWait(() -> { - GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); - if (null != tagNameAndComment) { - if (tagNameAndComment.getTagName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { - new CategorizeAction().addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); - } else { - AddDrawableTagAction.getInstance().addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); - } - refreshDirectoryTree(); + SwingUtilities.invokeLater(() -> { + GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); + if (null != tagNameAndComment) { + if (tagNameAndComment.getTagName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { + new CategorizeAction().addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); + } else { + AddDrawableTagAction.getInstance().addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } - }); - } catch (InterruptedException | InvocationTargetException ex) { - Exceptions.printStackTrace(ex); - } + refreshDirectoryTree(); + } + }); }); getItems().add(tagAndCommentItem); } From 51f6b05980ea192ff93b43470f18af6cd6fa76f8 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 15:46:12 -0400 Subject: [PATCH 087/198] only add new cat tag if there is no existing cat tag. put adding and removing fileids to/from group on jfx thread; remove file from groups when adding to new catagory based on new tag --- .../imagegallery/ImageGalleryController.java | 2 +- .../actions/CategorizeAction.java | 23 +++++++++---- .../datamodel/CategoryManager.java | 6 ++-- .../datamodel/grouping/GroupManager.java | 32 ++++++++++++------- 4 files changed, 41 insertions(+), 22 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 178c9dd725..d021dfcc40 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import java.beans.PropertyChangeEvent; import java.util.ArrayList; import java.util.List; @@ -63,6 +62,7 @@ import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 518a49b87a..f7c20ab56b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -19,8 +19,10 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.logging.Level; +import java.util.stream.Collectors; import javafx.event.ActionEvent; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; @@ -28,12 +30,14 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -127,11 +131,10 @@ public class CategorizeAction extends AddTagAction { try { DrawableFile file = controller.getFileFromId(fileID); //drawable db - - if (tagName != categoryManager.getTagName(Category.ZERO)) { // no tags for cat-0 - tagsManager.addContentTag(file, tagName, comment); //tsk db - } else { - tagsManager.getContentTagsByContent(file).stream() + final List fileTags = tagsManager.getContentTagsByContent(file); + if (tagName == categoryManager.getTagName(Category.ZERO)) { + // delete all cat tags for cat-0 + fileTags.stream() .filter(tag -> CategoryManager.isCategoryTagName(tag.getName())) .forEach((ct) -> { try { @@ -140,6 +143,14 @@ public class CategorizeAction extends AddTagAction { LOGGER.log(Level.SEVERE, "Error removing old categories result", ex); } }); + } else { + //add cat tag if no existing cat tag for that cat + if (fileTags.stream() + .map(Tag::getName) + .filter(tagName::equals) + .collect(Collectors.toList()).isEmpty()) { + tagsManager.addContentTag(file, tagName, comment); + } } } catch (TskCoreException ex) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 31be08e71a..3377fdce6e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -233,14 +233,12 @@ public class CategoryManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent event) { - ContentTag addedTag = event.getTag(); + final ContentTag addedTag = event.getTag(); if (isCategoryTagName(addedTag.getName())) { final DrawableTagsManager tagsManager = controller.getTagsManager(); try { //remove old category tag(s) if necessary - List allContentTags = tagsManager.getContentTagsByContent(addedTag.getContent()); - - for (ContentTag ct : allContentTags) { + for (ContentTag ct : tagsManager.getContentTagsByContent(addedTag.getContent())) { if (ct.getId() != addedTag.getId() && CategoryManager.isCategoryTagName(ct.getName())) { try { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index dc27ac136b..8b7844d9c4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -270,7 +270,9 @@ public class GroupManager { //get grouping this file would be in final DrawableGroup group = getGroupForKey(groupKey); if (group != null) { - group.removeFile(fileID); + Platform.runLater(() -> { + group.removeFile(fileID); + }); // If we're grouping by category, we don't want to remove empty groups. if (groupKey.getAttribute() != DrawableAttribute.CATEGORY) { @@ -536,16 +538,21 @@ public class GroupManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { - GroupKey groupKey = null; + GroupKey newGroupKey = null; + final long fileID = evt.getTag().getContent().getId(); if (groupBy == DrawableAttribute.CATEGORY && CategoryManager.isCategoryTagName(evt.getTag().getName())) { - groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + newGroupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + for (GroupKey oldGroupKey : groupMap.keySet()) { + if (oldGroupKey.equals(newGroupKey) == false) { + removeFromGroup(oldGroupKey, fileID); + } + } } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); + newGroupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } - if (groupKey != null) { - final long fileID = evt.getTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); + if (newGroupKey != null) { + DrawableGroup g = getGroupForKey(newGroupKey); + addFileToGroup(g, newGroupKey, fileID); } } @@ -555,9 +562,13 @@ public class GroupManager { //if there wasn't already a group check if there should be one now g = popuplateIfAnalyzed(groupKey, null); } - if (g != null) { + DrawableGroup group = g; + if (group != null) { //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. - g.addFile(fileID); + Platform.runLater(() -> { + group.addFile(fileID); + }); + } } @@ -569,7 +580,6 @@ public class GroupManager { } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } - if (groupKey != null) { final long fileID = evt.getTag().getContent().getId(); DrawableGroup g = removeFromGroup(groupKey, fileID); From 76cdc7863f27cd98832a0930a1866b3ac4107715 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 16:12:55 -0400 Subject: [PATCH 088/198] clean up add tag action, use invokeLater not invokeAndWait; getNonCategoryTagNames returns TagNames in alphabetical order by displayname --- .../imagegallery/actions/AddTagAction.java | 97 +++++++------------ .../datamodel/DrawableTagsManager.java | 14 ++- 2 files changed, 48 insertions(+), 63 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 49c1e2951f..4ae762217c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -18,24 +18,17 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.lang.reflect.InvocationTargetException; -import java.util.List; +import java.util.Collection; import java.util.Set; -import java.util.logging.Level; import javafx.event.ActionEvent; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; import javax.swing.SwingUtilities; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; /** * An abstract base class for actions that allow users to tag SleuthKit data @@ -79,76 +72,58 @@ abstract class AddTagAction { TagMenu(ImageGalleryController controller) { super(getActionDisplayName()); - // Get the current set of tag names. - DrawableTagsManager tagsManager = controller.getTagsManager(); - List tagNames = null; - try { - tagNames = tagsManager.getAllTagNames(); - } catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); - } - // Create a "Quick Tag" sub-menu. Menu quickTagMenu = new Menu("Quick Tag"); getItems().add(quickTagMenu); - // Each tag name in the current set of tags gets its own menu item in - // the "Quick Tags" sub-menu. Selecting one of these menu items adds - // a tag with the associated tag name. - if (null != tagNames && !tagNames.isEmpty()) { - for (final TagName tagName : tagNames) { - if (CategoryManager.isNotCategoryTagName(tagName)) { - MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); - tagNameItem.setOnAction((ActionEvent t) -> { - addTag(tagName, NO_COMMENT); - }); - quickTagMenu.getItems().add(tagNameItem); - } - } - } else { + /* Each non-Category tag name in the current set of tags gets its + * own menu item in the "Quick Tags" sub-menu. Selecting one of + * these menu items adds a tag with the associated tag name. */ + Collection tagNames = controller.getTagsManager().getNonCategoryTagNames(); + if (tagNames.isEmpty()) { MenuItem empty = new MenuItem("No tags"); empty.setDisable(true); quickTagMenu.getItems().add(empty); + } else { + for (final TagName tagName : tagNames) { + MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); + tagNameItem.setOnAction((ActionEvent t) -> { + addTag(tagName, NO_COMMENT); + }); + quickTagMenu.getItems().add(tagNameItem); + } } - // quickTagMenu.addSeparator(); - // The "Quick Tag" menu also gets an "Choose Tag..." menu item. - // Selecting this item initiates a dialog that can be used to create - // or select a tag name and adds a tag with the resulting name. + /* The "Quick Tag" menu also gets an "New Tag..." menu item. + * Selecting this item initiates a dialog that can be used to create + * or select a tag name and adds a tag with the resulting name. */ MenuItem newTagMenuItem = new MenuItem("New Tag..."); newTagMenuItem.setOnAction((ActionEvent t) -> { - try { - SwingUtilities.invokeAndWait(() -> { - TagName tagName = GetTagNameDialog.doDialog(); - if (tagName != null) { - addTag(tagName, NO_COMMENT); - } - }); - } catch (InterruptedException | InvocationTargetException ex) { - Exceptions.printStackTrace(ex); - } + SwingUtilities.invokeLater(() -> { + TagName tagName = GetTagNameDialog.doDialog(); + if (tagName != null) { + addTag(tagName, NO_COMMENT); + } + }); }); quickTagMenu.getItems().add(newTagMenuItem); - // Create a "Choose Tag and Comment..." menu item. Selecting this item initiates - // a dialog that can be used to create or select a tag name with an - // optional comment and adds a tag with the resulting name. + /* Create a "Tag and Comment..." menu item. Selecting this item + * initiates a dialog that can be used to create or select a tag + * name with an optional comment and adds a tag with the resulting + * name. */ MenuItem tagAndCommentItem = new MenuItem("Tag and Comment..."); tagAndCommentItem.setOnAction((ActionEvent t) -> { - try { - SwingUtilities.invokeAndWait(() -> { - GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); - if (null != tagNameAndComment) { - if (CategoryManager.isCategoryTagName(tagNameAndComment.getTagName())) { - new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); - } else { - new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); - } + SwingUtilities.invokeLater(() -> { + GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); + if (null != tagNameAndComment) { + if (CategoryManager.isCategoryTagName(tagNameAndComment.getTagName())) { + new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); + } else { + new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } - }); - } catch (InterruptedException | InvocationTargetException ex) { - Exceptions.printStackTrace(ex); - } + } + }); }); getItems().add(tagAndCommentItem); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index af5a0ebced..547ab7a858 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -27,6 +27,7 @@ import java.util.Objects; import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; +import javax.annotation.Nonnull; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; @@ -131,12 +132,21 @@ public class DrawableTagsManager { } } + /** + * get all the TagNames that are not categories + * + * @return all the TagNames that are not categories, in alphabetical order + * by displayName, or, an empty set if there was an exception looking them + * up from the db. + */ + @Nonnull public Collection getNonCategoryTagNames() { synchronized (autopsyTagsManagerLock) { try { return autopsyTagsManager.getAllTagNames().stream() - .filter(CategoryManager::isCategoryTagName) - .collect(Collectors.toSet()); + .filter(CategoryManager::isNotCategoryTagName) + .distinct().sorted() + .collect(Collectors.toList()); } catch (TskCoreException | IllegalStateException ex) { LOGGER.log(Level.WARNING, "couldn't access case", ex); } From d3bd4a6ed7fc8d0a2b8251baa8300017c7c1d0e7 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Tue, 23 Jun 2015 16:16:31 -0400 Subject: [PATCH 089/198] exceptions handled for invalid offsets --- .../autopsy/corecomponents/Bundle.properties | 1 + .../corecomponents/DataContentViewerHex.form | 2 +- .../corecomponents/DataContentViewerHex.java | 54 ++++++++----------- 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index 7c085de590..caa5ecd386 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -150,3 +150,4 @@ FXVideoPanel.progress.errorWritingVideoToDisk=Error writing video to disk DataContentViewerHex.goToOffsetLabel.text=Jump to Offset DataContentViewerHex.goToOffsetTextField.text= DataContentViewerHex.goToOffsetTextField.msgDlg=Invalid Offset: {0} +DataContentViewerHex.setDataView.invalidOffset.negativeOffsetValue=Cannot jump to the resultant offset \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form index 0939f572fc..cd5d9e21d0 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form @@ -149,7 +149,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index c60d1abe62..ea0e41ab77 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -31,7 +31,6 @@ import javax.swing.JTextPane; import javax.swing.text.BadLocationException; import javax.swing.text.Utilities; import org.openide.nodes.Node; -import org.openide.util.Exceptions; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.datamodel.DataConversion; @@ -98,6 +97,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont }}; this.outputViewPane.setBackground(new java.awt.Color(255, 255, 255)); // to make sure the background color is white this.outputViewPane.requestFocusInWindow(); + this.outputViewPane.setCursor(Cursor.getDefaultCursor()); totalPageLabel = new javax.swing.JLabel(); ofLabel = new javax.swing.JLabel(); currentPageLabel = new javax.swing.JLabel(); @@ -296,14 +296,12 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont /*** * Calculates the offset relative to the current caret position. - * @param add Pass true if the user provided offset is to be added with the offset of the caret position. Else false. - * @return + * @param userInput the user provided signed offset value. + * @return returns the resultant offset value relative to the current caret + * position. -1L is returned if the resultant offset cannot be calculated. */ - private long getOffset(boolean add) { - String hexOffsetStr = goToOffsetTextField.getText(); - String userProvidedRelativeOffsetStr; + private long getOffsetRelativeToCaretPosition(Long userInput) { String userSelectedLine; - userProvidedRelativeOffsetStr = hexOffsetStr.substring(hexOffsetStr.indexOf("+")); // NON-NLS try { // get the selected line. Extract the current hex offset location. userSelectedLine = outputViewPane.getText().subSequence( @@ -312,36 +310,32 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont .toString(); // NOTE: This needs to change if the outputFormat of outputViewPane changes. String hexForUserSelectedLine = userSelectedLine.substring(0, userSelectedLine.indexOf(":")); - if (add) { - return Long.decode(hexForUserSelectedLine) + Long.decode(userProvidedRelativeOffsetStr); - } else { - return Long.decode(hexForUserSelectedLine) - Long.decode(userProvidedRelativeOffsetStr); - } - } catch (BadLocationException ex) { + + return Long.decode(hexForUserSelectedLine) + userInput; + } catch (BadLocationException | StringIndexOutOfBoundsException | NumberFormatException ex) { // thrown in case the caret location is out of the range of the outputViewPane. - // Log it? + return -1L; } - return 0L; } private void goToOffsetTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToOffsetTextFieldActionPerformed long offset; - // jump forward relative to the current location. - if (goToOffsetTextField.getText().startsWith("+")) { - offset = getOffset(true); - } else - // jump backward relative to the current location. - if (goToOffsetTextField.getText().startsWith("-")) { - offset = getOffset(false); - } else { - // jump to an absolute location. - offset = Long.decode(goToOffsetTextField.getText()); + try { + if (goToOffsetTextField.getText().startsWith("+") || goToOffsetTextField.getText().startsWith("-")) { + offset = getOffsetRelativeToCaretPosition(Long.decode(goToOffsetTextField.getText())); + } else { + offset = Long.decode(goToOffsetTextField.getText()); + } + } catch (NumberFormatException ex) { + // notify the user and return + JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(), "DataContentViewerHex.goToOffsetTextField.msgDlg", goToOffsetTextField.getText())); + return; } - try { + if (offset >= 0) { setDataViewByOffset(offset); - } catch (NumberFormatException ex) { - JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(), "DataContentViewerHex.goToOffsetTextField.msgDlg", goToOffsetTextField.getText())); + } else { + outputViewPane.setText(NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.setDataView.invalidOffset.negativeOffsetValue")); } }//GEN-LAST:event_goToOffsetTextFieldActionPerformed @@ -443,10 +437,6 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont return; } - if (offset == 0) { - return; - } - currentPage = (int)(offset / pageLength) + 1; // change the cursor to "waiting cursor" for this operation From 890d904bad3fa948a6adc0117a03547dabe9b9b5 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 16:23:59 -0400 Subject: [PATCH 090/198] SlideShow toggle is disabled initialy; fix relative paths to images in fxml --- .../gui/drawableviews/DrawableTile.fxml | 112 +++++++++--------- .../gui/drawableviews/GroupPane.fxml | 12 +- .../gui/drawableviews/SlideShow.fxml | 12 +- 3 files changed, 69 insertions(+), 67 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml index 4d34061c77..acfcdc1336 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml @@ -7,60 +7,62 @@ - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+
-
-
- -
-
-
-
-
- - - + + + +
diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml index 6eb799970d..4760d1f0cf 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml @@ -23,7 +23,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -53,7 +53,7 @@ - + @@ -108,16 +108,16 @@ - + - + - + diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml index fb9e0aade4..fd3862afee 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml @@ -18,7 +18,7 @@ - + @@ -42,7 +42,7 @@ - + @@ -88,12 +88,12 @@ - + - + @@ -110,7 +110,7 @@ - + @@ -135,7 +135,7 @@ - + From ef50ce604b406d0f97866e3233a7e0f066181543 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Tue, 23 Jun 2015 17:03:26 -0400 Subject: [PATCH 091/198] setDataViewByOffset() and setDataViewByPageNumber() in DataContentViewerHex refactored --- .../corecomponents/DataContentViewerHex.java | 72 ++++--------------- 1 file changed, 12 insertions(+), 60 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index ea0e41ab77..11cee38ab4 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -361,7 +361,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont /** - * Sets the DataView (The tabbed panel) + * Sets the DataView (The tabbed panel) by page number * * @param page Page to display (1-based counting) */ @@ -369,76 +369,29 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont if (this.dataSource == null) { return; } - if (page == 0) { return; } - currentPage = page; long offset = (currentPage - 1) * pageLength; - - // change the cursor to "waiting cursor" for this operation - this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - - String errorText = null; - - int bytesRead = 0; - if (dataSource.getSize() > 0) { - try { - bytesRead = dataSource.read(data, offset, pageLength); // read the data - } catch (TskException ex) { - errorText = NbBundle.getMessage(this.getClass(), "DataContentViewerHex.setDataView.errorText", offset, - offset + pageLength); - logger.log(Level.WARNING, "Error while trying to show the hex content.", ex); //NON-NLS - } - } - - // set the data on the bottom and show it - if (bytesRead <= 0) { - errorText = NbBundle.getMessage(this.getClass(), "DataContentViewerHex.setDataView.errorText", offset, - offset + pageLength); - } - - - // disable or enable the next button - if ((errorText == null) && (currentPage < totalPages)) { - nextPageButton.setEnabled(true); - } - else { - nextPageButton.setEnabled(false); - } - - if ((errorText == null) && (currentPage > 1)) { - prevPageButton.setEnabled(true); - } - else { - prevPageButton.setEnabled(false); - } - - currentPageLabel.setText(Integer.toString(currentPage)); - setComponentsVisibility(true); // shows the components that not needed - - // set the output view - if (errorText == null) { - int showLength = bytesRead < pageLength ? bytesRead : (int) pageLength; - outputViewPane.setText(DataConversion.byteArrayToHex(data, showLength, offset)); - } - else { - outputViewPane.setText(errorText); - } - - outputViewPane.setCaretPosition(0); - this.setCursor(null); + setDataView(offset); goToOffsetTextField.setText(Long.toString(offset)); } - + /** + * Sets the DataView (The tabbed panel) by offset + * + * @param page Page to display (1-based counting) + */ private void setDataViewByOffset(long offset) { if (this.dataSource == null) { return; } + currentPage = (int) (offset / pageLength) + 1; + setDataView(offset); + goToPageTextField.setText(Integer.toString(currentPage)); + } - currentPage = (int)(offset / pageLength) + 1; - + private void setDataView(long offset) { // change the cursor to "waiting cursor" for this operation this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); @@ -487,7 +440,6 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont outputViewPane.setCaretPosition(0); this.setCursor(null); - goToPageTextField.setText(Integer.toString(currentPage)); } @Override From 5308dc1230d92c7f23952e54954193fa03dc9c8b Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 16:27:03 -0400 Subject: [PATCH 092/198] SlideShow toggle is disabled when there is no group selected; fix relative paths to images in fxml --- .../autopsy/imagegallery/gui/drawableviews/GroupPane.fxml | 2 +- .../autopsy/imagegallery/gui/drawableviews/GroupPane.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml index 4760d1f0cf..6dfe0d02ed 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml @@ -113,7 +113,7 @@ - + diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 4c2a056d46..ab011fc493 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -590,6 +590,7 @@ public class GroupPane extends BorderPane { Platform.runLater(() -> { gridView.getItems().setAll(Collections.emptyList()); setCenter(null); + slideShowToggle.setDisable(true); groupLabel.setText(""); resetScrollBar(); if (false == Case.isCaseOpen()) { From 2d7cc05e30e5dd4c364f2af1b289143fd1c14483 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 24 Jun 2015 10:13:59 -0400 Subject: [PATCH 093/198] remove TagAction class since it provides no value --- .../autopsy/actions/AddTagAction.java | 68 +++++++++++-------- .../DeleteBlackboardArtifactTagAction.java | 8 +-- .../actions/DeleteContentTagAction.java | 8 +-- .../sleuthkit/autopsy/actions/TagAction.java | 45 ------------ 4 files changed, 46 insertions(+), 83 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/actions/TagAction.java diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index 9c552247fd..7f4f813495 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -22,6 +22,7 @@ import java.awt.event.ActionEvent; import java.util.Collections; import java.util.List; import java.util.logging.Level; +import javax.swing.AbstractAction; import javax.swing.JMenu; import javax.swing.JMenuItem; import org.openide.util.NbBundle; @@ -33,45 +34,54 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** - * An abstract base class for Actions that allow users to tag SleuthKit data - * model objects. + * An abstract base class for Actions that allow users to tag SleuthKit data + * model objects. */ -abstract class AddTagAction extends TagAction implements Presenter.Popup { +abstract class AddTagAction extends AbstractAction implements Presenter.Popup { + private static final String NO_COMMENT = ""; - + AddTagAction(String menuText) { super(menuText); } - + @Override - public JMenuItem getPopupPresenter() { + public JMenuItem getPopupPresenter() { return new TagMenu(); } - - @Override - protected void doAction(ActionEvent event) { - } - + /** - * Template method to allow derived classes to provide a string for for a - * menu item label. + * Subclasses of AddTagAction, should not override actionPerformed, but + * instead override addTag. + * + * @param event + */ + @Override + @SuppressWarnings("NoopMethodInAbstractClass") + public void actionPerformed(ActionEvent event) { + } + + /** + * Template method to allow derived classes to provide a string for a menu + * item label. */ abstract protected String getActionDisplayName(); - + /** - * Template method to allow derived classes to add the indicated tag and - * comment to one or more a SleuthKit data model objects. + * Template method to allow derived classes to add the indicated tag and + * comment to one or more SleuthKit data model objects. */ abstract protected void addTag(TagName tagName, String comment); /** - * Instances of this class implement a context menu user interface for - * creating or selecting a tag name for a tag and specifying an optional tag - * comment. + * Instances of this class implement a context menu user interface for + * creating or selecting a tag name for a tag and specifying an optional tag + * comment. */ // @@@ This user interface has some significant usability issues and needs // to be reworked. private class TagMenu extends JMenu { + TagMenu() { super(getActionDisplayName()); @@ -81,15 +91,14 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { try { tagNames = tagsManager.getAllTagNames(); Collections.sort(tagNames); - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } - + // Create a "Quick Tag" sub-menu. JMenu quickTagMenu = new JMenu(NbBundle.getMessage(this.getClass(), "AddTagAction.quickTag")); - add(quickTagMenu); - + add(quickTagMenu); + // Each tag name in the current set of tags gets its own menu item in // the "Quick Tags" sub-menu. Selecting one of these menu items adds // a tag with the associated tag name. @@ -101,11 +110,10 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { }); quickTagMenu.add(tagNameItem); } - } - else { + } else { JMenuItem empty = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.noTags")); empty.setEnabled(false); - quickTagMenu.add(empty); + quickTagMenu.add(empty); } quickTagMenu.addSeparator(); @@ -133,7 +141,7 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } }); - add(tagAndCommentItem); + add(tagAndCommentItem); } - } -} \ No newline at end of file + } +} diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java index 5c7369c603..ac9e29fe59 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java @@ -21,19 +21,19 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import java.util.Collection; import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; +import javax.swing.AbstractAction; import javax.swing.JOptionPane; - import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this Action allow users to delete tags applied to blackboard artifacts. */ -public class DeleteBlackboardArtifactTagAction extends TagAction { +public class DeleteBlackboardArtifactTagAction extends AbstractAction { private static final String MENU_TEXT = NbBundle.getMessage(DeleteBlackboardArtifactTagAction.class, "DeleteBlackboardArtifactTagAction.deleteTags"); @@ -54,7 +54,7 @@ public class DeleteBlackboardArtifactTagAction extends TagAction { } @Override - protected void doAction(ActionEvent event) { + public void actionPerformed(ActionEvent event) { Collection selectedTags = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactTag.class); for (BlackboardArtifactTag tag : selectedTags) { try { diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java index d69e60bb31..c716311eea 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java @@ -21,19 +21,19 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import java.util.Collection; import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; +import javax.swing.AbstractAction; import javax.swing.JOptionPane; - import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this Action allow users to delete tags applied to content. */ -public class DeleteContentTagAction extends TagAction { +public class DeleteContentTagAction extends AbstractAction { private static final String MENU_TEXT = NbBundle.getMessage(DeleteContentTagAction.class, "DeleteContentTagAction.deleteTags"); @@ -54,7 +54,7 @@ public class DeleteContentTagAction extends TagAction { } @Override - protected void doAction(ActionEvent e) { + public void actionPerformed(ActionEvent e) { Collection selectedTags = Utilities.actionsGlobalContext().lookupAll(ContentTag.class); for (ContentTag tag : selectedTags) { try { diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagAction.java b/Core/src/org/sleuthkit/autopsy/actions/TagAction.java deleted file mode 100755 index ed53af2c6f..0000000000 --- a/Core/src/org/sleuthkit/autopsy/actions/TagAction.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013-15 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.actions; - -import java.awt.event.ActionEvent; -import javax.swing.AbstractAction; - -/** - * Abstract base class for Actions involving tags. - */ -abstract class TagAction extends AbstractAction { - - public TagAction(String menuText) { - super(menuText); - } - - @Override - public void actionPerformed(ActionEvent event) { - doAction(event); - } - - /** - * Derived classes must implement this Template Method for - * actionPerformed(). - * - * @param event ActionEvent object passed to actionPerformed() - */ - abstract protected void doAction(ActionEvent event); -} From f9f1c7db949bdbf25e3f580422d924087a6e83d4 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 24 Jun 2015 10:17:51 -0400 Subject: [PATCH 094/198] use private notifyPropertyChangeEvent() method in notifyNewDataSource --- .../sleuthkit/autopsy/casemodule/Case.java | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 19ec87e3cc..9b7c010bec 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -488,16 +488,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @param newDataSource new data source added */ void notifyNewDataSource(Content newDataSource) { - - try { - pcs.firePropertyChange(Events.DATA_SOURCE_ADDED.toString(), null, newDataSource); - } catch (Exception e) { - logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), - NbBundle.getMessage(this.getClass(), - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } + notifyPropertyChangeEvent(new PropertyChangeEvent(Case.class, Events.DATA_SOURCE_ADDED.toString(), null, newDataSource)); CoreComponentControl.openCoreWindows(); } @@ -507,7 +498,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @param newTag new ContentTag added */ public void notifyContentTagAdded(ContentTag newTag) { - notify(new ContentTagAddedEvent(newTag)); + notifyPropertyChangeEvent(new ContentTagAddedEvent(newTag)); } /** @@ -516,7 +507,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @param deletedTag ContentTag deleted */ public void notifyContentTagDeleted(ContentTag deletedTag) { - notify(new ContentTagDeletedEvent(deletedTag)); + notifyPropertyChangeEvent(new ContentTagDeletedEvent(deletedTag)); } /** @@ -525,7 +516,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @param newTag new BlackboardArtifactTag added */ public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) { - notify(new BlackBoardArtifactTagAddedEvent(newTag)); + notifyPropertyChangeEvent(new BlackBoardArtifactTagAddedEvent(newTag)); } /** @@ -534,7 +525,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @param deletedTag BlackboardArtifactTag deleted */ public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { - notify(new BlackBoardArtifactTagDeletedEvent(deletedTag)); + notifyPropertyChangeEvent(new BlackBoardArtifactTagDeletedEvent(deletedTag)); } /** @@ -542,7 +533,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * * @param propertyChangeEvent the event to distribute */ - private void notify(final PropertyChangeEvent propertyChangeEvent) { + private void notifyPropertyChangeEvent(final PropertyChangeEvent propertyChangeEvent) { try { pcs.firePropertyChange(propertyChangeEvent); } catch (Exception e) { From 8808496f83d3dbbc22ca96f57d64237beca18df6 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 24 Jun 2015 10:29:03 -0400 Subject: [PATCH 095/198] catch IllegalStateException from Case.getCurrentCase() in TagsManager methods --- .../casemodule/services/Bundle.properties | 6 ++++- .../casemodule/services/TagsManager.java | 24 +++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 5242f90667..b267fde0a2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -14,4 +14,8 @@ FileManager.addLocalDirInt2.exception.closed.msg=Attempted to use FileManager af TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} out of content size range (0 - {1}) TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} out of content size range (0 - {1}) TagsManager.addContentTag.exception.endLTbegin.msg=endByteOffset < beginByteOffset -TagsManager.predefTagNames.bookmark.text=Bookmark \ No newline at end of file +TagsManager.predefTagNames.bookmark.text=Bookmark +TagsManager.addContentTag.noCaseWarning=Failed to add publish new content tag event. There is no case open. +TagsManager.deleteContentTag.noCaseWarning=Failed to add publish content tag deleted event. There is no case open. +TagsManager.addBlackboardArtifactTag.noCaseWarning=Failed to add publish new blackboard artifact tag event. There is no case open. +TagsManager.deleteBlackboardArtifactTag.noCaseWarning=Failed to add publish blackboard artifact tag deleted event. There is no case open. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 123238c4e3..01daae9fba 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -248,7 +248,11 @@ public class TagsManager implements Closeable { } } final ContentTag newContentTag = tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); - Case.getCurrentCase().notifyContentTagAdded(newContentTag); + try { + Case.getCurrentCase().notifyContentTagAdded(newContentTag); + } catch (IllegalArgumentException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.addContentTag.noCaseWarning")); + } return newContentTag; } @@ -266,7 +270,11 @@ public class TagsManager implements Closeable { } tskCase.deleteContentTag(tag); - Case.getCurrentCase().notifyContentTagDeleted(tag); + try { + Case.getCurrentCase().notifyContentTagDeleted(tag); + } catch (IllegalArgumentException e) { + Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteContentTag.noCaseWarning")); + } } /** @@ -375,7 +383,11 @@ public class TagsManager implements Closeable { } BlackboardArtifactTag addBlackboardArtifactTag = tskCase.addBlackboardArtifactTag(artifact, tagName, comment); - Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(addBlackboardArtifactTag); + try { + Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(addBlackboardArtifactTag); + } catch (IllegalArgumentException e) { + Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.addBlackboardArtifactTag.noCaseWarning")); + } return addBlackboardArtifactTag; } @@ -393,7 +405,11 @@ public class TagsManager implements Closeable { } tskCase.deleteBlackboardArtifactTag(tag); - Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); + try { + Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); + } catch (IllegalArgumentException e) { + Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteBlackboardArtifactTag.noCaseWarning")); + } } /** From e30bc537a1f674eb0b3d490f3ac668c4348e0739 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 16 Jun 2015 11:14:44 -0400 Subject: [PATCH 096/198] make new DeleteFollowUpTag action; use Set instead of List to prevent duplicate files in groups --- .../actions/DeleteFollowUpTag.java | 86 +++++++++++++++++++ .../imagegallery/datamodel/DrawableDB.java | 10 +-- .../imagegallery/grouping/DrawableGroup.java | 4 +- .../imagegallery/grouping/GroupManager.java | 30 ++++--- .../imagegallery/gui/DrawableViewBase.java | 55 ++++++------ 5 files changed, 138 insertions(+), 47 deletions(-) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java new file mode 100644 index 0000000000..0399b545ed --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java @@ -0,0 +1,86 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery.actions; + +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import javafx.event.ActionEvent; +import org.controlsfx.control.action.Action; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; +import org.sleuthkit.autopsy.ingest.IngestServices; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * + */ +public class DeleteFollowUpTag extends Action { + + private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTag.class.getName()); + private final long fileID; + private final DrawableFile file; + + public DeleteFollowUpTag(DrawableFile file) { + super("Delete Follow Up Tag"); + this.file = file; + this.fileID = file.getId(); + + setEventHandler((ActionEvent t) -> { + deleteFollowupTag(); + }); + } + + /** + * + * @param fileID1 the value of fileID1 + * + * @throws IllegalStateException + */ + private void deleteFollowupTag() throws IllegalStateException { + + final ImageGalleryController controller = ImageGalleryController.getDefault(); + final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + try { + // remove file from old category group + controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); + + List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); + for (ContentTag ct : contentTagsByContent) { + if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { + sleuthKitCase.deleteContentTag(ct); + } + } + IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); + } + } +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index a5f91bb9d3..ac1f6c99eb 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -698,7 +698,7 @@ public final class DrawableDB { public Boolean isGroupAnalyzed(GroupKey gk) { dbReadLock(); try { - List fileIDsInGroup = getFileIDsInGroup(gk); + Set fileIDsInGroup = getFileIDsInGroup(gk); try { // In testing, this method appears to be a lot faster than doing one large select statement @@ -747,10 +747,10 @@ public final class DrawableDB { * * @throws TskCoreException */ - public List findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException { + public Set findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException { Statement statement = null; ResultSet rs = null; - List ret = new ArrayList<>(); + Set ret = new HashSet<>(); dbReadLock(); try { statement = con.createStatement(); @@ -984,7 +984,7 @@ public final class DrawableDB { } } - public List getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { + public Set getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { if (groupKey.getAttribute().isDBColumn) { switch (groupKey.getAttribute().attrName) { @@ -994,7 +994,7 @@ public final class DrawableDB { return groupManager.getFileIDsWithTag((TagName) groupKey.getValue()); } } - List files = new ArrayList<>(); + Set files = new HashSet<>(); dbReadLock(); try { PreparedStatement statement = getGroupStatment(groupKey.getAttribute()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index e6d1f3dad8..b59a1b8edd 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -18,8 +18,8 @@ */ package org.sleuthkit.autopsy.imagegallery.grouping; -import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.logging.Level; import javafx.beans.property.ReadOnlyBooleanWrapper; import javafx.collections.FXCollections; @@ -70,7 +70,7 @@ public class DrawableGroup implements Comparable { return groupKey.getValueDisplayName(); } - DrawableGroup(GroupKey groupKey, List filesInGroup, boolean seen) { + DrawableGroup(GroupKey groupKey, Set filesInGroup, boolean seen) { this.groupKey = groupKey; this.fileIDs.setAll(filesInGroup); this.seen.set(seen); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index ec35f6bb60..68e1044dbc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -40,6 +40,7 @@ import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javax.swing.SortOrder; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.netbeans.api.progress.ProgressHandle; @@ -241,8 +242,9 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * * @return the new DrawableGroup for the given key */ - public DrawableGroup makeGroup(GroupKey groupKey, List files) { - List newFiles = files == null ? new ArrayList<>() : files; + public DrawableGroup makeGroup(GroupKey groupKey, Set files) { + + Set newFiles = ObjectUtils.defaultIfNull(files, new HashSet()); final boolean groupSeen = db.isGroupSeen(groupKey); DrawableGroup g = new DrawableGroup(groupKey, newFiles, groupSeen); @@ -303,7 +305,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } - public synchronized void populateAnalyzedGroup(final GroupKey groupKey, List filesInGroup) { + public synchronized void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup) { populateAnalyzedGroup(groupKey, filesInGroup, null); } @@ -314,7 +316,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @param groupKey * @param filesInGroup */ - private synchronized
> void populateAnalyzedGroup(final GroupKey groupKey, List filesInGroup, ReGroupTask task) { + private synchronized > void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup, ReGroupTask task) { /* if this is not part of a regroup task or it is but the task is not * cancelled... @@ -352,7 +354,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * this * group if they are all analyzed */ - public List checkAnalyzed(final GroupKey groupKey) { + public Set checkAnalyzed(final GroupKey groupKey) { try { /* for attributes other than path we can't be sure a group is fully * analyzed because we don't know all the files that will be a part @@ -464,7 +466,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } - public List getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { + public Set getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { switch (groupKey.getAttribute().attrName) { //these cases get special treatment case CATEGORY: @@ -481,12 +483,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { // @@@ This was kind of slow in the profiler. Maybe we should cache it. // Unless the list of file IDs is necessary, use countFilesWithCategory() to get the counts. - public List getFileIDsWithCategory(Category category) throws TskCoreException { + public Set getFileIDsWithCategory(Category category) throws TskCoreException { try { if (category == Category.ZERO) { - List files = new ArrayList<>(); + Set files = new HashSet<>(); TagName[] tns = {Category.FOUR.getTagName(), Category.THREE.getTagName(), Category.TWO.getTagName(), Category.ONE.getTagName(), Category.FIVE.getTagName()}; for (TagName tn : tns) { List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tn); @@ -500,7 +502,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { return db.findAllFileIdsWhere("obj_id NOT IN (" + StringUtils.join(files, ',') + ")"); } else { - List files = new ArrayList<>(); + Set files = new HashSet<>(); List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(category.getTagName()); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { @@ -516,9 +518,9 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } - public List getFileIDsWithTag(TagName tagName) throws TskCoreException { + public Set getFileIDsWithTag(TagName tagName) throws TskCoreException { try { - List files = new ArrayList<>(); + Set files = new HashSet<>(); List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { @@ -636,7 +638,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { // It may be that this was the last unanalyzed file in the group, so test // whether the group is now fully analyzed. //TODO: use method in groupmanager ? - List checkAnalyzed = checkAnalyzed(gk); + Set checkAnalyzed = checkAnalyzed(gk); if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui populateAnalyzedGroup(gk, checkAnalyzed); } @@ -674,7 +676,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } else { //if there wasn't already a group check if there should be one now //TODO: use method in groupmanager ? - List checkAnalyzed = checkAnalyzed(gk); + Set checkAnalyzed = checkAnalyzed(gk); if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui populateAnalyzedGroup(gk, checkAnalyzed); } @@ -759,7 +761,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { //check if this group is analyzed final GroupKey groupKey = new GroupKey<>(groupBy, val); - List checkAnalyzed = checkAnalyzed(groupKey); + Set checkAnalyzed = checkAnalyzed(groupKey); if (checkAnalyzed != null) { // != null => the group is analyzed, so add it to the ui // makeGroup will create the group and add it to the map groupMap, but does not diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 23164f41fb..e866742505 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -22,8 +22,6 @@ package org.sleuthkit.autopsy.imagegallery.gui; import com.google.common.eventbus.Subscribe; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.List; import java.util.Objects; import java.util.logging.Level; import javafx.application.Platform; @@ -64,21 +62,16 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; +import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTag; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -272,28 +265,38 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie LOGGER.log(Level.SEVERE, "Failed to add follow up tag. Could not load TagName.", ex); } } else { - //TODO: convert this to an action! - final ImageGalleryController controller = ImageGalleryController.getDefault(); - try { - // remove file from old category group - controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); - - List contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(file); - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { - Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(ct); - } - } - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); - } + new DeleteFollowUpTag(file).handle(t); +// deleteFollowupTag(fileID); } - }); } +// /** +// * +// * @param fileID1 the value of fileID1 +// * +// * @throws IllegalStateException +// */ +// private void deleteFollowupTag(final Long fileID1) throws IllegalStateException { +// //TODO: convert this to an action! +// final ImageGalleryController controller = ImageGalleryController.getDefault(); +// try { +// // remove file from old category group +// controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID1); +// +// List contentTagsByContent = controller.getSleuthKitCase().getContentTagsByContent(file); +// for (ContentTag ct : contentTagsByContent) { +// if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { +// controller.getSleuthKitCase().deleteContentTag(ct); +// } +// } +// IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS +// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID1), DrawableAttribute.TAGS)); +// } catch (TskCoreException ex) { +// LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); +// } +// } + @Override public DrawableFile getFile() { if (fileID != null) { From dc65b8ae2fca457929a7d5982a3816fb15e2840d Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 16 Jun 2015 12:51:06 -0400 Subject: [PATCH 097/198] cleanup Follow Up tag and Category TagNames (prevent short name version from being added, by removing commas) --- .../imagegallery/ImageGalleryController.java | 1 + .../autopsy/imagegallery/TagUtils.java | 31 +++++++++++-------- .../actions/DeleteFollowUpTag.java | 2 ++ .../imagegallery/datamodel/Category.java | 19 +++++++----- .../datamodel/CategoryManager.java | 2 ++ 5 files changed, 35 insertions(+), 20 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index b93f362dae..8864ddc264 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -371,6 +371,7 @@ public final class ImageGalleryController { historyManager.clear(); }); Category.clearTagNames(); + TagUtils.clearFollowUpTagName(); Toolbar.getDefault().reset(); groupManager.clear(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java index b5eb4cfc25..8e9e8cfc98 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java @@ -20,10 +20,12 @@ package org.sleuthkit.autopsy.imagegallery; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; +import java.util.stream.Collectors; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.control.MenuItem; @@ -43,34 +45,36 @@ import org.sleuthkit.datamodel.TskCoreException; */ public class TagUtils { - private static final String follow_Up = "Follow Up"; + private static final String FOLLOW_UP = "Follow Up"; private static TagName followUpTagName; + /** + * Use when closing a case to make sure everything is re-initialized in the + * next case. + */ + public static void clearFollowUpTagName() { + followUpTagName = null; + } + private final static List listeners = new ArrayList<>(); synchronized public static TagName getFollowUpTagName() throws TskCoreException { if (followUpTagName == null) { - followUpTagName = getTagName(follow_Up); + followUpTagName = getTagName(FOLLOW_UP); } return followUpTagName; } static public Collection getNonCategoryTagNames() { - List nonCatTagNames = new ArrayList<>(); - List allTagNames; try { - allTagNames = Case.getCurrentCase().getServices().getTagsManager().getAllTagNames(); - for (TagName tn : allTagNames) { - if (tn.getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) { - nonCatTagNames.add(tn); - } - } + return Case.getCurrentCase().getServices().getTagsManager().getAllTagNames().stream() + .filter(Category::isCategoryTagName) + .collect(Collectors.toSet()); } catch (TskCoreException | IllegalStateException ex) { Logger.getLogger(TagUtils.class.getName()).log(Level.WARNING, "couldn't access case", ex); } - - return nonCatTagNames; + return Collections.emptySet(); } synchronized static public TagName getTagName(String displayName) throws TskCoreException { @@ -94,7 +98,7 @@ public class TagUtils { } public static void fireChange(Collection ids) { - Set listenersCopy = new HashSet(listeners); + Set listenersCopy = new HashSet<>(listeners); synchronized (listeners) { listenersCopy.addAll(listeners); } @@ -132,6 +136,7 @@ public class TagUtils { } public static interface TagListener { + public void handleTagsChanged(Collection ids); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java index 0399b545ed..0fe88de953 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java @@ -78,6 +78,8 @@ public class DeleteFollowUpTag extends Action { } } IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + + //make sure rest of ui hears category change. controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 780e851876..4839537731 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -34,16 +34,17 @@ import org.sleuthkit.datamodel.TskCoreException; */ public enum Category implements Comparable { - ZERO(Color.LIGHTGREY, 0, "CAT-0, Uncategorized"), - ONE(Color.RED, 1, "CAT-1, Child Exploitation (Illegal)"), - TWO(Color.ORANGE, 2, "CAT-2, Child Exploitation (Non-Illegal/Age Difficult)"), - THREE(Color.YELLOW, 3, "CAT-3, CGI/Animation (Child Exploitive)"), - FOUR(Color.BISQUE, 4, "CAT-4, Exemplar/Comparison (Internal Use Only)"), - FIVE(Color.GREEN, 5, "CAT-5, Non-pertinent"); + ZERO(Color.LIGHTGREY, 0, "CAT-0: Uncategorized"), + ONE(Color.RED, 1, "CAT-1: Child Exploitation (Illegal)"), + TWO(Color.ORANGE, 2, "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"), + THREE(Color.YELLOW, 3, "CAT-3: CGI/Animation (Child Exploitive)"), + FOUR(Color.BISQUE, 4, "CAT-4: Exemplar/Comparison (Internal Use Only)"), + FIVE(Color.GREEN, 5, "CAT-5: Non-pertinent"); /** map from displayName to enum value */ private static final Map nameMap - = Stream.of(values()).collect(Collectors.toMap(Category::getDisplayName, + = Stream.of(values()).collect(Collectors.toMap( + Category::getDisplayName, Function.identity())); public static final String CATEGORY_PREFIX = "CAT-"; @@ -65,6 +66,10 @@ public enum Category implements Comparable { Category.FIVE.tagName = null; } + public static boolean isCategoryTagName(TagName tName) { + return nameMap.containsKey(tName.getDisplayName()); + } + private TagName tagName; private final Color color; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 699af41bbb..f6e0404c6e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -26,6 +26,7 @@ import java.util.Collection; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.TagUtils; /** * Provides a cached view of the number of files per category, and fires @@ -75,6 +76,7 @@ public class CategoryManager { this.db = db; categoryCounts.invalidateAll(); Category.clearTagNames(); + TagUtils.clearFollowUpTagName(); } /** From 4960980c0dd8165bb8666f84ab2d7c40bc111563 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 16 Jun 2015 16:53:16 -0400 Subject: [PATCH 098/198] clean up and refactor code related to Tagging and actions; move away from singleton by injecting controller rather than using getDefault(); use EventBus in DrawableTagsManager (used to be TagUtils) requires equal and hashcode method implemented on TagName --- .../imagegallery/DrawableTagsManager.java | 161 ++++++++++++++++++ .../imagegallery/ImageGalleryController.java | 14 +- .../ImageGalleryTopComponent.java | 3 +- .../autopsy/imagegallery/TagUtils.java | 142 --------------- .../autopsy/imagegallery/TagsChangeEvent.java | 41 +++++ .../actions/AddDrawableTagAction.java | 45 ++--- .../imagegallery/actions/AddTagAction.java | 9 +- .../actions/CategorizeAction.java | 41 +++-- ...eFollowUpTag.java => DeleteTagAction.java} | 42 +++-- .../imagegallery/datamodel/Category.java | 19 --- .../datamodel/CategoryChangeEvent.java | 10 +- .../datamodel/CategoryManager.java | 29 +++- .../imagegallery/datamodel/DrawableDB.java | 15 +- .../imagegallery/grouping/GroupKey.java | 2 +- .../imagegallery/grouping/GroupManager.java | 36 ++-- .../imagegallery/gui/DrawableTile.java | 7 +- .../imagegallery/gui/DrawableView.java | 12 +- .../imagegallery/gui/DrawableViewBase.java | 62 +++---- .../autopsy/imagegallery/gui/GroupPane.java | 39 +++-- .../autopsy/imagegallery/gui/GuiUtils.java | 62 +++++++ .../imagegallery/gui/MetaDataPane.java | 20 ++- .../imagegallery/gui/SlideShowView.java | 12 +- .../autopsy/imagegallery/gui/Toolbar.java | 28 +-- 23 files changed, 494 insertions(+), 357 deletions(-) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/{DeleteFollowUpTag.java => DeleteTagAction.java} (66%) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java new file mode 100644 index 0000000000..3c1dd42de3 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -0,0 +1,161 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery; + +import com.google.common.eventbus.EventBus; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.stream.Collectors; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Manages Tags, Tagging, and the relationship between Categories and Tags in + * the autopsy Db. delegates some, work to the backing {@link TagsManager}. + */ +public class DrawableTagsManager { + + private static final String FOLLOW_UP = "Follow Up"; + + private TagsManager autopsyTagsManager; + + /** Used to distribute {@link TagsChangeEvent}s */ + private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); + + /** The tag name corresponging to the "built-in" tag "Follow Up" */ + private TagName followUpTagName; + + public DrawableTagsManager(TagsManager autopsyTagsManager) { + this.autopsyTagsManager = autopsyTagsManager; + + } + + /** + * assign a new TagsManager to back this one, ie when the current case + * changes + * + * @param autopsyTagsManager + */ + public synchronized void setAutopsyTagsManager(TagsManager autopsyTagsManager) { + this.autopsyTagsManager = autopsyTagsManager; + clearFollowUpTagName(); + } + + /** + * Use when closing a case to make sure everything is re-initialized in the + * next case. + */ + public synchronized void clearFollowUpTagName() { + followUpTagName = null; + } + + /** + * fire a CategoryChangeEvent with the given fileIDs + * + * @param fileIDs + */ + public final void fireChange(Collection fileIDs) { + tagsEventBus.post(new TagsChangeEvent(fileIDs)); + } + + /** + * register an object to receive CategoryChangeEvents + * + * @param listner + */ + public void registerListener(Object listner) { + tagsEventBus.register(listner); + } + + /** + * unregister an object from receiving CategoryChangeEvents + * + * @param listener + */ + public void unregisterListener(Object listener) { + tagsEventBus.unregister(listener); + } + + /** + * get the (cached) follow up TagName + * + * @return + * + * @throws TskCoreException + */ + synchronized public TagName getFollowUpTagName() throws TskCoreException { + if (followUpTagName == null) { + followUpTagName = getTagName(FOLLOW_UP); + } + return followUpTagName; + } + + public Collection getNonCategoryTagNames() { + try { + return autopsyTagsManager.getAllTagNames().stream() + .filter(Category::isCategoryTagName) + .collect(Collectors.toSet()); + } catch (TskCoreException | IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + } + return Collections.emptySet(); + } + + public synchronized TagName getTagName(String displayName) throws TskCoreException { + try { + for (TagName tn : autopsyTagsManager.getAllTagNames()) { + if (displayName.equals(tn.getDisplayName())) { + return tn; + } + } + try { + return autopsyTagsManager.addTagName(displayName); + } catch (TagsManager.TagNameAlreadyExistsException ex) { + throw new TskCoreException("tagame exists but wasn't found", ex); + } + } catch (IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); + throw new TskCoreException("Case was closed out from underneath", ex); + } + } + + public synchronized TagName getTagName(Category cat) { + try { + return getTagName(cat.getDisplayName()); + } catch (TskCoreException ex) { + return null; + } + } + + public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { + autopsyTagsManager.addContentTag(file, tagName, comment); + } + + public List getContentTagsByTagName(TagName t) throws TskCoreException { + return autopsyTagsManager.getContentTagsByTagName(t); + } + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 8864ddc264..ae7a169e96 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -126,7 +126,8 @@ public final class ImageGalleryController { private final GroupManager groupManager = new GroupManager(this); private final HashSetManager hashSetManager = new HashSetManager(); - private final CategoryManager categoryManager = new CategoryManager(); + private final CategoryManager categoryManager = new CategoryManager(this); + private final DrawableTagsManager tagsManager = new DrawableTagsManager(null); private StackPane fullUIStackPane; @@ -344,7 +345,7 @@ public final class ImageGalleryController { * @param theNewCase the case to configure the controller for */ public synchronized void setCase(Case theNewCase) { - this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), getSleuthKitCase()); + this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); @@ -356,6 +357,7 @@ public final class ImageGalleryController { groupManager.setDB(db); hashSetManager.setDb(db); categoryManager.setDb(db); + tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); SummaryTablePane.getDefault().refresh(); } @@ -371,9 +373,9 @@ public final class ImageGalleryController { historyManager.clear(); }); Category.clearTagNames(); - TagUtils.clearFollowUpTagName(); + tagsManager.clearFollowUpTagName(); - Toolbar.getDefault().reset(); + Toolbar.getDefault(this).reset(); groupManager.clear(); if (db != null) { db.closeDBCon(); @@ -489,6 +491,10 @@ public final class ImageGalleryController { return categoryManager; } + public DrawableTagsManager getTagsManager() { + return tagsManager; + } + // @@@ REVIEW IF THIS SHOLD BE STATIC... //TODO: concept seems like the controller deal with how much work to do at a given time // @@@ review this class for synchronization issues (i.e. reset and cancel being called, add, etc.) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java index 6aa431fb4c..e5c2bb3bd6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java @@ -34,7 +34,6 @@ import org.openide.util.NbBundle.Messages; import org.openide.windows.Mode; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.gui.GroupPane; import org.sleuthkit.autopsy.imagegallery.gui.MetaDataPane; @@ -145,7 +144,7 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl fullUIStack.getChildren().add(borderPane); splitPane = new SplitPane(); borderPane.setCenter(splitPane); - borderPane.setTop(Toolbar.getDefault()); + borderPane.setTop(Toolbar.getDefault(controller)); borderPane.setBottom(new StatusBar(controller)); metaDataTable = new MetaDataPane(controller); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java deleted file mode 100644 index 8e9e8cfc98..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import java.util.stream.Collectors; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.scene.control.MenuItem; -import javafx.scene.control.SplitMenuButton; -import javafx.scene.image.ImageView; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Contains static methods for dealing with Tags in ImageGallery - */ -public class TagUtils { - - private static final String FOLLOW_UP = "Follow Up"; - - private static TagName followUpTagName; - - /** - * Use when closing a case to make sure everything is re-initialized in the - * next case. - */ - public static void clearFollowUpTagName() { - followUpTagName = null; - } - - private final static List listeners = new ArrayList<>(); - - synchronized public static TagName getFollowUpTagName() throws TskCoreException { - if (followUpTagName == null) { - followUpTagName = getTagName(FOLLOW_UP); - } - return followUpTagName; - } - - static public Collection getNonCategoryTagNames() { - try { - return Case.getCurrentCase().getServices().getTagsManager().getAllTagNames().stream() - .filter(Category::isCategoryTagName) - .collect(Collectors.toSet()); - } catch (TskCoreException | IllegalStateException ex) { - Logger.getLogger(TagUtils.class.getName()).log(Level.WARNING, "couldn't access case", ex); - } - return Collections.emptySet(); - } - - synchronized static public TagName getTagName(String displayName) throws TskCoreException { - try { - final TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - - for (TagName tn : tagsManager.getAllTagNames()) { - if (displayName.equals(tn.getDisplayName())) { - return tn; - } - } - try { - return tagsManager.addTagName(displayName); - } catch (TagsManager.TagNameAlreadyExistsException ex) { - throw new TskCoreException("tagame exists but wasn't found", ex); - } - } catch (IllegalStateException ex) { - Logger.getLogger(TagUtils.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); - throw new TskCoreException("Case was closed out from underneath", ex); - } - } - - public static void fireChange(Collection ids) { - Set listenersCopy = new HashSet<>(listeners); - synchronized (listeners) { - listenersCopy.addAll(listeners); - } - for (TagListener list : listenersCopy) { - list.handleTagsChanged(ids); - } - } - - public static void registerListener(TagListener aThis) { - synchronized (listeners) { - listeners.add(aThis); - } - } - - public static void unregisterListener(TagListener aThis) { - synchronized (listeners) { - listeners.remove(aThis); - } - } - - /** - * @param tn the value of tn - */ - static public MenuItem createSelTagMenuItem(final TagName tn, final SplitMenuButton tagSelectedMenuButton) { - final MenuItem menuItem = new MenuItem(tn.getDisplayName(), new ImageView(DrawableAttribute.TAGS.getIcon())); - menuItem.setOnAction(new EventHandler() { - @Override - public void handle(ActionEvent t) { - AddDrawableTagAction.getInstance().addTag(tn, ""); - tagSelectedMenuButton.setText(tn.getDisplayName()); - tagSelectedMenuButton.setOnAction(this); - } - }); - return menuItem; - } - - public static interface TagListener { - - public void handleTagsChanged(Collection ids); - } -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java new file mode 100644 index 0000000000..0647a18456 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java @@ -0,0 +1,41 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery; + +import java.util.Collection; +import java.util.Collections; +import javax.annotation.concurrent.Immutable; + +/** + * + */ +@Immutable +public class TagsChangeEvent { + + private final Collection fileIDs; + + public Collection getFileIDs() { + return Collections.unmodifiableCollection(fileIDs); + } + + public TagsChangeEvent(Collection fileIDs) { + this.fileIDs = fileIDs; + } + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index a098e1a1c9..394f348466 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -27,7 +27,6 @@ import javafx.scene.control.Menu; import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.openide.util.Utilities; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; @@ -45,50 +44,41 @@ import org.sleuthkit.datamodel.TskCoreException; * diverged from autopsy action, make this extend from controlsfx Action */ public class AddDrawableTagAction extends AddTagAction { - + private static final Logger LOGGER = Logger.getLogger(AddDrawableTagAction.class.getName()); - // This class is a singleton to support multi-selection of nodes, since - // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every - // node in the array returns a reference to the same action object from Node.getActions(boolean). - private static AddDrawableTagAction instance; - - public static synchronized AddDrawableTagAction getInstance() { - if (null == instance) { - instance = new AddDrawableTagAction(); - } - return instance; + private final ImageGalleryController controller; + + public AddDrawableTagAction(ImageGalleryController controller) { + this.controller = controller; } - - private AddDrawableTagAction() { - } - + public Menu getPopupMenu() { - return new TagMenu(); + return new TagMenu(controller); } - + @Override protected String getActionDisplayName() { return Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File"; } - + @Override public void addTag(TagName tagName, String comment) { Set selectedFiles = new HashSet<>(FileIDSelectionModel.getInstance().getSelected()); addTagsToFiles(tagName, comment, selectedFiles); } - + @Override - public void addTagsToFiles(TagName tagName, String comment, Set selectedFiles){ + public void addTagsToFiles(TagName tagName, String comment, Set selectedFiles) { new SwingWorker() { - + @Override protected Void doInBackground() throws Exception { for (Long fileID : selectedFiles) { try { - DrawableFile file = ImageGalleryController.getDefault().getFileFromId(fileID); + DrawableFile file = controller.getFileFromId(fileID); LOGGER.log(Level.INFO, "tagging {0} with {1} and comment {2}", new Object[]{file.getName(), tagName.getDisplayName(), comment}); - Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment); + controller.getTagsManager().addContentTag(file, tagName, comment); } catch (IllegalStateException ex) { LOGGER.log(Level.SEVERE, "Case was closed out from underneath Updatefile task", ex); } catch (TskCoreException ex) { @@ -97,14 +87,12 @@ public class AddDrawableTagAction extends AddTagAction { } //make sure rest of ui hears category change. - ImageGalleryController.getDefault().getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); - + controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } - refreshDirectoryTree(); return null; } - + @Override protected void done() { super.done(); @@ -114,7 +102,6 @@ public class AddDrawableTagAction extends AddTagAction { LOGGER.log(Level.SEVERE, "unexpected exception while tagging files", ex); } } - }.execute(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 42cd0ecfd1..94fd9f070a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -30,6 +30,7 @@ import org.sleuthkit.autopsy.actions.GetTagNameDialog; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -43,7 +44,7 @@ import org.sleuthkit.datamodel.TskCoreException; * * //TODO: this class started as a cut and paste from * org.sleuthkit.autopsy.actions.AddTagAction and needs to be - * refactor or reintegrated to the AddTagAction hierarchy of Autopysy. + * refactored or reintegrated to the AddTagAction hierarchy of Autopysy. */ abstract class AddTagAction { @@ -86,7 +87,7 @@ abstract class AddTagAction { // to be reworked. protected class TagMenu extends Menu { - TagMenu() { + TagMenu(ImageGalleryController controller) { super(getActionDisplayName()); // Get the current set of tag names. @@ -147,9 +148,9 @@ abstract class AddTagAction { GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); if (null != tagNameAndComment) { if (tagNameAndComment.getTagName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { - new CategorizeAction().addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); + new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } else { - AddDrawableTagAction.getInstance().addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); + new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } refreshDirectoryTree(); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 79a04f535d..358516694e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -29,16 +29,18 @@ import javafx.scene.control.MenuItem; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -54,13 +56,13 @@ public class CategorizeAction extends AddTagAction { private final ImageGalleryController controller; - public CategorizeAction() { + public CategorizeAction(ImageGalleryController controller) { super(); - this.controller = ImageGalleryController.getDefault(); + this.controller = controller; } - static public Menu getPopupMenu() { - return new CategoryMenu(); + public Menu getPopupMenu() { + return new CategoryMenu(controller); } @Override @@ -90,7 +92,7 @@ public class CategorizeAction extends AddTagAction { */ static private class CategoryMenu extends Menu { - CategoryMenu() { + CategoryMenu(ImageGalleryController controller) { super("Categorize"); // Each category get an item in the sub-menu. Selecting one of these menu items adds @@ -99,8 +101,8 @@ public class CategorizeAction extends AddTagAction { MenuItem categoryItem = new MenuItem(cat.getDisplayName()); categoryItem.setOnAction((ActionEvent t) -> { - final CategorizeAction categorizeAction = new CategorizeAction(); - categorizeAction.addTag(cat.getTagName(), NO_COMMENT); + final CategorizeAction categorizeAction = new CategorizeAction(controller); + categorizeAction.addTag(controller.getCategoryManager().getTagName(cat), NO_COMMENT); }); categoryItem.setAccelerator(new KeyCodeCombination(KeyCode.getKeyCode(Integer.toString(cat.getCategoryNumber())))); getItems().add(categoryItem); @@ -123,29 +125,34 @@ public class CategorizeAction extends AddTagAction { @Override public void run() { + final GroupManager groupManager = controller.getGroupManager(); + final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + final CategoryManager categoryManager = controller.getCategoryManager(); + try { DrawableFile file = controller.getFileFromId(fileID); //drawable db Category oldCat = file.getCategory(); + // remove file from old category group - controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.CATEGORY, oldCat), fileID); //memory + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.CATEGORY, oldCat), fileID); //memory //remove old category tag if necessary - List allContentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(file); //tsk db + List allContentTags = sleuthKitCase.getContentTagsByContent(file); //tsk db + for (ContentTag ct : allContentTags) { //this is bad: treating tags as categories as long as their names start with prefix //TODO: abandon using tags for categories and instead add a new column to DrawableDB if (ct.getName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { - Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(ct); //tsk db - controller.getCategoryManager().decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db + sleuthKitCase.deleteContentTag(ct); //tsk db + categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db } - } - controller.getCategoryManager().incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db - if (tagName != Category.ZERO.getTagName()) { // no tags for cat-0 - Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment); //tsk db + categoryManager.incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db + if (tagName != categoryManager.getTagName(Category.ZERO)) { // no tags for cat-0 + controller.getTagsManager().addContentTag(file, tagName, comment); //tsk db } //make sure rest of ui hears category change. - controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui + groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error categorizing result", ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java similarity index 66% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java index 0fe88de953..38a8e40256 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java @@ -19,17 +19,16 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.Collections; -import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -39,21 +38,26 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** + * Action to delete the follow up tag a + * * */ -public class DeleteFollowUpTag extends Action { +public class DeleteTagAction extends Action { - private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTag.class.getName()); + private static final Logger LOGGER = Logger.getLogger(DeleteTagAction.class.getName()); private final long fileID; private final DrawableFile file; + private final ImageGalleryController controller; + private final ContentTag tag; - public DeleteFollowUpTag(DrawableFile file) { + public DeleteTagAction(ImageGalleryController controller, DrawableFile file, ContentTag tag) { super("Delete Follow Up Tag"); + this.controller = controller; this.file = file; this.fileID = file.getId(); - + this.tag = tag; setEventHandler((ActionEvent t) -> { - deleteFollowupTag(); + deleteTag(); }); } @@ -63,24 +67,26 @@ public class DeleteFollowUpTag extends Action { * * @throws IllegalStateException */ - private void deleteFollowupTag() throws IllegalStateException { + private void deleteTag() throws IllegalStateException { - final ImageGalleryController controller = ImageGalleryController.getDefault(); final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + final GroupManager groupManager = controller.getGroupManager(); + try { // remove file from old category group - controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); - - List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { - sleuthKitCase.deleteContentTag(ct); - } - } + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, tag.getName()), fileID); + sleuthKitCase.deleteContentTag(tag); +// +// List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); +// for (ContentTag ct : contentTagsByContent) { +// if (ct.getName().getDisplayName().equals(tagsManager.getFollowUpTagName().getDisplayName())) { +// sleuthKitCase.deleteContentTag(ct); +// } +// } IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS //make sure rest of ui hears category change. - controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 4839537731..0ded98426f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -20,14 +20,10 @@ package org.sleuthkit.autopsy.imagegallery.datamodel; import java.util.Map; import java.util.function.Function; -import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; import javafx.scene.paint.Color; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; /** * Enum to represent the six categories in the DHs image categorization scheme. @@ -101,19 +97,4 @@ public enum Category implements Comparable { return displayName; } - /** - * get the TagName used to store this Category in the main autopsy db. - * - * @return the TagName used for this Category - */ - public TagName getTagName() { - if (tagName == null) { - try { - tagName = TagUtils.getTagName(displayName); - } catch (TskCoreException ex) { - Logger.getLogger(Category.class.getName()).log(Level.SEVERE, "failed to get TagName for " + displayName, ex); - } - } - return tagName; - } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java index f53acac5f5..9896325e09 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java @@ -29,16 +29,16 @@ import javax.annotation.concurrent.Immutable; @Immutable public class CategoryChangeEvent { - private final Collection ids; + private final Collection fileIDs; /** * @return the fileIDs of the files whose categories have changed */ - public Collection getIds() { - return Collections.unmodifiableCollection(ids); + public Collection getFileIDs() { + return Collections.unmodifiableCollection(fileIDs); } - public CategoryChangeEvent(Collection ids) { - this.ids = ids; + public CategoryChangeEvent(Collection fileIDs) { + this.fileIDs = fileIDs; } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index f6e0404c6e..08ba1b17a5 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -26,7 +26,8 @@ import java.util.Collection; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.datamodel.TagName; /** * Provides a cached view of the number of files per category, and fires @@ -43,6 +44,7 @@ import org.sleuthkit.autopsy.imagegallery.TagUtils; public class CategoryManager { private static final java.util.logging.Logger LOGGER = Logger.getLogger(CategoryManager.class.getName()); + private final ImageGalleryController controller; /** * the DrawableDB that backs the category counts cache. The counts are @@ -63,6 +65,20 @@ public class CategoryManager { */ private final LoadingCache categoryCounts = CacheBuilder.newBuilder().build(CacheLoader.from(this::getCategoryCountHelper)); + /** + * cached TagNames corresponding to Categories, looked up from + * autopsyTagManager at initial request or if invalidated by case change. + */ + private final LoadingCache catTagNameMap = CacheBuilder.newBuilder().build(CacheLoader.from(cat + -> getController().getTagsManager().getTagName(cat))); + + public CategoryManager(ImageGalleryController controller) { + this.controller = controller; + } + + private ImageGalleryController getController() { + return controller; + } /** * assign a new db. the counts cache is invalidated and all subsequent db @@ -75,8 +91,8 @@ public class CategoryManager { public void setDb(DrawableDB db) { this.db = db; categoryCounts.invalidateAll(); + catTagNameMap.invalidateAll(); Category.clearTagNames(); - TagUtils.clearFollowUpTagName(); } /** @@ -171,4 +187,13 @@ public class CategoryManager { categoryEventBus.unregister(listener); } + /** + * get the TagName used to store this Category in the main autopsy db. + * + * @return the TagName used for this Category + */ + public TagName getTagName(Category cat) { + return catTagNameMap.getUnchecked(cat); + + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index ac1f6c99eb..b043bf126d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -47,6 +47,7 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; @@ -147,6 +148,7 @@ public final class DrawableDB { } } private final SleuthkitCase tskCase; + private final ImageGalleryController controller; //////////////general database logic , mostly borrowed from sleuthkitcase /** @@ -195,9 +197,10 @@ public final class DrawableDB { * * @throws SQLException if there is problem creating or configuring the db */ - private DrawableDB(Path dbPath, SleuthkitCase tskCase) throws SQLException, ExceptionInInitializerError, IOException { + private DrawableDB(Path dbPath, ImageGalleryController controller) throws SQLException, ExceptionInInitializerError, IOException { this.dbPath = dbPath; - this.tskCase = tskCase; + this.controller = controller; + this.tskCase = controller.getSleuthKitCase(); Files.createDirectories(dbPath.getParent()); if (initializeDBSchema()) { updateFileStmt = prepareStatement( @@ -286,10 +289,10 @@ public final class DrawableDB { * * @return */ - public static DrawableDB getDrawableDB(Path dbPath, SleuthkitCase tskCase) { + public static DrawableDB getDrawableDB(Path dbPath, ImageGalleryController controller) { try { - return new DrawableDB(dbPath.resolve("drawable.db"), tskCase); + return new DrawableDB(dbPath.resolve("drawable.db"), controller); } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "sql error creating database connection", ex); return null; @@ -1055,7 +1058,7 @@ public final class DrawableDB { public List> getFilesWithCategory(Category cat) throws TskCoreException, IllegalArgumentException { try { List> files = new ArrayList<>(); - List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(cat.getTagName()); + List contentTags = tskCase.getContentTagsByTagName(controller.getTagsManager().getTagName(cat)); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile) { files.add(DrawableFile.create((AbstractFile) ct.getContent(), isFileAnalyzed(ct.getContent().getId()), @@ -1240,7 +1243,7 @@ public final class DrawableDB { */ public long getCategoryCount(Category cat) { try { - return Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(cat.getTagName()).stream() + return tskCase.getContentTagsByTagName(controller.getTagsManager().getTagName(cat)).stream() .map(ContentTag::getContent) .map(Content::getId) .filter(this::isInDB) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java index 789cac7375..cd41534078 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java @@ -56,7 +56,7 @@ public class GroupKey> implements Comparable @Override public String toString() { - return "GroupKey: " + getAttribute() + " = " + getValue(); + return "GroupKey: " + getAttribute().attrName + " = " + getValue(); } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 68e1044dbc..dab1f9743f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -34,6 +34,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; +import java.util.stream.Stream; import javafx.application.Platform; import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleWrapper; @@ -51,10 +52,10 @@ import org.sleuthkit.autopsy.coreutils.LoggedTask; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; @@ -486,31 +487,34 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public Set getFileIDsWithCategory(Category category) throws TskCoreException { try { + final DrawableTagsManager tagsManager = controller.getTagsManager(); if (category == Category.ZERO) { + List< TagName> tns = Stream.of(Category.ONE, Category.TWO, Category.THREE, Category.FOUR, Category.FIVE) + .map(tagsManager::getTagName) + .collect(Collectors.toList()); Set files = new HashSet<>(); - TagName[] tns = {Category.FOUR.getTagName(), Category.THREE.getTagName(), Category.TWO.getTagName(), Category.ONE.getTagName(), Category.FIVE.getTagName()}; for (TagName tn : tns) { - List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tn); - for (ContentTag ct : contentTags) { - if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { - files.add(ct.getContent().getId()); - } + if (tn != null) { + List contentTags = tagsManager.getContentTagsByTagName(tn); + files.addAll(contentTags.stream() + .filter(ct -> ct.getContent() instanceof AbstractFile) + .filter(ct -> db.isInDB(ct.getContent().getId())) + .map(ct -> ct.getContent().getId()) + .collect(Collectors.toSet())); } } return db.findAllFileIdsWhere("obj_id NOT IN (" + StringUtils.join(files, ',') + ")"); } else { - Set files = new HashSet<>(); - List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(category.getTagName()); - for (ContentTag ct : contentTags) { - if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { - files.add(ct.getContent().getId()); - } - } + List contentTags = tagsManager.getContentTagsByTagName(tagsManager.getTagName(category)); + return contentTags.stream() + .filter(ct -> ct.getContent() instanceof AbstractFile) + .filter(ct -> db.isInDB(ct.getContent().getId())) + .map(ct -> ct.getContent().getId()) + .collect(Collectors.toSet()); - return files; } } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "TSK error getting files in Category:" + category.getDisplayName(), ex); @@ -688,7 +692,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { controller.getCategoryManager().fireChange(fileIDs); if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { - TagUtils.fireChange(fileIDs); + controller.getTagsManager().fireChange(fileIDs); } break; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java index 80f16a3d7a..75332ba158 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java @@ -32,7 +32,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableViewBase.globalSelectionModel; /** @@ -43,7 +42,7 @@ import static org.sleuthkit.autopsy.imagegallery.gui.DrawableViewBase.globalSele * * TODO: refactor this to extend from {@link Control}? -jm */ -public class DrawableTile extends DrawableViewBase implements TagUtils.TagListener { +public class DrawableTile extends DrawableViewBase { private static final DropShadow LAST_SELECTED_EFFECT = new DropShadow(10, Color.BLUE); @@ -73,8 +72,8 @@ public class DrawableTile extends DrawableViewBase implements TagUtils.TagListen setCacheHint(CacheHint.SPEED); nameLabel.prefWidthProperty().bind(imageView.fitWidthProperty()); - imageView.fitHeightProperty().bind(Toolbar.getDefault().sizeSliderValue()); - imageView.fitWidthProperty().bind(Toolbar.getDefault().sizeSliderValue()); + imageView.fitHeightProperty().bind(Toolbar.getDefault(getController()).sizeSliderValue()); + imageView.fitWidthProperty().bind(Toolbar.getDefault(getController()).sizeSliderValue()); globalSelectionModel.lastSelectedProperty().addListener((observable, oldValue, newValue) -> { try { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 8f91cdf932..ed0453ec0b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -1,7 +1,6 @@ package org.sleuthkit.autopsy.imagegallery.gui; import com.google.common.eventbus.Subscribe; -import java.util.Collection; import java.util.logging.Level; import javafx.application.Platform; import javafx.scene.layout.Border; @@ -13,7 +12,8 @@ import javafx.scene.layout.Region; import javafx.scene.paint.Color; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; @@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; * } to have there {@link DrawableView#handleCategoryChanged(org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent) * } method invoked */ -public interface DrawableView extends TagUtils.TagListener { +public interface DrawableView { //TODO: do this all in css? -jm static final int CAT_BORDER_WIDTH = 10; @@ -67,8 +67,10 @@ public interface DrawableView extends TagUtils.TagListener { @Subscribe void handleCategoryChanged(CategoryChangeEvent evt); - @Override - void handleTagsChanged(Collection ids); + @Subscribe + void handleTagsChanged(TagsChangeEvent evt); + + ImageGalleryController getController(); default boolean hasHashHit() { try { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index e866742505..7f29af775e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -64,10 +64,10 @@ import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; -import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; -import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTag; +import org.sleuthkit.autopsy.imagegallery.actions.DeleteTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -138,6 +138,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie */ final private GroupPane groupPane; private boolean registered = false; + private final ImageGalleryController controller; GroupPane getGroupPane() { return groupPane; @@ -145,6 +146,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie protected DrawableViewBase(GroupPane groupPane) { this.groupPane = groupPane; + this.controller = groupPane.getController(); globalSelectionModel.getSelected().addListener((Observable observable) -> { updateSelectionState(); }); @@ -194,9 +196,9 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie private ContextMenu buildContextMenu() { final ArrayList menuItems = new ArrayList<>(); - menuItems.add(CategorizeAction.getPopupMenu()); + menuItems.add(new CategorizeAction(controller).getPopupMenu()); - menuItems.add(AddDrawableTagAction.getInstance().getPopupMenu()); + menuItems.add(new AddDrawableTagAction(controller).getPopupMenu()); final MenuItem extractMenuItem = new MenuItem("Extract File(s)"); extractMenuItem.setOnAction((ActionEvent t) -> { @@ -260,43 +262,16 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie if (followUpToggle.isSelected() == true) { globalSelectionModel.clearAndSelect(fileID); try { - AddDrawableTagAction.getInstance().addTag(TagUtils.getFollowUpTagName(), ""); + new AddDrawableTagAction(controller).addTag(ImageGalleryController.getDefault().getTagsManager().getFollowUpTagName(), ""); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to add follow up tag. Could not load TagName.", ex); } } else { - new DeleteFollowUpTag(file).handle(t); -// deleteFollowupTag(fileID); + new DeleteTagAction(controller, file).handle(t); } }); } -// /** -// * -// * @param fileID1 the value of fileID1 -// * -// * @throws IllegalStateException -// */ -// private void deleteFollowupTag(final Long fileID1) throws IllegalStateException { -// //TODO: convert this to an action! -// final ImageGalleryController controller = ImageGalleryController.getDefault(); -// try { -// // remove file from old category group -// controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID1); -// -// List contentTagsByContent = controller.getSleuthKitCase().getContentTagsByContent(file); -// for (ContentTag ct : contentTagsByContent) { -// if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { -// controller.getSleuthKitCase().deleteContentTag(ct); -// } -// } -// IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS -// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID1), DrawableAttribute.TAGS)); -// } catch (TskCoreException ex) { -// LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); -// } -// } - @Override public DrawableFile getFile() { if (fileID != null) { @@ -315,7 +290,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie } protected boolean hasFollowUp() throws TskCoreException { - String followUpTagName = TagUtils.getFollowUpTagName().getDisplayName(); + String followUpTagName = ImageGalleryController.getDefault().getTagsManager().getFollowUpTagName().getDisplayName(); Collection tagNames = DrawableAttribute.TAGS.getValue(getFile()); return tagNames.stream().anyMatch((tn) -> tn.getDisplayName().equals(followUpTagName)); } @@ -326,8 +301,8 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie } @Override - synchronized public void handleTagsChanged(Collection ids) { - if (fileID != null && ids.contains(fileID)) { + synchronized public void handleTagsChanged(TagsChangeEvent evnt) { + if (fileID != null && evnt.getFileIDs().contains(fileID)) { updateFollowUpIcon(); } } @@ -354,8 +329,8 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie if (this.fileID == null || Case.isCaseOpen() == false) { if (registered == true) { - ImageGalleryController.getDefault().getCategoryManager().unregisterListener(this); - TagUtils.unregisterListener(this); + getController().getCategoryManager().unregisterListener(this); + getController().getTagsManager().unregisterListener(this); registered = false; } file = null; @@ -364,8 +339,8 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie }); } else { if (registered == false) { - ImageGalleryController.getDefault().getCategoryManager().registerListener(this); - TagUtils.registerListener(this); + getController().getCategoryManager().registerListener(this); + getController().getTagsManager().registerListener(this); registered = true; } file = null; @@ -411,8 +386,13 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { - if (evt.getIds().contains(getFileID())) { + if (evt.getFileIDs().contains(getFileID())) { updateCategoryBorder(); } } + + @Override + public ImageGalleryController getController() { + return controller; + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java index 30dcf743fb..09042abaf4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java @@ -100,11 +100,11 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.Back; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; @@ -277,7 +277,7 @@ public class GroupPane extends BorderPane implements GroupView { @Override public void handle(ActionEvent t) { Set fileIdSet = new HashSet<>(getGrouping().fileIds()); - new CategorizeAction().addTagsToFiles(cat.getTagName(), "", fileIdSet); + new CategorizeAction(controller).addTagsToFiles(controller.getTagsManager().getTagName(cat), "", fileIdSet); grpCatSplitMenu.setText(cat.getDisplayName()); grpCatSplitMenu.setOnAction(this); @@ -292,7 +292,7 @@ public class GroupPane extends BorderPane implements GroupView { @Override public void handle(ActionEvent t) { Set fileIdSet = new HashSet<>(getGrouping().fileIds()); - AddDrawableTagAction.getInstance().addTagsToFiles(tn, "", fileIdSet); + new AddDrawableTagAction(controller).addTagsToFiles(tn, "", fileIdSet); grpTagSplitMenu.setText(tn.getDisplayName()); grpTagSplitMenu.setOnAction(this); @@ -340,8 +340,8 @@ public class GroupPane extends BorderPane implements GroupView { flashAnimation.setAutoReverse(true); //configure gridView cell properties - gridView.cellHeightProperty().bind(Toolbar.getDefault().sizeSliderValue().add(75)); - gridView.cellWidthProperty().bind(Toolbar.getDefault().sizeSliderValue().add(75)); + gridView.cellHeightProperty().bind(Toolbar.getDefault(controller).sizeSliderValue().add(75)); + gridView.cellWidthProperty().bind(Toolbar.getDefault(controller).sizeSliderValue().add(75)); gridView.setCellFactory((GridView param) -> new DrawableCell()); //configure toolbar properties @@ -349,8 +349,8 @@ public class GroupPane extends BorderPane implements GroupView { spacer.setMinWidth(Region.USE_PREF_SIZE); try { - grpTagSplitMenu.setText(TagUtils.getFollowUpTagName().getDisplayName()); - grpTagSplitMenu.setOnAction(createGrpTagMenuItem(TagUtils.getFollowUpTagName()).getOnAction()); + grpTagSplitMenu.setText(getController().getTagsManager().getFollowUpTagName().getDisplayName()); + grpTagSplitMenu.setOnAction(createGrpTagMenuItem(getController().getTagsManager().getFollowUpTagName()).getOnAction()); } catch (TskCoreException tskCoreException) { LOGGER.log(Level.WARNING, "failed to load FollowUpTagName", tskCoreException); } @@ -358,8 +358,8 @@ public class GroupPane extends BorderPane implements GroupView { grpTagSplitMenu.showingProperty().addListener((ObservableValue ov, Boolean t, Boolean t1) -> { if (t1) { ArrayList selTagMenues = new ArrayList<>(); - for (final TagName tn : TagUtils.getNonCategoryTagNames()) { - MenuItem menuItem = TagUtils.createSelTagMenuItem(tn, grpTagSplitMenu); + for (final TagName tn : getController().getTagsManager().getNonCategoryTagNames()) { + MenuItem menuItem = GuiUtils.createSelTagMenuItem(tn, grpTagSplitMenu, controller); selTagMenues.add(menuItem); } grpTagSplitMenu.getItems().setAll(selTagMenues); @@ -419,9 +419,8 @@ public class GroupPane extends BorderPane implements GroupView { private ContextMenu buildContextMenu() { ArrayList menuItems = new ArrayList<>(); - menuItems.add(CategorizeAction.getPopupMenu()); - - menuItems.add(AddDrawableTagAction.getInstance().getPopupMenu()); + menuItems.add(new CategorizeAction(controller).getPopupMenu()); + menuItems.add(new AddDrawableTagAction(controller).getPopupMenu()); Collection menuProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class); @@ -653,6 +652,10 @@ public class GroupPane extends BorderPane implements GroupView { } } + ImageGalleryController getController() { + return controller; + } + private class DrawableCell extends GridCell { private final DrawableTile tile = new DrawableTile(GroupPane.this); @@ -751,27 +754,27 @@ public class GroupPane extends BorderPane implements GroupView { switch (t.getCode()) { case NUMPAD0: case DIGIT0: - new CategorizeAction().addTag(Category.ZERO.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.ZERO), ""); break; case NUMPAD1: case DIGIT1: - new CategorizeAction().addTag(Category.ONE.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.ONE), ""); break; case NUMPAD2: case DIGIT2: - new CategorizeAction().addTag(Category.TWO.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.TWO), ""); break; case NUMPAD3: case DIGIT3: - new CategorizeAction().addTag(Category.THREE.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.THREE), ""); break; case NUMPAD4: case DIGIT4: - new CategorizeAction().addTag(Category.FOUR.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.FOUR), ""); break; case NUMPAD5: case DIGIT5: - new CategorizeAction().addTag(Category.FIVE.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.FIVE), ""); break; } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java new file mode 100644 index 0000000000..4a2a84fd46 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java @@ -0,0 +1,62 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery.gui; + +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.scene.control.MenuItem; +import javafx.scene.control.SplitMenuButton; +import javafx.scene.image.ImageView; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.datamodel.TagName; + +/** + * Static utility methods for working with GUI components + */ +public class GuiUtils { + + /** + * make a new menu item that when clicked, tags the selected files with the + * given tagname + * + * @param tagName + * @param tagSelectedMenuButton + * @param controller + * + * @return + */ + public static MenuItem createSelTagMenuItem(final TagName tagName, final SplitMenuButton tagSelectedMenuButton, ImageGalleryController controller) { + final MenuItem menuItem = new MenuItem(tagName.getDisplayName(), new ImageView(DrawableAttribute.TAGS.getIcon())); + menuItem.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent t) { + new AddDrawableTagAction(controller).addTag(tagName, ""); + tagSelectedMenuButton.setText(tagName.getDisplayName()); + tagSelectedMenuButton.setOnAction(this); + } + }); + return menuItem; + } + + private GuiUtils() { + } + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index b4319ac815..f9f6115d67 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -45,7 +45,7 @@ import javafx.util.Pair; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -56,12 +56,17 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Shows details of the selected file. */ -public class MetaDataPane extends AnchorPane implements TagUtils.TagListener, DrawableView { +public class MetaDataPane extends AnchorPane implements DrawableView { private static final Logger LOGGER = Logger.getLogger(MetaDataPane.class.getName()); private final ImageGalleryController controller; + @Override + public ImageGalleryController getController() { + return controller; + } + private Long fileID; @FXML @@ -92,8 +97,8 @@ public class MetaDataPane extends AnchorPane implements TagUtils.TagListener, Dr assert imageView != null : "fx:id=\"imageView\" was not injected: check your FXML file 'MetaDataPane.fxml'."; assert tableView != null : "fx:id=\"tableView\" was not injected: check your FXML file 'MetaDataPane.fxml'."; assert valueColumn != null : "fx:id=\"valueColumn\" was not injected: check your FXML file 'MetaDataPane.fxml'."; - TagUtils.registerListener(this); - ImageGalleryController.getDefault().getCategoryManager().registerListener(this); + getController().getTagsManager().registerListener(this); + getController().getCategoryManager().registerListener(this); tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); tableView.setPlaceholder(new Label("Select a file to show its details here.")); @@ -224,14 +229,15 @@ public class MetaDataPane extends AnchorPane implements TagUtils.TagListener, Dr @Subscribe @Override public void handleCategoryChanged(CategoryChangeEvent evt) { - if (getFile() != null && evt.getIds().contains(getFileID())) { + if (getFile() != null && evt.getFileIDs().contains(getFileID())) { updateUI(); } } @Override - public void handleTagsChanged(Collection ids) { - if (getFile() != null && ids.contains(getFileID())) { + @Subscribe + public void handleTagsChanged(TagsChangeEvent evt) { + if (getFile() != null && evt.getFileIDs().contains(getFileID())) { updateUI(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index 88467e1973..7977eb0219 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -48,9 +48,9 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -66,7 +66,7 @@ import org.sleuthkit.datamodel.TskCoreException; * GroupPane. TODO: Extract a subclass for video files in slideshow mode-jm * TODO: reduce coupling to GroupPane */ -public class SlideShowView extends DrawableViewBase implements TagUtils.TagListener { +public class SlideShowView extends DrawableViewBase { private static final Logger LOGGER = Logger.getLogger(SlideShowView.class.getName()); @@ -127,7 +127,7 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe tagSplitButton.setOnAction((ActionEvent t) -> { try { - TagUtils.createSelTagMenuItem(TagUtils.getFollowUpTagName(), tagSplitButton).getOnAction().handle(t); + GuiUtils.createSelTagMenuItem(getController().getTagsManager().getFollowUpTagName(), tagSplitButton, getController()).getOnAction().handle(t); } catch (TskCoreException ex) { Exceptions.printStackTrace(ex); } @@ -137,8 +137,8 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe tagSplitButton.showingProperty().addListener((ObservableValue ov, Boolean t, Boolean t1) -> { if (t1) { ArrayList selTagMenues = new ArrayList<>(); - for (final TagName tn : TagUtils.getNonCategoryTagNames()) { - MenuItem menuItem = TagUtils.createSelTagMenuItem(tn, tagSplitButton); + for (final TagName tn : getController().getTagsManager().getNonCategoryTagNames()) { + MenuItem menuItem = GuiUtils.createSelTagMenuItem(tn, tagSplitButton, getController()); selTagMenues.add(menuItem); } tagSplitButton.getItems().setAll(selTagMenues); @@ -347,7 +347,7 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe public void changed(ObservableValue ov, Boolean t, Boolean t1) { if (t1) { FileIDSelectionModel.getInstance().clearAndSelect(getFileID()); - new CategorizeAction().addTag(cat.getTagName(), ""); + new CategorizeAction(getController()).addTag(getController().getTagsManager().getTagName(cat), ""); } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index bf62f89084..2131ff73fc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -41,10 +41,10 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javax.swing.SortOrder; import org.openide.util.Exceptions; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.ThumbnailCache; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; @@ -105,6 +105,7 @@ public class Toolbar extends ToolBar { ImageGalleryController.getDefault().getGroupManager().regroup(groupByBox.getSelectionModel().getSelectedItem(), sortByBox.getSelectionModel().getSelectedItem(), getSortOrder(), false); }; + private ImageGalleryController controller; synchronized public SortOrder getSortOrder() { return orderProperty.get(); @@ -117,9 +118,9 @@ public class Toolbar extends ToolBar { return sizeSlider.valueProperty(); } - static synchronized public Toolbar getDefault() { + static synchronized public Toolbar getDefault(ImageGalleryController controller) { if (instance == null) { - instance = new Toolbar(); + instance = new Toolbar(controller); } return instance; } @@ -151,7 +152,7 @@ public class Toolbar extends ToolBar { tagSelectedMenuButton.setOnAction((ActionEvent t) -> { try { - TagUtils.createSelTagMenuItem(TagUtils.getFollowUpTagName(), tagSelectedMenuButton).getOnAction().handle(t); + GuiUtils.createSelTagMenuItem(getController().getTagsManager().getFollowUpTagName(), tagSelectedMenuButton, getController()).getOnAction().handle(t); } catch (TskCoreException ex) { Exceptions.printStackTrace(ex); } @@ -161,22 +162,22 @@ public class Toolbar extends ToolBar { tagSelectedMenuButton.showingProperty().addListener((ObservableValue ov, Boolean t, Boolean t1) -> { if (t1) { ArrayList selTagMenues = new ArrayList<>(); - for (final TagName tn : TagUtils.getNonCategoryTagNames()) { - MenuItem menuItem = TagUtils.createSelTagMenuItem(tn, tagSelectedMenuButton); + for (final TagName tn : getController().getTagsManager().getNonCategoryTagNames()) { + MenuItem menuItem = GuiUtils.createSelTagMenuItem(tn, tagSelectedMenuButton, getController()); selTagMenues.add(menuItem); } tagSelectedMenuButton.getItems().setAll(selTagMenues); } }); - catSelectedMenuButton.setOnAction(createSelCatMenuItem(Category.FIVE, catSelectedMenuButton).getOnAction()); + catSelectedMenuButton.setOnAction(createSelCatMenuItem(Category.FIVE, catSelectedMenuButton, getController()).getOnAction()); catSelectedMenuButton.setText(Category.FIVE.getDisplayName()); catSelectedMenuButton.setGraphic(new ImageView(DrawableAttribute.CATEGORY.getIcon())); catSelectedMenuButton.showingProperty().addListener((ObservableValue ov, Boolean t, Boolean t1) -> { if (t1) { ArrayList categoryMenues = new ArrayList<>(); for (final Category cat : Category.values()) { - MenuItem menuItem = createSelCatMenuItem(cat, catSelectedMenuButton); + MenuItem menuItem = createSelCatMenuItem(cat, catSelectedMenuButton, getController()); categoryMenues.add(menuItem); } catSelectedMenuButton.getItems().setAll(categoryMenues); @@ -221,20 +222,25 @@ public class Toolbar extends ToolBar { }); } - private Toolbar() { + private Toolbar(ImageGalleryController controller) { + this.controller = controller; FXMLConstructor.construct(this, "Toolbar.fxml"); } - private static MenuItem createSelCatMenuItem(Category cat, final SplitMenuButton catSelectedMenuButton) { + private static MenuItem createSelCatMenuItem(Category cat, final SplitMenuButton catSelectedMenuButton, ImageGalleryController controller) { final MenuItem menuItem = new MenuItem(cat.getDisplayName(), new ImageView(DrawableAttribute.CATEGORY.getIcon())); menuItem.setOnAction(new EventHandler() { @Override public void handle(ActionEvent t) { - new CategorizeAction().addTag(cat.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(cat), ""); catSelectedMenuButton.setText(cat.getDisplayName()); catSelectedMenuButton.setOnAction(this); } }); return menuItem; } + + private ImageGalleryController getController() { + return controller; + } } From 1e9d6c54c4da95ade4225e750b1554e77ca30695 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 17 Jun 2015 15:51:15 -0400 Subject: [PATCH 099/198] make sure all code is using the correct TagsManager (DrawableTagsManager) from controller; more cleanup --- .../imagegallery/DrawableTagsManager.java | 49 +++++++++++++++++-- .../imagegallery/ImageGalleryController.java | 39 ++++++++------- .../actions/AddDrawableTagAction.java | 3 +- .../imagegallery/actions/AddTagAction.java | 21 ++------ .../actions/CategorizeAction.java | 3 +- ...tion.java => DeleteFollowUpTagAction.java} | 43 ++++++++-------- .../imagegallery/datamodel/DrawableDB.java | 4 +- .../imagegallery/datamodel/DrawableFile.java | 10 ++-- .../imagegallery/grouping/GroupManager.java | 33 ++++++++++--- .../imagegallery/gui/DrawableViewBase.java | 16 +++--- 10 files changed, 133 insertions(+), 88 deletions(-) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/{DeleteTagAction.java => DeleteFollowUpTagAction.java} (69%) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 3c1dd42de3..7ba9ceb842 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -28,6 +28,10 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.ingest.IngestServices; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -45,7 +49,7 @@ public class DrawableTagsManager { /** Used to distribute {@link TagsChangeEvent}s */ private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); - /** The tag name corresponging to the "built-in" tag "Follow Up" */ + /** The tag name corresponding to the "built-in" tag "Follow Up" */ private TagName followUpTagName; public DrawableTagsManager(TagsManager autopsyTagsManager) { @@ -113,7 +117,7 @@ public class DrawableTagsManager { return followUpTagName; } - public Collection getNonCategoryTagNames() { + synchronized public Collection getNonCategoryTagNames() { try { return autopsyTagsManager.getAllTagNames().stream() .filter(Category::isCategoryTagName) @@ -124,6 +128,20 @@ public class DrawableTagsManager { return Collections.emptySet(); } + /** + * Gets content tags count by content. + * + * @param The content of interest. + * + * @return A list, possibly empty, of the tags that have been applied to the + * artifact. + * + * @throws TskCoreException + */ + public synchronized List getContentTagsByContent(Content content) throws TskCoreException { + return autopsyTagsManager.getContentTagsByContent(content); + } + public synchronized TagName getTagName(String displayName) throws TskCoreException { try { for (TagName tn : autopsyTagsManager.getAllTagNames()) { @@ -150,12 +168,35 @@ public class DrawableTagsManager { } } - public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { + synchronized public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { autopsyTagsManager.addContentTag(file, tagName, comment); } - public List getContentTagsByTagName(TagName t) throws TskCoreException { + synchronized public List getContentTagsByTagName(TagName t) throws TskCoreException { return autopsyTagsManager.getContentTagsByTagName(t); } + /** + * Fire the ModuleDataEvent that we use as a place holder for a real Tag + * Event. This is used to refresh the autopsy tag tree and the ui in + * ImageGallery + * + * + * Note: this is a hack. In an ideal world, TagsManager would fire + * events so that the directory tree would refresh. But, we haven't + * had a chance to add that so, we fire these events and the tree + * refreshes based on them. + */ + static public void fireTagsChangedEvent() { + + IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + } + + public synchronized List getAllTagNames() throws TskCoreException { + return autopsyTagsManager.getAllTagNames(); + } + + public synchronized List getTagNamesInUse() throws TskCoreException { + return autopsyTagsManager.getTagNamesInUse(); + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index ae7a169e96..4bed46a023 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.imagegallery; import java.beans.PropertyChangeEvent; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; @@ -134,6 +135,7 @@ public final class ImageGalleryController { private StackPane centralStackPane; private Node infoOverlay; + private SleuthkitCase sleuthKitCase; public ReadOnlyBooleanProperty getMetaDataCollapsed() { return metaDataCollapsed.getReadOnlyProperty(); @@ -345,20 +347,25 @@ public final class ImageGalleryController { * @param theNewCase the case to configure the controller for */ public synchronized void setCase(Case theNewCase) { - this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); + if (Objects.nonNull(theNewCase)) { + this.sleuthKitCase = theNewCase.getSleuthkitCase(); + this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); - setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); - setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); + setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); + setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); - // if we add this line icons are made as files are analyzed rather than on demand. - // db.addUpdatedFileListener(IconCache.getDefault()); - restartWorker(); - historyManager.clear(); - groupManager.setDB(db); - hashSetManager.setDb(db); - categoryManager.setDb(db); - tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); - SummaryTablePane.getDefault().refresh(); + // if we add this line icons are made as files are analyzed rather than on demand. + // db.addUpdatedFileListener(IconCache.getDefault()); + restartWorker(); + historyManager.clear(); + groupManager.setDB(db); + hashSetManager.setDb(db); + categoryManager.setDb(db); + tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); + SummaryTablePane.getDefault().refresh(); + } else { + reset(); + } } /** @@ -558,12 +565,8 @@ public final class ImageGalleryController { } } - public SleuthkitCase getSleuthKitCase() throws IllegalStateException { - if (Case.isCaseOpen()) { - return Case.getCurrentCase().getSleuthkitCase(); - } else { - throw new IllegalStateException("No Case is open!"); - } + public synchronized SleuthkitCase getSleuthKitCase() { + return sleuthKitCase; } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index 394f348466..9d5c5f277b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -28,6 +28,7 @@ import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.openide.util.Utilities; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -89,7 +90,7 @@ public class AddDrawableTagAction extends AddTagAction { //make sure rest of ui hears category change. controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } - refreshDirectoryTree(); + DrawableTagsManager.fireTagsChangedEvent(); return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 94fd9f070a..95d3346175 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -27,14 +27,11 @@ import javafx.scene.control.MenuItem; import javax.swing.SwingUtilities; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -48,16 +45,6 @@ import org.sleuthkit.datamodel.TskCoreException; */ abstract class AddTagAction { - @SuppressWarnings("deprecation") - protected void refreshDirectoryTree() { - - /* Note: this is a hack. In an ideal world, TagsManager would fire - * events so that the directory tree would refresh. But, we haven't - * had a chance to add that so, we fire these events and the tree - * refreshes based on them. - */ - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - } protected static final String NO_COMMENT = ""; /** @@ -91,7 +78,7 @@ abstract class AddTagAction { super(getActionDisplayName()); // Get the current set of tag names. - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + DrawableTagsManager tagsManager = controller.getTagsManager(); List tagNames = null; try { tagNames = tagsManager.getAllTagNames(); @@ -112,7 +99,7 @@ abstract class AddTagAction { MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); tagNameItem.setOnAction((ActionEvent t) -> { addTag(tagName, NO_COMMENT); - refreshDirectoryTree(); + DrawableTagsManager.fireTagsChangedEvent(); }); quickTagMenu.getItems().add(tagNameItem); } @@ -152,7 +139,7 @@ abstract class AddTagAction { } else { new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } - refreshDirectoryTree(); + } }); }); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 358516694e..b3bb065644 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -30,6 +30,7 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -159,7 +160,7 @@ public class CategorizeAction extends AddTagAction { JOptionPane.showMessageDialog(null, "Unable to categorize " + fileID + ".", "Categorizing Error", JOptionPane.ERROR_MESSAGE); } - refreshDirectoryTree(); + DrawableTagsManager.fireTagsChangedEvent(); } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java similarity index 69% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 38a8e40256..6a1a54c30d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -19,19 +19,18 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.Collections; +import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; @@ -39,23 +38,19 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Action to delete the follow up tag a - * - * */ -public class DeleteTagAction extends Action { +public class DeleteFollowUpTagAction extends Action { - private static final Logger LOGGER = Logger.getLogger(DeleteTagAction.class.getName()); + private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTagAction.class.getName()); private final long fileID; private final DrawableFile file; private final ImageGalleryController controller; - private final ContentTag tag; - public DeleteTagAction(ImageGalleryController controller, DrawableFile file, ContentTag tag) { + public DeleteFollowUpTagAction(ImageGalleryController controller, DrawableFile file) { super("Delete Follow Up Tag"); this.controller = controller; this.file = file; this.fileID = file.getId(); - this.tag = tag; setEventHandler((ActionEvent t) -> { deleteTag(); }); @@ -63,27 +58,28 @@ public class DeleteTagAction extends Action { /** * - * @param fileID1 the value of fileID1 * - * @throws IllegalStateException + * */ - private void deleteTag() throws IllegalStateException { + private void deleteTag() { final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); final GroupManager groupManager = controller.getGroupManager(); + final DrawableTagsManager tagsManager = controller.getTagsManager(); try { + final TagName followUpTagName = tagsManager.getFollowUpTagName(); // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, tag.getName()), fileID); - sleuthKitCase.deleteContentTag(tag); -// -// List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); -// for (ContentTag ct : contentTagsByContent) { -// if (ct.getName().getDisplayName().equals(tagsManager.getFollowUpTagName().getDisplayName())) { -// sleuthKitCase.deleteContentTag(ct); -// } -// } - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); + + List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); + for (ContentTag ct : contentTagsByContent) { + if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { + sleuthKitCase.deleteContentTag(ct); + } + } + + DrawableTagsManager.fireTagsChangedEvent(); //make sure rest of ui hears category change. groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); @@ -91,4 +87,5 @@ public class DeleteTagAction extends Action { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index b043bf126d..49b0818e3b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -1058,7 +1058,7 @@ public final class DrawableDB { public List> getFilesWithCategory(Category cat) throws TskCoreException, IllegalArgumentException { try { List> files = new ArrayList<>(); - List contentTags = tskCase.getContentTagsByTagName(controller.getTagsManager().getTagName(cat)); + List contentTags = controller.getTagsManager().getContentTagsByTagName(controller.getTagsManager().getTagName(cat)); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile) { files.add(DrawableFile.create((AbstractFile) ct.getContent(), isFileAnalyzed(ct.getContent().getId()), @@ -1145,7 +1145,7 @@ public final class DrawableDB { * in. * * - * //TODO: why does this go to the SKC? don't we already have this in =fo + * //TODO: why does this go to the SKC? don't we already have this info * in the drawable db? */ @Nonnull diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 78bb8c6401..bd4c84dd5e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -170,19 +170,16 @@ public abstract class DrawableFile extends AbstractFile public Set getTagNames() { try { - List contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(this); - return contentTagsByContent.stream() + return getSleuthkitCase().getContentTagsByContent(this).stream() .map(Tag::getName) .collect(Collectors.toSet()); - } catch (TskCoreException ex) { Logger.getAnonymousLogger().log(Level.WARNING, "problem looking up " + DrawableAttribute.TAGS.getDisplayName() + " for " + file.getName(), ex); - return Collections.emptySet(); } catch (IllegalStateException ex) { Logger.getAnonymousLogger().log(Level.WARNING, "there is no case open; failed to look up " + DrawableAttribute.TAGS.getDisplayName() + " for " + file.getName()); - return Collections.emptySet(); } + return Collections.emptySet(); } @Deprecated @@ -275,7 +272,8 @@ public abstract class DrawableFile extends AbstractFile public void updateCategory() { try { - List contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(this); + + List contentTagsByContent = getSleuthkitCase().getContentTagsByContent(this); Category cat = null; for (ContentTag ct : contentTagsByContent) { if (ct.getName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index dab1f9743f..221c7ef4d1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -40,6 +40,9 @@ import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; import javax.swing.SortOrder; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -80,11 +83,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { private DrawableDB db; private final ImageGalleryController controller; + /** * map from {@link GroupKey}s to {@link DrawableGroup}s. All groups (even - * not - * fully analyzed or not visible groups could be in this map + * not fully analyzed or not visible groups could be in this map */ + @GuardedBy("this") private final Map, DrawableGroup> groupMap = new HashMap<>(); /** @@ -153,7 +157,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { Set> resultSet = new HashSet<>(); for (Comparable val : groupBy.getValue(file)) { if (groupBy == DrawableAttribute.TAGS) { - if (((TagName) val).getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) { + if (Category.isCategoryTagName((TagName) val) == false) { resultSet.add(new GroupKey(groupBy, val)); } } else { @@ -189,9 +193,24 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * or * null if no group exists for that key. */ - public DrawableGroup getGroupForKey(GroupKey groupKey) { + @Nullable + public DrawableGroup getGroupForKey(@Nonnull GroupKey groupKey) { synchronized (groupMap) { + if (groupKey.getAttribute() == DrawableAttribute.TAGS) { + + System.out.println(groupKey); +// @SuppressWarnings("unchecked") +// GroupKey tagKey = (GroupKey) groupKey; +// +// return groupMap.keySet().stream() +// .filter((GroupKey t) -> t.getAttribute() == DrawableAttribute.TAGS) +// .map((GroupKey t) -> (GroupKey) t) +// .filter(t -> tagKey.getValue().getDisplayName().equals(t.getValue().getDisplayName())) +// .findFirst().map(groupMap::get).orElse(null); + + } //else { return groupMap.get(groupKey); +// } } } @@ -443,7 +462,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { values = (List) Arrays.asList(Category.values()); break; case TAGS: - values = (List) Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse().stream() + values = (List) controller.getTagsManager().getTagNamesInUse().stream() .filter(t -> t.getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) .collect(Collectors.toList()); break; @@ -525,14 +544,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public Set getFileIDsWithTag(TagName tagName) throws TskCoreException { try { Set files = new HashSet<>(); - List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName); + List contentTags = controller.getTagsManager().getContentTagsByTagName(tagName); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { - files.add(ct.getContent().getId()); } } - return files; } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "TSK error getting files with Tag:" + tagName.getDisplayName(), ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 7f29af775e..52ac70def0 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -67,7 +67,7 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; -import org.sleuthkit.autopsy.imagegallery.actions.DeleteTagAction; +import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -257,17 +257,17 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @SuppressWarnings("deprecation") protected void initialize() { - followUpToggle.setOnAction((ActionEvent t) -> { - + followUpToggle.setOnAction((ActionEvent event) -> { if (followUpToggle.isSelected() == true) { - globalSelectionModel.clearAndSelect(fileID); try { - new AddDrawableTagAction(controller).addTag(ImageGalleryController.getDefault().getTagsManager().getFollowUpTagName(), ""); + final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); + globalSelectionModel.clearAndSelect(fileID); + new AddDrawableTagAction(controller).addTag(followUpTagName, ""); } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to add follow up tag. Could not load TagName.", ex); + LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); } } else { - new DeleteTagAction(controller, file).handle(t); + new DeleteFollowUpTagAction(controller, file).handle(event); } }); } @@ -290,7 +290,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie } protected boolean hasFollowUp() throws TskCoreException { - String followUpTagName = ImageGalleryController.getDefault().getTagsManager().getFollowUpTagName().getDisplayName(); + String followUpTagName = getController().getTagsManager().getFollowUpTagName().getDisplayName(); Collection tagNames = DrawableAttribute.TAGS.getValue(getFile()); return tagNames.stream().anyMatch((tn) -> tn.getDisplayName().equals(followUpTagName)); } From 2be00f7694988715e33f94f82c79e04e51e6df39 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 17 Jun 2015 15:54:34 -0400 Subject: [PATCH 100/198] more cleanup of Categories/Tags and listening to autopsy generated "Tag Events" -remove unused code from Category.java -use Category.isCategoryTagName instead of .getDisplayName().startsWith(Category.CATEGORY_PREFIX) -regroup when notified of Tag Change from autopsy --- .../imagegallery/DrawableTagsManager.java | 3 +- .../imagegallery/ImageGalleryController.java | 229 +++++++++--------- .../imagegallery/actions/AddTagAction.java | 4 +- .../actions/CategorizeAction.java | 4 +- .../imagegallery/datamodel/Category.java | 29 +-- .../datamodel/CategoryManager.java | 1 - .../imagegallery/datamodel/DrawableFile.java | 22 +- .../imagegallery/grouping/GroupManager.java | 17 +- .../imagegallery/gui/DrawableView.java | 32 +-- .../imagegallery/gui/MetaDataPane.java | 18 +- 10 files changed, 181 insertions(+), 178 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 7ba9ceb842..2639de7617 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -22,6 +22,7 @@ import com.google.common.eventbus.EventBus; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.logging.Level; import java.util.stream.Collectors; import org.sleuthkit.autopsy.casemodule.services.TagsManager; @@ -111,7 +112,7 @@ public class DrawableTagsManager { * @throws TskCoreException */ synchronized public TagName getFollowUpTagName() throws TskCoreException { - if (followUpTagName == null) { + if (Objects.isNull(followUpTagName)) { followUpTagName = getTagName(FOLLOW_UP); } return followUpTagName; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 4bed46a023..11fd505ba6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.imagegallery; import java.beans.PropertyChangeEvent; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.BlockingQueue; @@ -57,7 +58,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.History; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -68,6 +68,7 @@ import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; import org.sleuthkit.autopsy.imagegallery.gui.SummaryTablePane; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -83,25 +84,25 @@ import org.sleuthkit.datamodel.TskData; * control. */ public final class ImageGalleryController { - + private static final Logger LOGGER = Logger.getLogger(ImageGalleryController.class.getName()); - + private final Region infoOverLayBackground = new Region() { { setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY))); setOpacity(.4); } }; - + private static ImageGalleryController instance; - + public static synchronized ImageGalleryController getDefault() { if (instance == null) { instance = new ImageGalleryController(); } return instance; } - + private final History historyManager = new History<>(); /** @@ -109,75 +110,75 @@ public final class ImageGalleryController { * not listen to speed up ingest */ private final SimpleBooleanProperty listeningEnabled = new SimpleBooleanProperty(false); - + private final ReadOnlyIntegerWrapper queueSizeProperty = new ReadOnlyIntegerWrapper(0); - + private final ReadOnlyBooleanWrapper regroupDisabled = new ReadOnlyBooleanWrapper(false); - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private final ReadOnlyBooleanWrapper stale = new ReadOnlyBooleanWrapper(false); - + private final ReadOnlyBooleanWrapper metaDataCollapsed = new ReadOnlyBooleanWrapper(false); - + private final FileIDSelectionModel selectionModel = FileIDSelectionModel.getInstance(); - + private DBWorkerThread dbWorkerThread; - + private DrawableDB db; - + private final GroupManager groupManager = new GroupManager(this); private final HashSetManager hashSetManager = new HashSetManager(); private final CategoryManager categoryManager = new CategoryManager(this); private final DrawableTagsManager tagsManager = new DrawableTagsManager(null); - + private StackPane fullUIStackPane; - + private StackPane centralStackPane; - + private Node infoOverlay; private SleuthkitCase sleuthKitCase; - + public ReadOnlyBooleanProperty getMetaDataCollapsed() { return metaDataCollapsed.getReadOnlyProperty(); } - + public void setMetaDataCollapsed(Boolean metaDataCollapsed) { this.metaDataCollapsed.set(metaDataCollapsed); } - + private GroupViewState getViewState() { return historyManager.getCurrentState(); } - + public ReadOnlyBooleanProperty regroupDisabled() { return regroupDisabled.getReadOnlyProperty(); } - + public ReadOnlyObjectProperty viewState() { return historyManager.currentState(); } - + public synchronized FileIDSelectionModel getSelectionModel() { - + return selectionModel; } - + public GroupManager getGroupManager() { return groupManager; } - + public DrawableDB getDatabase() { return db; } - + synchronized public void setListeningEnabled(boolean enabled) { listeningEnabled.set(enabled); } - + synchronized boolean isListeningEnabled() { return listeningEnabled.get(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.ANY) void setStale(Boolean b) { Platform.runLater(() -> { @@ -187,18 +188,18 @@ public final class ImageGalleryController { new PerCaseProperties(Case.getCurrentCase()).setConfigSetting(ImageGalleryModule.getModuleName(), PerCaseProperties.STALE, b.toString()); } } - + public ReadOnlyBooleanProperty stale() { return stale.getReadOnlyProperty(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) boolean isStale() { return stale.get(); } - + private ImageGalleryController() { - + listeningEnabled.addListener((observable, oldValue, newValue) -> { //if we just turned on listening and a case is open and that case is not up to date if (newValue && !oldValue && Case.existsCurrentCase() && ImageGalleryModule.isDrawableDBStale(Case.getCurrentCase())) { @@ -206,28 +207,28 @@ public final class ImageGalleryController { queueDBWorkerTask(new CopyAnalyzedFiles()); } }); - + groupManager.getAnalyzedGroups().addListener((Observable o) -> { if (Case.isCaseOpen()) { checkForGroups(); } }); - + groupManager.getUnSeenGroups().addListener((Observable observable) -> { //if there are unseen groups and none being viewed if (groupManager.getUnSeenGroups().isEmpty() == false && (getViewState() == null || getViewState().getGroup() == null)) { advance(GroupViewState.tile(groupManager.getUnSeenGroups().get(0))); } }); - + viewState().addListener((Observable observable) -> { selectionModel.clearSelection(); }); - + regroupDisabled.addListener((Observable observable) -> { checkForGroups(); }); - + IngestManager.getInstance().addIngestModuleEventListener((PropertyChangeEvent evt) -> { Platform.runLater(this::updateRegroupDisabled); }); @@ -236,27 +237,27 @@ public final class ImageGalleryController { }); // metaDataCollapsed.bind(Toolbar.getDefault().showMetaDataProperty()); } - + public ReadOnlyBooleanProperty getCanAdvance() { return historyManager.getCanAdvance(); } - + public ReadOnlyBooleanProperty getCanRetreat() { return historyManager.getCanRetreat(); } - + public void advance(GroupViewState newState) { historyManager.advance(newState); } - + public GroupViewState advance() { return historyManager.advance(); } - + public GroupViewState retreat() { return historyManager.retreat(); } - + private void updateRegroupDisabled() { regroupDisabled.set(getFileUpdateQueueSizeProperty().get() > 0 || IngestManager.getInstance().isIngestRunning()); } @@ -278,7 +279,7 @@ public final class ImageGalleryController { new NoGroupsDialog("No groups are fully analyzed yet, but ingest is still ongoing. Please Wait.", new ProgressIndicator())); } - + } else if (getFileUpdateQueueSizeProperty().get() > 0) { replaceNotification(fullUIStackPane, new NoGroupsDialog("No groups are fully analyzed yet, but image / video data is still being populated. Please Wait.", @@ -292,19 +293,19 @@ public final class ImageGalleryController { replaceNotification(fullUIStackPane, new NoGroupsDialog("There are no images/videos in the added datasources.")); } - + } else if (!groupManager.isRegrouping()) { replaceNotification(centralStackPane, new NoGroupsDialog("There are no fully analyzed groups to display:" + " the current Group By setting resulted in no groups, " + "or no groups are fully analyzed but ingest is not running.")); } - + } else { clearNotification(); } } - + private void clearNotification() { //remove the ingest spinner if (fullUIStackPane != null) { @@ -315,27 +316,27 @@ public final class ImageGalleryController { centralStackPane.getChildren().remove(infoOverlay); } } - + private void replaceNotification(StackPane stackPane, Node newNode) { clearNotification(); - + infoOverlay = new StackPane(infoOverLayBackground, newNode); if (stackPane != null) { stackPane.getChildren().add(infoOverlay); } } - + private void restartWorker() { if (dbWorkerThread != null) { // Keep using the same worker thread if one exists return; } dbWorkerThread = new DBWorkerThread(); - + getFileUpdateQueueSizeProperty().addListener((Observable o) -> { Platform.runLater(this::updateRegroupDisabled); }); - + Thread th = new Thread(dbWorkerThread); th.setDaemon(false); // we want it to go away when it is done th.start(); @@ -350,7 +351,7 @@ public final class ImageGalleryController { if (Objects.nonNull(theNewCase)) { this.sleuthKitCase = theNewCase.getSleuthkitCase(); this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); - + setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); @@ -362,7 +363,9 @@ public final class ImageGalleryController { hashSetManager.setDb(db); categoryManager.setDb(db); tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); + tagsManager.registerListener(groupManager); SummaryTablePane.getDefault().refresh(); + } else { reset(); } @@ -379,9 +382,9 @@ public final class ImageGalleryController { Platform.runLater(() -> { historyManager.clear(); }); - Category.clearTagNames(); tagsManager.clearFollowUpTagName(); - + tagsManager.unregisterListener(groupManager); + Toolbar.getDefault(this).reset(); groupManager.clear(); if (db != null) { @@ -403,21 +406,21 @@ public final class ImageGalleryController { } dbWorkerThread.addTask(innerTask); } - + public DrawableFile getFileFromId(Long fileID) throws TskCoreException { return db.getFileFromID(fileID); } - + public void setStacks(StackPane fullUIStack, StackPane centralStack) { fullUIStackPane = fullUIStack; this.centralStackPane = centralStack; Platform.runLater(this::checkForGroups); } - + public ReadOnlyIntegerProperty getFileUpdateQueueSizeProperty() { return queueSizeProperty.getReadOnlyProperty(); } - + public ReadOnlyDoubleProperty regroupProgress() { return groupManager.regroupProgress(); } @@ -436,6 +439,10 @@ public final class ImageGalleryController { case CONTENT_CHANGED: //TODO: do we need to do anything here? -jm case DATA_ADDED: + ModuleDataEvent oldValue = (ModuleDataEvent) evt.getOldValue(); + if ("TagAction".equals(oldValue.getModuleName()) && oldValue.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { + getTagsManager().fireChange(Collections.singleton(-1L)); + } /* we could listen to DATA events and progressivly * update files, and get data from DataSource ingest * modules, but given that most modules don't post new @@ -489,15 +496,15 @@ public final class ImageGalleryController { } }); } - + public HashSetManager getHashSetManager() { return hashSetManager; } - + public CategoryManager getCategoryManager() { return categoryManager; } - + public DrawableTagsManager getTagsManager() { return tagsManager; } @@ -538,7 +545,7 @@ public final class ImageGalleryController { queueSizeProperty.set(workQueue.size()); }); } - + @Override public void run() { @@ -549,22 +556,22 @@ public final class ImageGalleryController { } try { InnerTask it = workQueue.take(); - + if (it.cancelled == false) { it.run(); } - + Platform.runLater(() -> { queueSizeProperty.set(workQueue.size()); }); - + } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); } } } } - + public synchronized SleuthkitCase getSleuthKitCase() { return sleuthKitCase; } @@ -573,55 +580,55 @@ public final class ImageGalleryController { * Abstract base class for task to be done on {@link DBWorkerThread} */ static public abstract class InnerTask implements Runnable { - + public double getProgress() { return progress.get(); } - + public final void updateProgress(Double workDone) { this.progress.set(workDone); } - + public String getMessage() { return message.get(); } - + public final void updateMessage(String Status) { this.message.set(Status); } SimpleObjectProperty state = new SimpleObjectProperty<>(Worker.State.READY); SimpleDoubleProperty progress = new SimpleDoubleProperty(this, "pregress"); SimpleStringProperty message = new SimpleStringProperty(this, "status"); - + public SimpleDoubleProperty progressProperty() { return progress; } - + public SimpleStringProperty messageProperty() { return message; } - + public Worker.State getState() { return state.get(); } - + protected void updateState(Worker.State newState) { state.set(newState); } - + public ReadOnlyObjectProperty stateProperty() { return new ReadOnlyObjectWrapper<>(state.get()); } - + protected InnerTask() { } - + protected volatile boolean cancelled = false; - + public void cancel() { updateState(Worker.State.CANCELLED); } - + protected boolean isCancelled() { return getState() == Worker.State.CANCELLED; } @@ -631,25 +638,25 @@ public final class ImageGalleryController { * Abstract base class for tasks associated with a file in the database */ static public abstract class FileTask extends InnerTask { - + private final AbstractFile file; - + public AbstractFile getFile() { return file; } - + public FileTask(AbstractFile f) { super(); this.file = f; } - + } /** * task that updates one file in database with results from ingest */ private class UpdateFileTask extends FileTask { - + public UpdateFileTask(AbstractFile f) { super(f); } @@ -676,7 +683,7 @@ public final class ImageGalleryController { * task that updates one file in database with results from ingest */ private class RemoveFileTask extends FileTask { - + public RemoveFileTask(AbstractFile f) { super(f); } @@ -695,7 +702,7 @@ public final class ImageGalleryController { Logger.getLogger(RemoveFileTask.class.getName()).log(Level.SEVERE, "Case was closed out from underneath RemoveFile task"); } } - + } } @@ -707,16 +714,16 @@ public final class ImageGalleryController { * adds them to the Drawable DB */ private class CopyAnalyzedFiles extends InnerTask { - + final private String DRAWABLE_QUERY = "name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "'"; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("populating analyzed image/video database"); - + @Override public void run() { progressHandle.start(); updateMessage("populating analyzed image/video database"); - + try { //grab all files with supported extension or detected mime types final List files = getSleuthKitCase().findAllFilesWhere(DRAWABLE_QUERY + " or tsk_files.obj_id in (select tsk_files.obj_id from tsk_files , blackboard_artifacts, blackboard_attributes" @@ -726,7 +733,7 @@ public final class ImageGalleryController { + " and blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID() + " and blackboard_attributes.value_text in ('" + StringUtils.join(ImageGalleryModule.getSupportedMimes(), "','") + "'))"); progressHandle.switchToDeterminate(files.size()); - + updateProgress(0.0); //do in transaction @@ -740,7 +747,7 @@ public final class ImageGalleryController { } final Boolean hasMimeType = ImageGalleryModule.hasSupportedMimeType(f); final boolean known = f.getKnown() == TskData.FileKnown.KNOWN; - + if (known) { db.removeFile(f.getId(), tr); //remove known files } else { @@ -760,38 +767,38 @@ public final class ImageGalleryController { } } } - + units++; final int prog = units; progressHandle.progress(f.getName(), units); updateProgress(prog - 1 / (double) files.size()); updateMessage(f.getName()); } - + progressHandle.finish(); - + progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); updateMessage("commiting image/video database"); updateProgress(1.0); - + progressHandle.start(); db.commitTransaction(tr, true); - + } catch (TskCoreException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.SEVERE, "Case was closed out from underneath CopyDataSource task", ex); } - + progressHandle.finish(); - + updateMessage( ""); updateProgress( -1.0); setStale(false); } - + } /** @@ -802,7 +809,7 @@ public final class ImageGalleryController { * netbeans and ImageGallery progress/status */ class PrePopulateDataSourceFiles extends InnerTask { - + private final Content dataSource; /** @@ -812,7 +819,7 @@ public final class ImageGalleryController { */ // (name like '.jpg' or name like '.png' ...) private final String DRAWABLE_QUERY = "(name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "') "; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("prepopulating image/video database"); /** @@ -838,7 +845,7 @@ public final class ImageGalleryController { final List files; try { List fsObjIds = new ArrayList<>(); - + String fsQuery; if (dataSource instanceof Image) { Image image = (Image) dataSource; @@ -852,7 +859,7 @@ public final class ImageGalleryController { else { fsQuery = "(fs_obj_id IS NULL) "; } - + files = getSleuthKitCase().findAllFilesWhere(fsQuery + " and " + DRAWABLE_QUERY); progressHandle.switchToDeterminate(files.size()); @@ -870,21 +877,21 @@ public final class ImageGalleryController { final int prog = units; progressHandle.progress(f.getName(), units); } - + progressHandle.finish(); progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); - + progressHandle.start(); db.commitTransaction(tr, false); - + } catch (TskCoreException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException | NullPointerException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "Case was closed out from underneath prepopulating database"); } - + progressHandle.finish(); } } - + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 95d3346175..65a7de525b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -95,7 +95,7 @@ abstract class AddTagAction { // a tag with the associated tag name. if (null != tagNames && !tagNames.isEmpty()) { for (final TagName tagName : tagNames) { - if (tagName.getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) { + if (Category.isNotCategoryTagName(tagName)) { MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); tagNameItem.setOnAction((ActionEvent t) -> { addTag(tagName, NO_COMMENT); @@ -134,7 +134,7 @@ abstract class AddTagAction { SwingUtilities.invokeLater(() -> { GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); if (null != tagNameAndComment) { - if (tagNameAndComment.getTagName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { + if (Category.isCategoryTagName(tagNameAndComment.getTagName())) { new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } else { new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index b3bb065644..1b84b005bf 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -141,9 +141,7 @@ public class CategorizeAction extends AddTagAction { List allContentTags = sleuthKitCase.getContentTagsByContent(file); //tsk db for (ContentTag ct : allContentTags) { - //this is bad: treating tags as categories as long as their names start with prefix - //TODO: abandon using tags for categories and instead add a new column to DrawableDB - if (ct.getName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { + if (Category.isCategoryTagName(ct.getName())) { sleuthKitCase.deleteContentTag(ct); //tsk db categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 0ded98426f..ee6a46098e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -43,30 +43,25 @@ public enum Category implements Comparable { Category::getDisplayName, Function.identity())); - public static final String CATEGORY_PREFIX = "CAT-"; - public static Category fromDisplayName(String displayName) { return nameMap.get(displayName); } - /** - * Use when closing a case to make sure everything is re-initialized in the - * next case. - */ - public static void clearTagNames() { - Category.ZERO.tagName = null; - Category.ONE.tagName = null; - Category.TWO.tagName = null; - Category.THREE.tagName = null; - Category.FOUR.tagName = null; - Category.FIVE.tagName = null; - } - public static boolean isCategoryTagName(TagName tName) { - return nameMap.containsKey(tName.getDisplayName()); + return isCategoryName(tName.getDisplayName()); } - private TagName tagName; + public static boolean isNotCategoryTagName(TagName tName) { + return isNotCategoryName(tName.getDisplayName()); + } + + public static boolean isCategoryName(String tName) { + return nameMap.containsKey(tName); + } + + public static boolean isNotCategoryName(String tName) { + return nameMap.containsKey(tName) == false; + } private final Color color; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 08ba1b17a5..0197c3c847 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -92,7 +92,6 @@ public class CategoryManager { this.db = db; categoryCounts.invalidateAll(); catTagNameMap.invalidateAll(); - Category.clearTagNames(); } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index bd4c84dd5e..4d3de0d553 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -46,7 +46,6 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBU import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.LONG; import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.SleuthkitItemVisitor; import org.sleuthkit.datamodel.Tag; @@ -111,7 +110,6 @@ public abstract class DrawableFile extends AbstractFile super(file.getSleuthkitCase(), file.getId(), file.getAttrType(), file.getAttrId(), file.getName(), file.getType(), file.getMetaAddr(), (int) file.getMetaSeq(), file.getDirType(), file.getMetaType(), null, new Integer(0).shortValue(), file.getSize(), file.getCtime(), file.getCrtime(), file.getAtime(), file.getMtime(), new Integer(0).shortValue(), file.getUid(), file.getGid(), file.getMd5Hash(), file.getKnown(), file.getParentPath()); this.analyzed = new SimpleBooleanProperty(analyzed); this.file = file; - } public abstract boolean isVideo(); @@ -272,20 +270,14 @@ public abstract class DrawableFile extends AbstractFile public void updateCategory() { try { + category.set(getSleuthkitCase().getContentTagsByContent(this).stream() + .map(Tag::getName).filter(Category::isCategoryTagName) + .findFirst() + .map(TagName::getDisplayName) + .map(Category::fromDisplayName) + .orElse(Category.ZERO) + ); - List contentTagsByContent = getSleuthkitCase().getContentTagsByContent(this); - Category cat = null; - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { - cat = Category.fromDisplayName(ct.getName().getDisplayName()); - break; - } - } - if (cat == null) { - category.set(Category.ZERO); - } else { - category.set(cat); - } } catch (TskCoreException ex) { Logger.getLogger(DrawableFile.class.getName()).log(Level.WARNING, "problem looking up category for file " + this.getName(), ex); } catch (IllegalStateException ex) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 221c7ef4d1..cd02ba9c0a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.grouping; +import com.google.common.eventbus.Subscribe; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; @@ -59,6 +60,7 @@ import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; +import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; @@ -157,7 +159,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { Set> resultSet = new HashSet<>(); for (Comparable val : groupBy.getValue(file)) { if (groupBy == DrawableAttribute.TAGS) { - if (Category.isCategoryTagName((TagName) val) == false) { + if (Category.isNotCategoryTagName((TagName) val)) { resultSet.add(new GroupKey(groupBy, val)); } } else { @@ -463,7 +465,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { break; case TAGS: values = (List) controller.getTagsManager().getTagNamesInUse().stream() - .filter(t -> t.getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) + .filter(Category::isNotCategoryTagName) .collect(Collectors.toList()); break; case ANALYZED: @@ -590,7 +592,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @param sortOrder * @param force true to force a full db query regroup */ - public > void regroup(final DrawableAttribute groupBy, final GroupSortBy sortBy, final SortOrder sortOrder, Boolean force) { + public synchronized > void regroup(final DrawableAttribute groupBy, final GroupSortBy sortBy, final SortOrder sortOrder, Boolean force) { if (!Case.isCaseOpen()) { return; @@ -633,6 +635,15 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { return regroupProgress.getReadOnlyProperty(); } + @Subscribe + public void handleAutopsyTagChange(TagsChangeEvent evt) { + if (groupBy == DrawableAttribute.TAGS + && evt.getFileIDs().size() == 1 + && evt.getFileIDs().contains(-1L)) { + regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); + } + } + /** * handle {@link FileUpdateEvent} sent from Db when files are * inserted/updated diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index ed0453ec0b..93dbae801e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -84,21 +84,25 @@ public interface DrawableView { } static Border getCategoryBorder(Category category) { - switch (category) { - case ONE: - return CAT1_BORDER; - case TWO: - return CAT2_BORDER; - case THREE: - return CAT3_BORDER; - case FOUR: - return CAT4_BORDER; - case FIVE: - return CAT5_BORDER; - case ZERO: - default: - return CAT0_BORDER; + if (category != null) { + switch (category) { + case ONE: + return CAT1_BORDER; + case TWO: + return CAT2_BORDER; + case THREE: + return CAT3_BORDER; + case FOUR: + return CAT4_BORDER; + case FIVE: + return CAT5_BORDER; + case ZERO: + default: + return CAT0_BORDER; + } + } else { + return CAT0_BORDER; } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index f9f6115d67..4ab6fff208 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -92,6 +92,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { } @FXML + @SuppressWarnings("unchecked") void initialize() { assert attributeColumn != null : "fx:id=\"attributeColumn\" was not injected: check your FXML file 'MetaDataPane.fxml'."; assert imageView != null : "fx:id=\"imageView\" was not injected: check your FXML file 'MetaDataPane.fxml'."; @@ -121,14 +122,12 @@ public class MetaDataPane extends AnchorPane implements DrawableView { attributeColumn.setPrefWidth(USE_COMPUTED_SIZE); valueColumn.setCellValueFactory((p) -> { - if (p.getValue().getKey() == DrawableAttribute.TAGS) { - return new SimpleStringProperty(((Collection) p.getValue().getValue()).stream() - .map(TagName::getDisplayName) - .filter((String t) -> t.startsWith(Category.CATEGORY_PREFIX) == false) - .collect(Collectors.joining(" ; ", "", ""))); - } else { - return new SimpleStringProperty(StringUtils.join((Iterable) p.getValue().getValue(), " ; ")); - } + return (p.getValue().getKey() == DrawableAttribute.TAGS) + ? new SimpleStringProperty(((Collection) p.getValue().getValue()).stream() + .map(TagName::getDisplayName) + .filter(Category::isNotCategoryName) + .collect(Collectors.joining(" ; "))) + : new SimpleStringProperty(StringUtils.join((Iterable) p.getValue().getValue(), " ; ")); }); valueColumn.setPrefWidth(USE_COMPUTED_SIZE); valueColumn.setCellFactory((p) -> new TableCell, ? extends Object>, String>() { @@ -150,9 +149,6 @@ public class MetaDataPane extends AnchorPane implements DrawableView { controller.getSelectionModel().lastSelectedProperty().addListener((observable, oldFileID, newFileID) -> { setFile(newFileID); }); - -// MetaDataPane.this.visibleProperty().bind(controller.getMetaDataCollapsed().not()); -// MetaDataPane.this.managedProperty().bind(controller.getMetaDataCollapsed().not()); } @Override From b1954998304e6bb8af9a97c54f440949cdf6ad07 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 17 Jun 2015 17:42:00 -0400 Subject: [PATCH 101/198] more work to keep autopsy and ImageGallery tags in sync add setFiles method to DrawableGroup; don't clear groups from GroupMap except for CaseChange; reuse groups via setFiles method when regrouping reselect group in navpanel after regroup --- .../imagegallery/DrawableTagsManager.java | 2 +- .../imagegallery/grouping/DrawableGroup.java | 25 +++++++-- .../imagegallery/grouping/GroupManager.java | 56 ++++++++----------- .../imagegallery/gui/navpanel/NavPanel.java | 6 ++ 4 files changed, 50 insertions(+), 39 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 2639de7617..149c7fd888 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index b59a1b8edd..386ae51d65 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -134,7 +134,7 @@ public class DrawableGroup implements Comparable { ((DrawableGroup) obj).groupKey); } - synchronized public void addFile(Long f) { + synchronized void addFile(Long f) { invalidateHashSetHitsCount(); if (fileIDs.contains(f) == false) { fileIDs.add(f); @@ -142,7 +142,21 @@ public class DrawableGroup implements Comparable { } } - synchronized public void removeFile(Long f) { + synchronized void setFiles(Set newFileIds) { + invalidateHashSetHitsCount(); + boolean filesRemoved = fileIDs.removeIf((Long t) -> newFileIds.contains(t) == false); + if (filesRemoved) { + seen.set(false); + } + for (Long f : newFileIds) { + if (fileIDs.contains(f) == false) { + fileIDs.add(f); + seen.set(false); + } + } + } + + synchronized void removeFile(Long f) { invalidateHashSetHitsCount(); if (fileIDs.removeAll(f)) { seen.set(false); @@ -151,11 +165,13 @@ public class DrawableGroup implements Comparable { // By default, sort by group key name @Override - public int compareTo(DrawableGroup other) { + public int compareTo(DrawableGroup other + ) { return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName()); } - void setSeen(boolean isSeen) { + void setSeen(boolean isSeen + ) { this.seen.set(isSeen); } @@ -166,4 +182,5 @@ public class DrawableGroup implements Comparable { public boolean isSeen() { return seen.get(); } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index cd02ba9c0a..a79b8e3b48 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -198,21 +198,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Nullable public DrawableGroup getGroupForKey(@Nonnull GroupKey groupKey) { synchronized (groupMap) { - if (groupKey.getAttribute() == DrawableAttribute.TAGS) { - - System.out.println(groupKey); -// @SuppressWarnings("unchecked") -// GroupKey tagKey = (GroupKey) groupKey; -// -// return groupMap.keySet().stream() -// .filter((GroupKey t) -> t.getAttribute() == DrawableAttribute.TAGS) -// .map((GroupKey t) -> (GroupKey) t) -// .filter(t -> tagKey.getValue().getDisplayName().equals(t.getValue().getDisplayName())) -// .findFirst().map(groupMap::get).orElse(null); - - } //else { return groupMap.get(groupKey); -// } } } @@ -255,7 +241,8 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { /** * make and return a new group with the given key and files. If a group - * already existed for that key, it will be replaced. + * already existed for that key, it will be updated to contain the given + * files. * * NOTE: this is the only API for making a new group. * @@ -265,28 +252,33 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @return the new DrawableGroup for the given key */ public DrawableGroup makeGroup(GroupKey groupKey, Set files) { - - Set newFiles = ObjectUtils.defaultIfNull(files, new HashSet()); - final boolean groupSeen = db.isGroupSeen(groupKey); - DrawableGroup g = new DrawableGroup(groupKey, newFiles, groupSeen); - - g.seenProperty().addListener((observable, oldSeen, newSeen) -> { - markGroupSeen(g, newSeen); - }); synchronized (groupMap) { - groupMap.put(groupKey, g); + if (groupMap.containsKey(groupKey)) { + DrawableGroup group = groupMap.get(groupKey); + group.setFiles(ObjectUtils.defaultIfNull(files, Collections.emptySet())); + return group; + } else { + final boolean groupSeen = db.isGroupSeen(groupKey); + DrawableGroup group = new DrawableGroup(groupKey, files, groupSeen); + group.seenProperty().addListener((observable, oldSeen, newSeen) -> { + markGroupSeen(group, newSeen); + }); + groupMap.put(groupKey, group); + return group; + } } - return g; } /** - * 'mark' the given group as seen. This removes it from the queue of groups + * 'mark' the given group as seen. This removes it from the queue of + * groups * to review, and is persisted in the drawable db. * * @param group the {@link DrawableGroup} to mark as seen */ @ThreadConfined(type = ThreadType.JFX) - public void markGroupSeen(DrawableGroup group, boolean seen) { + public void markGroupSeen(DrawableGroup group, boolean seen + ) { db.markGroupSeen(group.getGroupKey(), seen); group.setSeen(seen); if (seen) { @@ -314,9 +306,6 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { // If we're grouping by category, we don't want to remove empty groups. if (groupKey.getAttribute() != DrawableAttribute.CATEGORY) { if (group.fileIds().isEmpty()) { - synchronized (groupMap) { - groupMap.remove(groupKey, group); - } Platform.runLater(() -> { analyzedGroups.remove(group); unSeenGroups.remove(group); @@ -624,6 +613,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder)); }); } + } /** @@ -723,6 +713,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { controller.getTagsManager().fireChange(fileIDs); } break; + } } @@ -768,14 +759,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { unSeenGroups.clear(); } }); - synchronized (groupMap) { - groupMap.clear(); - } // Get the list of group keys final List vals = findValuesForAttribute(groupBy); - // Make a list of each group + // Make a list of each group final List groups = new ArrayList<>(); groupProgress.start(vals.size()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java index 09b025d75e..482ff66f7c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java @@ -155,6 +155,7 @@ public class NavPanel extends TabPane { initNavTree(); controller.getGroupManager().getAnalyzedGroups().addListener((ListChangeListener.Change change) -> { + TreeItem selectedItem = activeTreeProperty.get().getSelectionModel().getSelectedItem(); boolean wasPermuted = false; while (change.next()) { for (DrawableGroup g : change.getAddedSubList()) { @@ -175,6 +176,11 @@ public class NavPanel extends TabPane { if (wasPermuted) { rebuildTrees(); + } + if (selectedItem != null) { + Platform.runLater(() -> { + setFocusedGroup(selectedItem.getValue().getGroup()); + }); } }); From 2916f60dc7c2c6bdadd078e4a6e4246475bc6ee8 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 11:39:16 -0400 Subject: [PATCH 102/198] refactor in GroupManager, to make logic and flow cleaner split FileUpdateEvent handlers to seperate update and removed methods name DbWorkerThread, Thread --- .../autopsy/imagegallery/FileUpdateEvent.java | 5 +- .../imagegallery/ImageGalleryController.java | 222 ++++++------ .../imagegallery/actions/NextUnseenGroup.java | 1 + .../imagegallery/datamodel/DrawableDB.java | 2 +- .../imagegallery/grouping/DrawableGroup.java | 6 +- .../imagegallery/grouping/GroupManager.java | 323 +++++++----------- .../imagegallery/gui/navpanel/NavPanel.java | 4 +- 7 files changed, 238 insertions(+), 325 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java index 038ac4bafb..c2803a5090 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.imagegallery; import java.util.Collection; +import java.util.Collections; import java.util.EventListener; import java.util.HashSet; import java.util.Set; @@ -43,7 +44,7 @@ public class FileUpdateEvent { } public Collection getFileIDs() { - return fileIDs; + return Collections.unmodifiableCollection(fileIDs); } public DrawableAttribute getChangedAttribute() { @@ -86,5 +87,7 @@ public class FileUpdateEvent { public static interface FileUpdateListener extends EventListener { public void handleFileUpdate(FileUpdateEvent evt); + + public void handleFileRemoved(FileUpdateEvent evt); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 11fd505ba6..e649afbc39 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -84,25 +84,25 @@ import org.sleuthkit.datamodel.TskData; * control. */ public final class ImageGalleryController { - + private static final Logger LOGGER = Logger.getLogger(ImageGalleryController.class.getName()); - + private final Region infoOverLayBackground = new Region() { { setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY))); setOpacity(.4); } }; - + private static ImageGalleryController instance; - + public static synchronized ImageGalleryController getDefault() { if (instance == null) { instance = new ImageGalleryController(); } return instance; } - + private final History historyManager = new History<>(); /** @@ -110,75 +110,75 @@ public final class ImageGalleryController { * not listen to speed up ingest */ private final SimpleBooleanProperty listeningEnabled = new SimpleBooleanProperty(false); - + private final ReadOnlyIntegerWrapper queueSizeProperty = new ReadOnlyIntegerWrapper(0); - + private final ReadOnlyBooleanWrapper regroupDisabled = new ReadOnlyBooleanWrapper(false); - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private final ReadOnlyBooleanWrapper stale = new ReadOnlyBooleanWrapper(false); - + private final ReadOnlyBooleanWrapper metaDataCollapsed = new ReadOnlyBooleanWrapper(false); - + private final FileIDSelectionModel selectionModel = FileIDSelectionModel.getInstance(); - + private DBWorkerThread dbWorkerThread; - + private DrawableDB db; - + private final GroupManager groupManager = new GroupManager(this); private final HashSetManager hashSetManager = new HashSetManager(); private final CategoryManager categoryManager = new CategoryManager(this); private final DrawableTagsManager tagsManager = new DrawableTagsManager(null); - + private StackPane fullUIStackPane; - + private StackPane centralStackPane; - + private Node infoOverlay; private SleuthkitCase sleuthKitCase; - + public ReadOnlyBooleanProperty getMetaDataCollapsed() { return metaDataCollapsed.getReadOnlyProperty(); } - + public void setMetaDataCollapsed(Boolean metaDataCollapsed) { this.metaDataCollapsed.set(metaDataCollapsed); } - + private GroupViewState getViewState() { return historyManager.getCurrentState(); } - + public ReadOnlyBooleanProperty regroupDisabled() { return regroupDisabled.getReadOnlyProperty(); } - + public ReadOnlyObjectProperty viewState() { return historyManager.currentState(); } - + public synchronized FileIDSelectionModel getSelectionModel() { - + return selectionModel; } - + public GroupManager getGroupManager() { return groupManager; } - + public DrawableDB getDatabase() { return db; } - + synchronized public void setListeningEnabled(boolean enabled) { listeningEnabled.set(enabled); } - + synchronized boolean isListeningEnabled() { return listeningEnabled.get(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.ANY) void setStale(Boolean b) { Platform.runLater(() -> { @@ -188,18 +188,18 @@ public final class ImageGalleryController { new PerCaseProperties(Case.getCurrentCase()).setConfigSetting(ImageGalleryModule.getModuleName(), PerCaseProperties.STALE, b.toString()); } } - + public ReadOnlyBooleanProperty stale() { return stale.getReadOnlyProperty(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) boolean isStale() { return stale.get(); } - + private ImageGalleryController() { - + listeningEnabled.addListener((observable, oldValue, newValue) -> { //if we just turned on listening and a case is open and that case is not up to date if (newValue && !oldValue && Case.existsCurrentCase() && ImageGalleryModule.isDrawableDBStale(Case.getCurrentCase())) { @@ -207,28 +207,28 @@ public final class ImageGalleryController { queueDBWorkerTask(new CopyAnalyzedFiles()); } }); - + groupManager.getAnalyzedGroups().addListener((Observable o) -> { if (Case.isCaseOpen()) { checkForGroups(); } }); - + groupManager.getUnSeenGroups().addListener((Observable observable) -> { //if there are unseen groups and none being viewed if (groupManager.getUnSeenGroups().isEmpty() == false && (getViewState() == null || getViewState().getGroup() == null)) { advance(GroupViewState.tile(groupManager.getUnSeenGroups().get(0))); } }); - + viewState().addListener((Observable observable) -> { selectionModel.clearSelection(); }); - + regroupDisabled.addListener((Observable observable) -> { checkForGroups(); }); - + IngestManager.getInstance().addIngestModuleEventListener((PropertyChangeEvent evt) -> { Platform.runLater(this::updateRegroupDisabled); }); @@ -237,27 +237,27 @@ public final class ImageGalleryController { }); // metaDataCollapsed.bind(Toolbar.getDefault().showMetaDataProperty()); } - + public ReadOnlyBooleanProperty getCanAdvance() { return historyManager.getCanAdvance(); } - + public ReadOnlyBooleanProperty getCanRetreat() { return historyManager.getCanRetreat(); } - + public void advance(GroupViewState newState) { historyManager.advance(newState); } - + public GroupViewState advance() { return historyManager.advance(); } - + public GroupViewState retreat() { return historyManager.retreat(); } - + private void updateRegroupDisabled() { regroupDisabled.set(getFileUpdateQueueSizeProperty().get() > 0 || IngestManager.getInstance().isIngestRunning()); } @@ -279,7 +279,7 @@ public final class ImageGalleryController { new NoGroupsDialog("No groups are fully analyzed yet, but ingest is still ongoing. Please Wait.", new ProgressIndicator())); } - + } else if (getFileUpdateQueueSizeProperty().get() > 0) { replaceNotification(fullUIStackPane, new NoGroupsDialog("No groups are fully analyzed yet, but image / video data is still being populated. Please Wait.", @@ -293,19 +293,19 @@ public final class ImageGalleryController { replaceNotification(fullUIStackPane, new NoGroupsDialog("There are no images/videos in the added datasources.")); } - + } else if (!groupManager.isRegrouping()) { replaceNotification(centralStackPane, new NoGroupsDialog("There are no fully analyzed groups to display:" + " the current Group By setting resulted in no groups, " + "or no groups are fully analyzed but ingest is not running.")); } - + } else { clearNotification(); } } - + private void clearNotification() { //remove the ingest spinner if (fullUIStackPane != null) { @@ -316,28 +316,28 @@ public final class ImageGalleryController { centralStackPane.getChildren().remove(infoOverlay); } } - + private void replaceNotification(StackPane stackPane, Node newNode) { clearNotification(); - + infoOverlay = new StackPane(infoOverLayBackground, newNode); if (stackPane != null) { stackPane.getChildren().add(infoOverlay); } } - + private void restartWorker() { if (dbWorkerThread != null) { // Keep using the same worker thread if one exists return; } dbWorkerThread = new DBWorkerThread(); - + getFileUpdateQueueSizeProperty().addListener((Observable o) -> { Platform.runLater(this::updateRegroupDisabled); }); - - Thread th = new Thread(dbWorkerThread); + + Thread th = new Thread(dbWorkerThread, "DB-Worker-Thread"); th.setDaemon(false); // we want it to go away when it is done th.start(); } @@ -351,7 +351,7 @@ public final class ImageGalleryController { if (Objects.nonNull(theNewCase)) { this.sleuthKitCase = theNewCase.getSleuthkitCase(); this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); - + setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); @@ -365,7 +365,7 @@ public final class ImageGalleryController { tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); tagsManager.registerListener(groupManager); SummaryTablePane.getDefault().refresh(); - + } else { reset(); } @@ -384,7 +384,7 @@ public final class ImageGalleryController { }); tagsManager.clearFollowUpTagName(); tagsManager.unregisterListener(groupManager); - + Toolbar.getDefault(this).reset(); groupManager.clear(); if (db != null) { @@ -406,21 +406,21 @@ public final class ImageGalleryController { } dbWorkerThread.addTask(innerTask); } - + public DrawableFile getFileFromId(Long fileID) throws TskCoreException { return db.getFileFromID(fileID); } - + public void setStacks(StackPane fullUIStack, StackPane centralStack) { fullUIStackPane = fullUIStack; this.centralStackPane = centralStack; Platform.runLater(this::checkForGroups); } - + public ReadOnlyIntegerProperty getFileUpdateQueueSizeProperty() { return queueSizeProperty.getReadOnlyProperty(); } - + public ReadOnlyDoubleProperty regroupProgress() { return groupManager.regroupProgress(); } @@ -496,15 +496,15 @@ public final class ImageGalleryController { } }); } - + public HashSetManager getHashSetManager() { return hashSetManager; } - + public CategoryManager getCategoryManager() { return categoryManager; } - + public DrawableTagsManager getTagsManager() { return tagsManager; } @@ -545,7 +545,7 @@ public final class ImageGalleryController { queueSizeProperty.set(workQueue.size()); }); } - + @Override public void run() { @@ -556,22 +556,22 @@ public final class ImageGalleryController { } try { InnerTask it = workQueue.take(); - + if (it.cancelled == false) { it.run(); } - + Platform.runLater(() -> { queueSizeProperty.set(workQueue.size()); }); - + } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); } } } } - + public synchronized SleuthkitCase getSleuthKitCase() { return sleuthKitCase; } @@ -580,55 +580,55 @@ public final class ImageGalleryController { * Abstract base class for task to be done on {@link DBWorkerThread} */ static public abstract class InnerTask implements Runnable { - + public double getProgress() { return progress.get(); } - + public final void updateProgress(Double workDone) { this.progress.set(workDone); } - + public String getMessage() { return message.get(); } - + public final void updateMessage(String Status) { this.message.set(Status); } SimpleObjectProperty state = new SimpleObjectProperty<>(Worker.State.READY); SimpleDoubleProperty progress = new SimpleDoubleProperty(this, "pregress"); SimpleStringProperty message = new SimpleStringProperty(this, "status"); - + public SimpleDoubleProperty progressProperty() { return progress; } - + public SimpleStringProperty messageProperty() { return message; } - + public Worker.State getState() { return state.get(); } - + protected void updateState(Worker.State newState) { state.set(newState); } - + public ReadOnlyObjectProperty stateProperty() { return new ReadOnlyObjectWrapper<>(state.get()); } - + protected InnerTask() { } - + protected volatile boolean cancelled = false; - + public void cancel() { updateState(Worker.State.CANCELLED); } - + protected boolean isCancelled() { return getState() == Worker.State.CANCELLED; } @@ -638,25 +638,25 @@ public final class ImageGalleryController { * Abstract base class for tasks associated with a file in the database */ static public abstract class FileTask extends InnerTask { - + private final AbstractFile file; - + public AbstractFile getFile() { return file; } - + public FileTask(AbstractFile f) { super(); this.file = f; } - + } /** * task that updates one file in database with results from ingest */ private class UpdateFileTask extends FileTask { - + public UpdateFileTask(AbstractFile f) { super(f); } @@ -683,7 +683,7 @@ public final class ImageGalleryController { * task that updates one file in database with results from ingest */ private class RemoveFileTask extends FileTask { - + public RemoveFileTask(AbstractFile f) { super(f); } @@ -702,7 +702,7 @@ public final class ImageGalleryController { Logger.getLogger(RemoveFileTask.class.getName()).log(Level.SEVERE, "Case was closed out from underneath RemoveFile task"); } } - + } } @@ -714,16 +714,16 @@ public final class ImageGalleryController { * adds them to the Drawable DB */ private class CopyAnalyzedFiles extends InnerTask { - + final private String DRAWABLE_QUERY = "name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "'"; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("populating analyzed image/video database"); - + @Override public void run() { progressHandle.start(); updateMessage("populating analyzed image/video database"); - + try { //grab all files with supported extension or detected mime types final List files = getSleuthKitCase().findAllFilesWhere(DRAWABLE_QUERY + " or tsk_files.obj_id in (select tsk_files.obj_id from tsk_files , blackboard_artifacts, blackboard_attributes" @@ -733,7 +733,7 @@ public final class ImageGalleryController { + " and blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID() + " and blackboard_attributes.value_text in ('" + StringUtils.join(ImageGalleryModule.getSupportedMimes(), "','") + "'))"); progressHandle.switchToDeterminate(files.size()); - + updateProgress(0.0); //do in transaction @@ -747,7 +747,7 @@ public final class ImageGalleryController { } final Boolean hasMimeType = ImageGalleryModule.hasSupportedMimeType(f); final boolean known = f.getKnown() == TskData.FileKnown.KNOWN; - + if (known) { db.removeFile(f.getId(), tr); //remove known files } else { @@ -767,38 +767,38 @@ public final class ImageGalleryController { } } } - + units++; final int prog = units; progressHandle.progress(f.getName(), units); updateProgress(prog - 1 / (double) files.size()); updateMessage(f.getName()); } - + progressHandle.finish(); - + progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); updateMessage("commiting image/video database"); updateProgress(1.0); - + progressHandle.start(); db.commitTransaction(tr, true); - + } catch (TskCoreException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.SEVERE, "Case was closed out from underneath CopyDataSource task", ex); } - + progressHandle.finish(); - + updateMessage( ""); updateProgress( -1.0); setStale(false); } - + } /** @@ -809,7 +809,7 @@ public final class ImageGalleryController { * netbeans and ImageGallery progress/status */ class PrePopulateDataSourceFiles extends InnerTask { - + private final Content dataSource; /** @@ -819,7 +819,7 @@ public final class ImageGalleryController { */ // (name like '.jpg' or name like '.png' ...) private final String DRAWABLE_QUERY = "(name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "') "; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("prepopulating image/video database"); /** @@ -845,7 +845,7 @@ public final class ImageGalleryController { final List files; try { List fsObjIds = new ArrayList<>(); - + String fsQuery; if (dataSource instanceof Image) { Image image = (Image) dataSource; @@ -859,7 +859,7 @@ public final class ImageGalleryController { else { fsQuery = "(fs_obj_id IS NULL) "; } - + files = getSleuthKitCase().findAllFilesWhere(fsQuery + " and " + DRAWABLE_QUERY); progressHandle.switchToDeterminate(files.size()); @@ -877,21 +877,21 @@ public final class ImageGalleryController { final int prog = units; progressHandle.progress(f.getName(), units); } - + progressHandle.finish(); progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); - + progressHandle.start(); db.commitTransaction(tr, false); - + } catch (TskCoreException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException | NullPointerException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "Case was closed out from underneath prepopulating database"); } - + progressHandle.finish(); } } - + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java index ab8ef06401..550581d8b2 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java @@ -51,6 +51,7 @@ public class NextUnseenGroup extends Action { this.controller = controller; setGraphic(new ImageView(ADVANCE)); + //TODO: do we need both these listeners? controller.getGroupManager().getAnalyzedGroups().addListener((Observable observable) -> { Platform.runLater(this::updateButton); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 49b0818e3b..9dfbbdc239 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -656,7 +656,7 @@ public final class DrawableDB { private void fireRemovedFiles(Collection fileIDs) { for (FileUpdateEvent.FileUpdateListener listener : updateListeners) { - listener.handleFileUpdate(FileUpdateEvent.newRemovedEvent(fileIDs)); + listener.handleFileRemoved(FileUpdateEvent.newRemovedEvent(fileIDs)); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index 386ae51d65..0ad8b2640e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -165,13 +165,11 @@ public class DrawableGroup implements Comparable { // By default, sort by group key name @Override - public int compareTo(DrawableGroup other - ) { + public int compareTo(DrawableGroup other) { return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName()); } - void setSeen(boolean isSeen - ) { + void setSeen(boolean isSeen) { this.seen.set(isSeen); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index a79b8e3b48..2027dae724 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-4 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,10 +25,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ExecutorService; @@ -41,12 +43,14 @@ import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javafx.collections.transformation.SortedList; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; import javax.swing.SortOrder; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; @@ -98,16 +102,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { */ @ThreadConfined(type = ThreadType.JFX) private final ObservableList analyzedGroups = FXCollections.observableArrayList(); + private final SortedList unmodifiableAnalyzedGroups = new SortedList<>(analyzedGroups); - private final ObservableList publicAnalyzedGroupsWrapper = FXCollections.unmodifiableObservableList(analyzedGroups); - /** - * list of unseen groups - */ + /** list of unseen groups */ @ThreadConfined(type = ThreadType.JFX) private final ObservableList unSeenGroups = FXCollections.observableArrayList(); - -// private final SortedList sortedUnSeenGroups = new SortedList<>(unSeenGroups); - private final ObservableList publicSortedUnseenGroupsWrapper = FXCollections.unmodifiableObservableList(unSeenGroups); + private final SortedList unmodifiableUnSeenGroups = new SortedList<>(unSeenGroups); private ReGroupTask groupByTask; @@ -117,7 +117,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { private volatile DrawableAttribute groupBy = DrawableAttribute.PATH; private volatile SortOrder sortOrder = SortOrder.ASCENDING; - private ReadOnlyDoubleWrapper regroupProgress = new ReadOnlyDoubleWrapper(); + private final ReadOnlyDoubleWrapper regroupProgress = new ReadOnlyDoubleWrapper(); public void setDB(DrawableDB db) { this.db = db; @@ -125,13 +125,15 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); } + @SuppressWarnings("ReturnOfCollectionOrArrayField") public ObservableList getAnalyzedGroups() { - return publicAnalyzedGroupsWrapper; + return unmodifiableAnalyzedGroups; } @ThreadConfined(type = ThreadType.JFX) + @SuppressWarnings("ReturnOfCollectionOrArrayField") public ObservableList getUnSeenGroups() { - return publicSortedUnseenGroupsWrapper; + return unmodifiableUnSeenGroups; } /** @@ -239,36 +241,6 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } - /** - * make and return a new group with the given key and files. If a group - * already existed for that key, it will be updated to contain the given - * files. - * - * NOTE: this is the only API for making a new group. - * - * @param groupKey the groupKey that uniquely identifies this group - * @param files a list of fileids that are members of this group - * - * @return the new DrawableGroup for the given key - */ - public DrawableGroup makeGroup(GroupKey groupKey, Set files) { - synchronized (groupMap) { - if (groupMap.containsKey(groupKey)) { - DrawableGroup group = groupMap.get(groupKey); - group.setFiles(ObjectUtils.defaultIfNull(files, Collections.emptySet())); - return group; - } else { - final boolean groupSeen = db.isGroupSeen(groupKey); - DrawableGroup group = new DrawableGroup(groupKey, files, groupSeen); - group.seenProperty().addListener((observable, oldSeen, newSeen) -> { - markGroupSeen(group, newSeen); - }); - groupMap.put(groupKey, group); - return group; - } - } - } - /** * 'mark' the given group as seen. This removes it from the queue of * groups @@ -277,15 +249,13 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @param group the {@link DrawableGroup} to mark as seen */ @ThreadConfined(type = ThreadType.JFX) - public void markGroupSeen(DrawableGroup group, boolean seen - ) { + public void markGroupSeen(DrawableGroup group, boolean seen) { db.markGroupSeen(group.getGroupKey(), seen); group.setSeen(seen); if (seen) { unSeenGroups.removeAll(group); } else if (unSeenGroups.contains(group) == false) { unSeenGroups.add(group); - FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); } } @@ -297,7 +267,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @param groupKey the value of groupKey * @param fileID the value of file */ - public synchronized void removeFromGroup(GroupKey groupKey, final Long fileID) { + public synchronized DrawableGroup removeFromGroup(GroupKey groupKey, final Long fileID) { //get grouping this file would be in final DrawableGroup group = getGroupForKey(groupKey); if (group != null) { @@ -311,74 +281,10 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { unSeenGroups.remove(group); }); } - } else { } } - } - public synchronized void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup) { - populateAnalyzedGroup(groupKey, filesInGroup, null); - } - - /** - * create a group with the given GroupKey and file ids and add it to the - * analyzed group list. - * - * @param groupKey - * @param filesInGroup - */ - private synchronized > void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup, ReGroupTask task) { - - /* if this is not part of a regroup task or it is but the task is not - * cancelled... - * - * this allows us to stop if a regroup task has been cancelled (e.g. the - * user picked a different group by attribute, while the current task - * was still running) */ - if (task == null || (task.isCancelled() == false)) { - DrawableGroup g = makeGroup(groupKey, filesInGroup); - populateAnalyzedGroup(g, task); - } - } - - private synchronized void populateAnalyzedGroup(final DrawableGroup g, ReGroupTask task) { - - if (task == null || (task.isCancelled() == false)) { - final boolean groupSeen = db.isGroupSeen(g.getGroupKey()); - - Platform.runLater(() -> { - if (analyzedGroups.contains(g) == false) { - analyzedGroups.add(g); - } - markGroupSeen(g, groupSeen); - - }); - } - } - - /** - * check if the group for the given groupkey is analyzed - * - * @param groupKey - * - * @return null if this group is not analyzed or a list of file ids in - * this - * group if they are all analyzed - */ - public Set checkAnalyzed(final GroupKey groupKey) { - try { - /* for attributes other than path we can't be sure a group is fully - * analyzed because we don't know all the files that will be a part - * of that group */ - if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { - return getFileIDsInGroup(groupKey); - } else { - return null; - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); - return null; - } + return group; } /** @@ -595,9 +501,6 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { if (groupByTask != null) { groupByTask.cancel(true); } - Platform.runLater(() -> { - FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); - }); groupByTask = new ReGroupTask(groupBy, sortBy, sortOrder); Platform.runLater(() -> { @@ -605,15 +508,14 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { }); regroupExecutor.submit(groupByTask); } else { - // just resort the list of groups + // resort the list of groups setSortBy(sortBy); setSortOrder(sortOrder); Platform.runLater(() -> { - FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); - FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder)); + unmodifiableAnalyzedGroups.setComparator(sortBy.getGrpComparator(sortOrder)); + unmodifiableUnSeenGroups.setComparator(sortBy.getGrpComparator(sortOrder)); }); } - } /** @@ -634,86 +536,114 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } + @Override + synchronized public void handleFileRemoved(FileUpdateEvent evt) { + Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.REMOVE); + + for (final long fileId : evt.getFileIDs()) { + //get grouping(s) this file would be in + Set> groupsForFile = getGroupKeysForFileID(fileId); + + for (GroupKey gk : groupsForFile) { + DrawableGroup g = removeFromGroup(gk, fileId); + + if (g == null) { + // It may be that this was the last unanalyzed file in the group, so test + // whether the group is now fully analyzed. + popuplateIfAnalyzed(gk, null); + } + } + } + } + /** * handle {@link FileUpdateEvent} sent from Db when files are * inserted/updated * - * TODO: why isn't this just two methods! - * * @param evt */ @Override synchronized public void handleFileUpdate(FileUpdateEvent evt) { - final Collection fileIDs = evt.getFileIDs(); - switch (evt.getUpdateType()) { - case REMOVE: - for (final long fileId : fileIDs) { - //get grouping(s) this file would be in - Set> groupsForFile = getGroupKeysForFileID(fileId); + Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.UPDATE); + Collection fileIDs = evt.getFileIDs(); + /** + * TODO: is there a way to optimize this to avoid quering to db + * so much. the problem is that as a new files are analyzed they + * might be in new groups( if we are grouping by say make or + * model) -jm + */ + for (long fileId : fileIDs) { - for (GroupKey gk : groupsForFile) { - removeFromGroup(gk, fileId); + controller.getHashSetManager().invalidateHashSetsForFile(fileId); - DrawableGroup g = getGroupForKey(gk); + //get grouping(s) this file would be in + Set> groupsForFile = getGroupKeysForFileID(fileId); - if (g == null) { - // It may be that this was the last unanalyzed file in the group, so test - // whether the group is now fully analyzed. - //TODO: use method in groupmanager ? - Set checkAnalyzed = checkAnalyzed(gk); - if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui - populateAnalyzedGroup(gk, checkAnalyzed); + for (GroupKey gk : groupsForFile) { + DrawableGroup g = getGroupForKey(gk); + + if (g == null) { + //if there wasn't already a group check if there should be one now + popuplateIfAnalyzed(gk, null); + } else { + //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. + g.addFile(fileId); + } + } + } + + //we fire this event for all files so that the category counts get updated during initial db population + controller.getCategoryManager().fireChange(fileIDs); + + if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { + controller.getTagsManager().fireChange(fileIDs); + } + } + + private void popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { + + if (Objects.nonNull(task) && (task.isCancelled())) { + /* if this method call is part of a ReGroupTask and that task is + * cancelled, no-op + * + * this allows us to stop if a regroup task has been cancelled (e.g. + * the user picked a different group by attribute, while the + * current task was still running) */ + } else { // no task or un-cancelled task + if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { + /* for attributes other than path we can't be sure a group is + * fully analyzed because we don't know all the files that + * will be a part of that group */ + + try { + Set fileIDs = getFileIDsInGroup(groupKey); + if (Objects.nonNull(fileIDs)) { + DrawableGroup group; + final boolean groupSeen = db.isGroupSeen(groupKey); + synchronized (groupMap) { + if (groupMap.containsKey(groupKey)) { + group = groupMap.get(groupKey); + group.setFiles(ObjectUtils.defaultIfNull(fileIDs, Collections.emptySet())); + } else { + + group = new DrawableGroup(groupKey, fileIDs, groupSeen); + group.seenProperty().addListener((observable, oldSeen, newSeen) -> { + markGroupSeen(group, newSeen); + }); + groupMap.put(groupKey, group); } } - } - } - - break; - case UPDATE: - - /** - * TODO: is there a way to optimize this to avoid quering to db - * so much. the problem is that as a new files are analyzed they - * might be in new groups( if we are grouping by say make or - * model) - * - * TODO: Should this be a InnerTask so it can be done by the - * WorkerThread? Is it already done by worker thread because - * handlefileUpdate is invoked through call on db in UpdateTask - * innertask? -jm - */ - for (final long fileId : fileIDs) { - - controller.getHashSetManager().invalidateHashSetsForFile(fileId); - - //get grouping(s) this file would be in - Set> groupsForFile = getGroupKeysForFileID(fileId); - - for (GroupKey gk : groupsForFile) { - DrawableGroup g = getGroupForKey(gk); - - if (g != null) { - //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. - g.addFile(fileId); - } else { - //if there wasn't already a group check if there should be one now - //TODO: use method in groupmanager ? - Set checkAnalyzed = checkAnalyzed(gk); - if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui - populateAnalyzedGroup(gk, checkAnalyzed); + Platform.runLater(() -> { + if (analyzedGroups.contains(group) == false) { + analyzedGroups.add(group); } - } + markGroupSeen(group, groupSeen); + }); } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); } - - //we fire this event for all files so that the category counts get updated during initial db population - controller.getCategoryManager().fireChange(fileIDs); - - if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { - controller.getTagsManager().fireChange(fileIDs); - } - break; - + } } } @@ -755,17 +685,16 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { groupProgress = ProgressHandleFactory.createHandle("regrouping files by " + groupBy.attrName.toString() + " sorted by " + sortBy.name() + " in " + sortOrder.toString() + " order", this); Platform.runLater(() -> { analyzedGroups.clear(); - synchronized (unSeenGroups) { - unSeenGroups.clear(); - } + unSeenGroups.clear(); + + final Comparator grpComparator = sortBy.getGrpComparator(sortOrder); + unmodifiableAnalyzedGroups.setComparator(grpComparator); + unmodifiableUnSeenGroups.setComparator(grpComparator); }); // Get the list of group keys final List vals = findValuesForAttribute(groupBy); - // Make a list of each group - final List groups = new ArrayList<>(); - groupProgress.start(vals.size()); int p = 0; @@ -778,25 +707,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { updateMessage("regrouping files by " + groupBy.attrName.toString() + " : " + val); updateProgress(p, vals.size()); groupProgress.progress("regrouping files by " + groupBy.attrName.toString() + " : " + val, p); - //check if this group is analyzed - final GroupKey groupKey = new GroupKey<>(groupBy, val); - - Set checkAnalyzed = checkAnalyzed(groupKey); - if (checkAnalyzed != null) { // != null => the group is analyzed, so add it to the ui - - // makeGroup will create the group and add it to the map groupMap, but does not - // update anything else - DrawableGroup g = makeGroup(groupKey, checkAnalyzed); - groups.add(g); - } - } - - // Sort the group list - Collections.sort(groups, sortBy.getGrpComparator(sortOrder)); - - // Officially add all groups in order - for (DrawableGroup g : groups) { - populateAnalyzedGroup(g, ReGroupTask.this); + popuplateIfAnalyzed(new GroupKey(groupBy, val), this); } updateProgress(1, 1); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java index 482ff66f7c..efc855e8ca 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java @@ -171,13 +171,14 @@ public class NavPanel extends TabPane { if (change.wasPermutated()) { // Handle this afterward wasPermuted = true; + break; } } if (wasPermuted) { rebuildTrees(); } - if (selectedItem != null) { + if (selectedItem != null && selectedItem.getValue().getGroup() != null) { Platform.runLater(() -> { setFocusedGroup(selectedItem.getValue().getGroup()); }); @@ -268,7 +269,6 @@ public class NavPanel extends TabPane { } private static List groupingToPath(DrawableGroup g) { - if (g.groupKey.getAttribute() == DrawableAttribute.PATH) { String path = g.groupKey.getValueDisplayName(); From 8b26c43b2065488543c3abcd11657610c6c02539 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 13:51:37 -0400 Subject: [PATCH 103/198] rename method; add synchronization; remove singletonness from SummaryTablePane --- .../imagegallery/DrawableTagsManager.java | 4 ++-- .../imagegallery/ImageGalleryController.java | 4 +--- .../ImageGalleryTopComponent.java | 2 +- .../actions/AddDrawableTagAction.java | 2 +- .../imagegallery/actions/AddTagAction.java | 4 ++-- .../actions/CategorizeAction.java | 2 +- .../actions/DeleteFollowUpTagAction.java | 2 +- .../datamodel/CategoryManager.java | 21 +++++++++++++------ .../imagegallery/gui/SummaryTablePane.java | 18 ++++++---------- 9 files changed, 30 insertions(+), 29 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 149c7fd888..7e0303fe4d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -78,7 +78,7 @@ public class DrawableTagsManager { } /** - * fire a CategoryChangeEvent with the given fileIDs + * fire a TagsChangeEvent with the given fileIDs * * @param fileIDs */ @@ -188,7 +188,7 @@ public class DrawableTagsManager { * had a chance to add that so, we fire these events and the tree * refreshes based on them. */ - static public void fireTagsChangedEvent() { + static public void refreshTagsInAutopsy() { IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index e649afbc39..6c54db8185 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -65,7 +65,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; -import org.sleuthkit.autopsy.imagegallery.gui.SummaryTablePane; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -364,8 +363,6 @@ public final class ImageGalleryController { categoryManager.setDb(db); tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); tagsManager.registerListener(groupManager); - SummaryTablePane.getDefault().refresh(); - } else { reset(); } @@ -442,6 +439,7 @@ public final class ImageGalleryController { ModuleDataEvent oldValue = (ModuleDataEvent) evt.getOldValue(); if ("TagAction".equals(oldValue.getModuleName()) && oldValue.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { getTagsManager().fireChange(Collections.singleton(-1L)); + getCategoryManager().invalidateCaches(); } /* we could listen to DATA events and progressivly * update files, and get data from DataSource ingest diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java index e5c2bb3bd6..850230cb88 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java @@ -150,7 +150,7 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl metaDataTable = new MetaDataPane(controller); navPanel = new NavPanel(controller); - leftPane = new VBox(navPanel, SummaryTablePane.getDefault()); + leftPane = new VBox(navPanel, new SummaryTablePane(controller)); SplitPane.setResizableWithParent(leftPane, Boolean.FALSE); SplitPane.setResizableWithParent(groupPane, Boolean.TRUE); SplitPane.setResizableWithParent(metaDataTable, Boolean.FALSE); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index 9d5c5f277b..e88c51f12b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -90,7 +90,7 @@ public class AddDrawableTagAction extends AddTagAction { //make sure rest of ui hears category change. controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 65a7de525b..a82244d368 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -99,7 +99,7 @@ abstract class AddTagAction { MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); tagNameItem.setOnAction((ActionEvent t) -> { addTag(tagName, NO_COMMENT); - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); }); quickTagMenu.getItems().add(tagNameItem); } @@ -120,7 +120,7 @@ abstract class AddTagAction { TagName tagName = GetTagNameDialog.doDialog(); if (tagName != null) { addTag(tagName, NO_COMMENT); - refreshDirectoryTree(); + } }); }); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 1b84b005bf..27f599cafe 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -158,7 +158,7 @@ public class CategorizeAction extends AddTagAction { JOptionPane.showMessageDialog(null, "Unable to categorize " + fileID + ".", "Categorizing Error", JOptionPane.ERROR_MESSAGE); } - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 6a1a54c30d..bba6d5e4dc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -79,7 +79,7 @@ public class DeleteFollowUpTagAction extends Action { } } - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); //make sure rest of ui hears category change. groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 0197c3c847..f8b0e6beb1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -23,6 +23,7 @@ import com.google.common.cache.LoadingCache; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import java.util.Collection; +import java.util.Collections; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; @@ -44,6 +45,7 @@ import org.sleuthkit.datamodel.TagName; public class CategoryManager { private static final java.util.logging.Logger LOGGER = Logger.getLogger(CategoryManager.class.getName()); + private final ImageGalleryController controller; /** @@ -88,10 +90,17 @@ public class CategoryManager { * * @param db */ - public void setDb(DrawableDB db) { + synchronized public void setDb(DrawableDB db) { this.db = db; categoryCounts.invalidateAll(); catTagNameMap.invalidateAll(); + fireChange(Collections.singleton(-1L)); + } + + synchronized public void invalidateCaches() { + categoryCounts.invalidateAll(); + catTagNameMap.invalidateAll(); + fireChange(Collections.singleton(-1L)); } /** @@ -101,7 +110,7 @@ public class CategoryManager { * * @return the long the number of files with the given Category */ - public long getCategoryCount(Category cat) { + synchronized public long getCategoryCount(Category cat) { if (cat == Category.ZERO) { // Keeping track of the uncategorized files is a bit tricky while ingest // is going on, so always use the list of file IDs we already have along with the @@ -119,7 +128,7 @@ public class CategoryManager { * * @param cat the Category to increment */ - public void incrementCategoryCount(Category cat) { + synchronized public void incrementCategoryCount(Category cat) { if (cat != Category.ZERO) { categoryCounts.getUnchecked(cat).increment(); } @@ -131,7 +140,7 @@ public class CategoryManager { * * @param cat the Category to decrement */ - public void decrementCategoryCount(Category cat) { + synchronized public void decrementCategoryCount(Category cat) { if (cat != Category.ZERO) { categoryCounts.getUnchecked(cat).decrement(); } @@ -147,7 +156,7 @@ public class CategoryManager { * @return a LongAdder whose value is set to the number of file with the * given Category */ - private LongAdder getCategoryCountHelper(Category cat) { + synchronized private LongAdder getCategoryCountHelper(Category cat) { LongAdder longAdder = new LongAdder(); longAdder.decrement(); try { @@ -191,7 +200,7 @@ public class CategoryManager { * * @return the TagName used for this Category */ - public TagName getTagName(Category cat) { + synchronized public TagName getTagName(Category cat) { return catTagNameMap.getUnchecked(cat); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java index 6692bf873f..2710020c45 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java @@ -43,8 +43,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; */ public class SummaryTablePane extends AnchorPane { - private static SummaryTablePane instance; - @FXML private TableColumn, String> catColumn; @@ -53,6 +51,7 @@ public class SummaryTablePane extends AnchorPane { @FXML private TableView> tableView; + private final ImageGalleryController controller; @FXML void initialize() { @@ -74,19 +73,14 @@ public class SummaryTablePane extends AnchorPane { tableView.getColumns().setAll(Arrays.asList(catColumn, countColumn)); -// //register for category events - ImageGalleryController.getDefault().getCategoryManager().registerListener(this); + //register for category events + controller.getCategoryManager().registerListener(this); } - private SummaryTablePane() { + public SummaryTablePane(ImageGalleryController controller) { + this.controller = controller; FXMLConstructor.construct(this, "SummaryTablePane.fxml"); - } - public static synchronized SummaryTablePane getDefault() { - if (instance == null) { - instance = new SummaryTablePane(); - } - return instance; } /** @@ -101,7 +95,7 @@ public class SummaryTablePane extends AnchorPane { final ObservableList> data = FXCollections.observableArrayList(); if (Case.isCaseOpen()) { for (Category cat : Category.values()) { - data.add(new Pair<>(cat, ImageGalleryController.getDefault().getCategoryManager().getCategoryCount(cat))); + data.add(new Pair<>(cat, controller.getCategoryManager().getCategoryCount(cat))); } } Platform.runLater(() -> { From b430039c1b9d77aa13a885c9db3ab42d91818562 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 15:20:02 -0400 Subject: [PATCH 104/198] more tag/category autopsy integeration update CategoryCounts, FollowUp and Category border on general Tag Event use most severe category if multiple categories are present for a file enforce category ordering via enum declaration order --- .../imagegallery/datamodel/Category.java | 9 +++++--- .../imagegallery/datamodel/DrawableFile.java | 7 +++--- .../imagegallery/gui/DrawableView.java | 22 +++++++++++-------- .../imagegallery/gui/DrawableViewBase.java | 6 ++--- .../imagegallery/gui/MetaDataPane.java | 4 ++-- .../imagegallery/gui/SummaryTablePane.java | 5 +---- 6 files changed, 28 insertions(+), 25 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index ee6a46098e..aed95afec6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -28,14 +28,17 @@ import org.sleuthkit.datamodel.TagName; /** * Enum to represent the six categories in the DHs image categorization scheme. */ -public enum Category implements Comparable { +public enum Category { - ZERO(Color.LIGHTGREY, 0, "CAT-0: Uncategorized"), + /* This order of declaration is required so that Enum's compareTo method + * preserves the fact that lower category numbers are first/most sever, + * except 0 which is last */ ONE(Color.RED, 1, "CAT-1: Child Exploitation (Illegal)"), TWO(Color.ORANGE, 2, "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"), THREE(Color.YELLOW, 3, "CAT-3: CGI/Animation (Child Exploitive)"), FOUR(Color.BISQUE, 4, "CAT-4: Exemplar/Comparison (Internal Use Only)"), - FIVE(Color.GREEN, 5, "CAT-5: Non-pertinent"); + FIVE(Color.GREEN, 5, "CAT-5: Non-pertinent"), + ZERO(Color.LIGHTGREY, 0, "CAT-0: Uncategorized"); /** map from displayName to enum value */ private static final Map nameMap diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 4d3de0d553..3890ca577a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -268,22 +268,21 @@ public abstract class DrawableFile extends AbstractFile return category; } - public void updateCategory() { + /** set the category property to the most severe one found */ + private void updateCategory() { try { category.set(getSleuthkitCase().getContentTagsByContent(this).stream() .map(Tag::getName).filter(Category::isCategoryTagName) - .findFirst() .map(TagName::getDisplayName) .map(Category::fromDisplayName) + .sorted().findFirst() //sort by severity and take the first .orElse(Category.ZERO) ); - } catch (TskCoreException ex) { Logger.getLogger(DrawableFile.class.getName()).log(Level.WARNING, "problem looking up category for file " + this.getName(), ex); } catch (IllegalStateException ex) { // We get here many times if the case is closed during ingest, so don't print out a ton of warnings. } - } public abstract Image getThumbnail(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 93dbae801e..99d8671a63 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -108,15 +108,19 @@ public interface DrawableView { @ThreadConfined(type = ThreadConfined.ThreadType.ANY) default Category updateCategoryBorder() { - final Category category = getFile().getCategory(); - final Border border = hasHashHit() && (category == Category.ZERO) - ? HASH_BORDER - : getCategoryBorder(category); + if (getFile() != null) { + final Category category = getFile().getCategory(); + final Border border = hasHashHit() && (category == Category.ZERO) + ? HASH_BORDER + : getCategoryBorder(category); - Platform.runLater(() -> { - getCategoryBorderRegion().setBorder(border); - getCategoryBorderRegion().requestLayout(); - }); - return category; + Platform.runLater(() -> { + getCategoryBorderRegion().setBorder(border); + getCategoryBorderRegion().requestLayout(); + }); + return category; + } else { + return Category.ZERO; + } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 52ac70def0..38c48c2951 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -2,7 +2,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-14 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -302,7 +302,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Override synchronized public void handleTagsChanged(TagsChangeEvent evnt) { - if (fileID != null && evnt.getFileIDs().contains(fileID)) { + if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { updateFollowUpIcon(); } } @@ -386,7 +386,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { - if (evt.getFileIDs().contains(getFileID())) { + if (evt.getFileIDs().contains(getFileID()) || evt.getFileIDs().contains(-1L)) { updateCategoryBorder(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index 4ab6fff208..4f4cace550 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -225,7 +225,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @Subscribe @Override public void handleCategoryChanged(CategoryChangeEvent evt) { - if (getFile() != null && evt.getFileIDs().contains(getFileID())) { + if (getFile() != null && (evt.getFileIDs().contains(-1L) || evt.getFileIDs().contains(getFileID()))) { updateUI(); } } @@ -233,7 +233,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @Override @Subscribe public void handleTagsChanged(TagsChangeEvent evt) { - if (getFile() != null && evt.getFileIDs().contains(getFileID())) { + if (getFile() != null && (evt.getFileIDs().contains(-1L) || evt.getFileIDs().contains(getFileID()))) { updateUI(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java index 2710020c45..955cf0760f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java @@ -75,6 +75,7 @@ public class SummaryTablePane extends AnchorPane { //register for category events controller.getCategoryManager().registerListener(this); + handleCategoryChanged(null); } public SummaryTablePane(ImageGalleryController controller) { @@ -88,10 +89,6 @@ public class SummaryTablePane extends AnchorPane { */ @Subscribe public void handleCategoryChanged(CategoryChangeEvent evt) { - refresh(); - } - - public void refresh() { final ObservableList> data = FXCollections.observableArrayList(); if (Case.isCaseOpen()) { for (Category cat : Category.values()) { From 6d12aec7ae418e53c9f5e85596aff05cfe61d390 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 16:57:28 -0400 Subject: [PATCH 105/198] new Tag event system --- .../imagegallery/DrawableTagsManager.java | 148 +++++++++++------- .../imagegallery/ImageGalleryController.java | 30 +++- .../actions/CategorizeAction.java | 1 + .../actions/DeleteFollowUpTagAction.java | 70 ++++----- .../imagegallery/datamodel/Category.java | 3 + .../imagegallery/grouping/GroupManager.java | 6 +- .../imagegallery/gui/DrawableViewBase.java | 15 +- 7 files changed, 163 insertions(+), 110 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 7e0303fe4d..add7065742 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -45,6 +45,7 @@ public class DrawableTagsManager { private static final String FOLLOW_UP = "Follow Up"; + private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; /** Used to distribute {@link TagsChangeEvent}s */ @@ -64,26 +65,21 @@ public class DrawableTagsManager { * * @param autopsyTagsManager */ - public synchronized void setAutopsyTagsManager(TagsManager autopsyTagsManager) { - this.autopsyTagsManager = autopsyTagsManager; - clearFollowUpTagName(); + public void setAutopsyTagsManager(TagsManager autopsyTagsManager) { + synchronized (autopsyTagsManager) { + this.autopsyTagsManager = autopsyTagsManager; + clearFollowUpTagName(); + } } /** * Use when closing a case to make sure everything is re-initialized in the * next case. */ - public synchronized void clearFollowUpTagName() { - followUpTagName = null; - } - - /** - * fire a TagsChangeEvent with the given fileIDs - * - * @param fileIDs - */ - public final void fireChange(Collection fileIDs) { - tagsEventBus.post(new TagsChangeEvent(fileIDs)); + public void clearFollowUpTagName() { + synchronized (autopsyTagsManager) { + followUpTagName = null; + } } /** @@ -111,22 +107,26 @@ public class DrawableTagsManager { * * @throws TskCoreException */ - synchronized public TagName getFollowUpTagName() throws TskCoreException { - if (Objects.isNull(followUpTagName)) { - followUpTagName = getTagName(FOLLOW_UP); + public TagName getFollowUpTagName() throws TskCoreException { + synchronized (autopsyTagsManager) { + if (Objects.isNull(followUpTagName)) { + followUpTagName = getTagName(FOLLOW_UP); + } + return followUpTagName; } - return followUpTagName; } - synchronized public Collection getNonCategoryTagNames() { - try { - return autopsyTagsManager.getAllTagNames().stream() - .filter(Category::isCategoryTagName) - .collect(Collectors.toSet()); - } catch (TskCoreException | IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + public Collection getNonCategoryTagNames() { + synchronized (autopsyTagsManager) { + try { + return autopsyTagsManager.getAllTagNames().stream() + .filter(Category::isCategoryTagName) + .collect(Collectors.toSet()); + } catch (TskCoreException | IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + } + return Collections.emptySet(); } - return Collections.emptySet(); } /** @@ -139,29 +139,33 @@ public class DrawableTagsManager { * * @throws TskCoreException */ - public synchronized List getContentTagsByContent(Content content) throws TskCoreException { - return autopsyTagsManager.getContentTagsByContent(content); - } - - public synchronized TagName getTagName(String displayName) throws TskCoreException { - try { - for (TagName tn : autopsyTagsManager.getAllTagNames()) { - if (displayName.equals(tn.getDisplayName())) { - return tn; - } - } - try { - return autopsyTagsManager.addTagName(displayName); - } catch (TagsManager.TagNameAlreadyExistsException ex) { - throw new TskCoreException("tagame exists but wasn't found", ex); - } - } catch (IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); - throw new TskCoreException("Case was closed out from underneath", ex); + public List getContentTagsByContent(Content content) throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getContentTagsByContent(content); } } - public synchronized TagName getTagName(Category cat) { + public TagName getTagName(String displayName) throws TskCoreException { + synchronized (autopsyTagsManager) { + try { + for (TagName tn : autopsyTagsManager.getAllTagNames()) { + if (displayName.equals(tn.getDisplayName())) { + return tn; + } + } + try { + return autopsyTagsManager.addTagName(displayName); + } catch (TagsManager.TagNameAlreadyExistsException ex) { + throw new TskCoreException("tagame exists but wasn't found", ex); + } + } catch (IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); + throw new TskCoreException("Case was closed out from underneath", ex); + } + } + } + + public TagName getTagName(Category cat) { try { return getTagName(cat.getDisplayName()); } catch (TskCoreException ex) { @@ -169,12 +173,18 @@ public class DrawableTagsManager { } } - synchronized public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { - autopsyTagsManager.addContentTag(file, tagName, comment); + public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { + ContentTag addContentTag; + synchronized (autopsyTagsManager) { + addContentTag = autopsyTagsManager.addContentTag(file, tagName, comment); + } + fireTagAdded(addContentTag); } - synchronized public List getContentTagsByTagName(TagName t) throws TskCoreException { - return autopsyTagsManager.getContentTagsByTagName(t); + public List getContentTagsByTagName(TagName t) throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getContentTagsByTagName(t); + } } /** @@ -189,15 +199,43 @@ public class DrawableTagsManager { * refreshes based on them. */ static public void refreshTagsInAutopsy() { - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS } - public synchronized List getAllTagNames() throws TskCoreException { - return autopsyTagsManager.getAllTagNames(); + public List getAllTagNames() throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getAllTagNames(); + } } - public synchronized List getTagNamesInUse() throws TskCoreException { - return autopsyTagsManager.getTagNamesInUse(); + public List getTagNamesInUse() throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getTagNamesInUse(); + } } + + public void fireTagAdded(ContentTag newTag) { + tagsEventBus.post(new TagsChangeEvent(Collections.singleton(newTag.getContent().getId()))); + } + + public void fireTagDeleted(ContentTag oldTag) { + tagsEventBus.post(new TagsChangeEvent(Collections.singleton(oldTag.getContent().getId()))); + } +// +// /** +// * fire a TagsChangeEvent with the given fileIDs +// * +// * @param fileIDs +// */ +// public final void fireChange(Collection fileIDs) { +// tagsEventBus.post(new TagsChangeEvent(fileIDs)); +// } + + public void deleteContentTag(ContentTag ct) throws TskCoreException { + synchronized (autopsyTagsManager) { + autopsyTagsManager.deleteContentTag(ct); + } + fireTagDeleted(ct); + } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 6c54db8185..046c88bc7a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -58,7 +58,10 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.History; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; +import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; @@ -67,11 +70,11 @@ import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase; @@ -436,11 +439,6 @@ public final class ImageGalleryController { case CONTENT_CHANGED: //TODO: do we need to do anything here? -jm case DATA_ADDED: - ModuleDataEvent oldValue = (ModuleDataEvent) evt.getOldValue(); - if ("TagAction".equals(oldValue.getModuleName()) && oldValue.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { - getTagsManager().fireChange(Collections.singleton(-1L)); - getCategoryManager().invalidateCaches(); - } /* we could listen to DATA events and progressivly * update files, and get data from DataSource ingest * modules, but given that most modules don't post new @@ -491,6 +489,26 @@ public final class ImageGalleryController { setStale(true); } break; + case CONTENT_TAG_ADDED: + ContentTag newTag = (ContentTag) evt.getNewValue(); + if (Category.isCategoryTagName(newTag.getName())) { + new CategorizeAction(ImageGalleryController.this).addTag(newTag.getName(), ""); + } else { + getTagsManager().fireTagAdded(newTag); + } + break; + case CONTENT_TAG_DELETED: + ContentTag oldTag = (ContentTag) evt.getOldValue(); + final long fileID = oldTag.getContent().getId(); + if (getDatabase().isInDB(fileID)) { + if (Category.isCategoryTagName(oldTag.getName())) { + getCategoryManager().decrementCategoryCount(Category.fromTagName(oldTag.getName())); + getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); + } else { + getTagsManager().fireTagDeleted(oldTag); + } + } + break; } }); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 27f599cafe..8918934a6e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -161,4 +161,5 @@ public class CategorizeAction extends AddTagAction { DrawableTagsManager.refreshTagsInAutopsy(); } } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index bba6d5e4dc..98fdc316ad 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; +import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; @@ -43,49 +44,40 @@ public class DeleteFollowUpTagAction extends Action { private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTagAction.class.getName()); private final long fileID; - private final DrawableFile file; - private final ImageGalleryController controller; - public DeleteFollowUpTagAction(ImageGalleryController controller, DrawableFile file) { + public DeleteFollowUpTagAction(final ImageGalleryController controller, final DrawableFile file) { super("Delete Follow Up Tag"); - this.controller = controller; - this.file = file; this.fileID = file.getId(); setEventHandler((ActionEvent t) -> { - deleteTag(); + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + final GroupManager groupManager = controller.getGroupManager(); + final DrawableTagsManager tagsManager = controller.getTagsManager(); + + try { + final TagName followUpTagName = tagsManager.getFollowUpTagName(); + // remove file from old category group + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); + + List contentTagsByContent = tagsManager.getContentTagsByContent(file); + for (ContentTag ct : contentTagsByContent) { + if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { + tagsManager.deleteContentTag(ct); + } + } + + DrawableTagsManager.refreshTagsInAutopsy(); + //make sure rest of ui hears category change. + groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); + } + return null; + } + }.execute(); }); } - - /** - * - * - * - */ - private void deleteTag() { - - final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); - final GroupManager groupManager = controller.getGroupManager(); - final DrawableTagsManager tagsManager = controller.getTagsManager(); - - try { - final TagName followUpTagName = tagsManager.getFollowUpTagName(); - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); - - List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { - sleuthKitCase.deleteContentTag(ct); - } - } - - DrawableTagsManager.refreshTagsInAutopsy(); - - //make sure rest of ui hears category change. - groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); - } - } - } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index aed95afec6..00750c4ba9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -49,6 +49,9 @@ public enum Category { public static Category fromDisplayName(String displayName) { return nameMap.get(displayName); } + public static Category fromTagName(TagName tagName) { + return nameMap.get(tagName.getDisplayName()); + } public static boolean isCategoryTagName(TagName tName) { return isCategoryName(tName.getDisplayName()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 2027dae724..51a99bd5f7 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -595,9 +595,9 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { //we fire this event for all files so that the category counts get updated during initial db population controller.getCategoryManager().fireChange(fileIDs); - if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { - controller.getTagsManager().fireChange(fileIDs); - } +// if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { +// controller.getTagsManager().fireChange(fileIDs); +// } } private void popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 38c48c2951..93026d688d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -300,13 +300,6 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie return fileID; } - @Override - synchronized public void handleTagsChanged(TagsChangeEvent evnt) { - if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { - updateFollowUpIcon(); - } - } - synchronized protected void updateFollowUpIcon() { if (file != null) { try { @@ -383,6 +376,14 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie return imageBorder; } + @Subscribe + @Override + synchronized public void handleTagsChanged(TagsChangeEvent evnt) { + if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { + updateFollowUpIcon(); + } + } + @Subscribe @Override synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { From dabcec9e27d4dc6ff40e57f19bea12a5908f9605 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 17:00:05 -0400 Subject: [PATCH 106/198] more granular synchronization in DrawableTagsManager --- .../sleuthkit/autopsy/casemodule/Case.java | 21 ++++++++++-- .../casemodule/services/TagsManager.java | 20 +++++++---- .../imagegallery/DrawableTagsManager.java | 34 +++++++------------ 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index db1250ebf7..c304e97f9e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -49,8 +49,13 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.Version; -import org.sleuthkit.datamodel.*; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.Report; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitJNI.CaseDbHandle.AddImageProcess; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskException; /** * Stores all information for a given case. Only a single case can currently be @@ -126,7 +131,19 @@ public class Case implements SleuthkitCase.ErrorObserver { * case. The old value supplied by the event object is null and the new * value is a reference to a Report object representing the new report. */ - REPORT_ADDED; + REPORT_ADDED, + /** new value is tag added */ + BLACKBOARD_ARTIFACT_TAG_ADDED, + /** + * old value is tag deleted + */ + BLACKBOARD_ARTIFACT_TAG_DELETED, + /** new value is tag added */ + CONTENT_TAG_ADDED, + /** + * old value is tag deleted + */ + CONTENT_TAG_DELETED; }; private String name; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 6be8439029..4e5aaecdc8 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -24,9 +24,9 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; - import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; @@ -216,8 +216,10 @@ public class TagsManager implements Closeable { NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endLTbegin.msg")); } } - - return tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); + + final ContentTag newContentTag = tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); + Case.getPropertyChangeSupport().firePropertyChange(Case.Events.CONTENT_TAG_ADDED.toString(), null, newContentTag); + return newContentTag; } /** @@ -232,6 +234,7 @@ public class TagsManager implements Closeable { } tskCase.deleteContentTag(tag); + Case.getPropertyChangeSupport().firePropertyChange(Case.Events.CONTENT_TAG_DELETED.toString(), tag, null); } /** @@ -317,8 +320,10 @@ public class TagsManager implements Closeable { if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.addBlackboardArtifactTag(artifact, tagName, comment); + + final BlackboardArtifactTag newBlackboardArtifactTag = tskCase.addBlackboardArtifactTag(artifact, tagName, comment); + Case.getPropertyChangeSupport().firePropertyChange(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString(), null, newBlackboardArtifactTag); + return newBlackboardArtifactTag; } /** @@ -331,7 +336,8 @@ public class TagsManager implements Closeable { if (!tagNamesInitialized) { getExistingTagNames(); } - + + Case.getPropertyChangeSupport().firePropertyChange(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString(), tag, null); tskCase.deleteBlackboardArtifactTag(tag); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index add7065742..13455d2fb1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -45,7 +45,7 @@ public class DrawableTagsManager { private static final String FOLLOW_UP = "Follow Up"; - private Object autopsyTagsManagerLock = new Object(); + final private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; /** Used to distribute {@link TagsChangeEvent}s */ @@ -66,7 +66,7 @@ public class DrawableTagsManager { * @param autopsyTagsManager */ public void setAutopsyTagsManager(TagsManager autopsyTagsManager) { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { this.autopsyTagsManager = autopsyTagsManager; clearFollowUpTagName(); } @@ -77,7 +77,7 @@ public class DrawableTagsManager { * next case. */ public void clearFollowUpTagName() { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { followUpTagName = null; } } @@ -108,7 +108,7 @@ public class DrawableTagsManager { * @throws TskCoreException */ public TagName getFollowUpTagName() throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { if (Objects.isNull(followUpTagName)) { followUpTagName = getTagName(FOLLOW_UP); } @@ -117,7 +117,7 @@ public class DrawableTagsManager { } public Collection getNonCategoryTagNames() { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { try { return autopsyTagsManager.getAllTagNames().stream() .filter(Category::isCategoryTagName) @@ -140,13 +140,13 @@ public class DrawableTagsManager { * @throws TskCoreException */ public List getContentTagsByContent(Content content) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getContentTagsByContent(content); } } public TagName getTagName(String displayName) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { try { for (TagName tn : autopsyTagsManager.getAllTagNames()) { if (displayName.equals(tn.getDisplayName())) { @@ -175,14 +175,14 @@ public class DrawableTagsManager { public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { ContentTag addContentTag; - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { addContentTag = autopsyTagsManager.addContentTag(file, tagName, comment); } fireTagAdded(addContentTag); } public List getContentTagsByTagName(TagName t) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getContentTagsByTagName(t); } } @@ -203,13 +203,13 @@ public class DrawableTagsManager { } public List getAllTagNames() throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getAllTagNames(); } } public List getTagNamesInUse() throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getTagNamesInUse(); } } @@ -221,21 +221,11 @@ public class DrawableTagsManager { public void fireTagDeleted(ContentTag oldTag) { tagsEventBus.post(new TagsChangeEvent(Collections.singleton(oldTag.getContent().getId()))); } -// -// /** -// * fire a TagsChangeEvent with the given fileIDs -// * -// * @param fileIDs -// */ -// public final void fireChange(Collection fileIDs) { -// tagsEventBus.post(new TagsChangeEvent(fileIDs)); -// } public void deleteContentTag(ContentTag ct) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { autopsyTagsManager.deleteContentTag(ct); } fireTagDeleted(ct); } - } From 335b82bbc2868fb9100aadc6e9b07fba956b49b4 Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 10:22:18 -0400 Subject: [PATCH 107/198] Tag Events - created new Case.Event enum values for BlackBoard/Content tags added/deleted - created new PropertyChangeEvent subclasses for BlackBoard/Content tags added/deleted - replaced ModuleDataEvent hack with new Tag Events - removed [in] from javadocs, other minor cleanup --- .../autopsy/actions/AddTagAction.java | 38 +- .../sleuthkit/autopsy/actions/TagAction.java | 35 +- .../sleuthkit/autopsy/casemodule/Case.java | 108 ++++- .../casemodule/services/TagsManager.java | 386 ++++++++++-------- .../org/sleuthkit/autopsy/datamodel/Tags.java | 15 +- .../BlackBoardArtifactTagAddedEvent.java | 33 ++ .../BlackBoardArtifactTagDeletedEvent.java | 32 ++ .../autopsy/events/ContentTagAddedEvent.java | 35 ++ .../events/ContentTagDeletedEvent.java | 34 ++ .../autopsy/events/TagAddedEvent.java | 46 +++ .../autopsy/events/TagDeletedEvent.java | 45 ++ 11 files changed, 564 insertions(+), 243 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagAddedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagDeletedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/ContentTagAddedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/ContentTagDeletedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index b051fa2238..9c552247fd 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,20 +19,18 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.Collections; import java.util.List; import java.util.logging.Level; import javax.swing.JMenu; import javax.swing.JMenuItem; - import org.openide.util.NbBundle; import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.coreutils.Logger; /** * An abstract base class for Actions that allow users to tag SleuthKit data @@ -98,12 +96,8 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { if (null != tagNames && !tagNames.isEmpty()) { for (final TagName tagName : tagNames) { JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName()); - tagNameItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - addTag(tagName, NO_COMMENT); - refreshDirectoryTree(); - } + tagNameItem.addActionListener((ActionEvent e) -> { + addTag(tagName, NO_COMMENT); }); quickTagMenu.add(tagNameItem); } @@ -120,14 +114,10 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { // Selecting this item initiates a dialog that can be used to create // or select a tag name and adds a tag with the resulting name. JMenuItem newTagMenuItem = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.newTag")); - newTagMenuItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - TagName tagName = GetTagNameDialog.doDialog(); - if (tagName != null) { - addTag(tagName, NO_COMMENT); - refreshDirectoryTree(); - } + newTagMenuItem.addActionListener((ActionEvent e) -> { + TagName tagName = GetTagNameDialog.doDialog(); + if (null != tagName) { + addTag(tagName, NO_COMMENT); } }); quickTagMenu.add(newTagMenuItem); @@ -137,14 +127,10 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { // optional comment and adds a tag with the resulting name. JMenuItem tagAndCommentItem = new JMenuItem( NbBundle.getMessage(this.getClass(), "AddTagAction.tagAndComment")); - tagAndCommentItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); - if (null != tagNameAndComment) { - addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); - refreshDirectoryTree(); - } + tagAndCommentItem.addActionListener((ActionEvent e) -> { + GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); + if (null != tagNameAndComment) { + addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } }); add(tagAndCommentItem); diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagAction.java b/Core/src/org/sleuthkit/autopsy/actions/TagAction.java index a540ce878a..ed53af2c6f 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/TagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/TagAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,41 +20,26 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; /** * Abstract base class for Actions involving tags. */ - abstract class TagAction extends AbstractAction { +abstract class TagAction extends AbstractAction { + public TagAction(String menuText) { super(menuText); } - + @Override public void actionPerformed(ActionEvent event) { doAction(event); - refreshDirectoryTree(); - } - + } + /** - * Derived classes must implement this Template Method for actionPerformed(). - * @param event ActionEvent object passed to actionPerformed() + * Derived classes must implement this Template Method for + * actionPerformed(). + * + * @param event ActionEvent object passed to actionPerformed() */ abstract protected void doAction(ActionEvent event); - - /** - * Derived classes should call this method any time a tag is created, updated - * or deleted outside of an actionPerformed() call. - */ - @SuppressWarnings("deprecation") - protected void refreshDirectoryTree() { - - /* Note: this is a hack. In an ideal world, TagsManager would fire events so - * that the directory tree would refresh. But, we haven't had a chance to add - * that so, we fire these events and the tree refreshes based on them. - */ - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index c304e97f9e..19ec87e3cc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.Frame; +import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.BufferedInputStream; @@ -49,7 +50,13 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.Version; +import org.sleuthkit.autopsy.events.BlackBoardArtifactTagAddedEvent; +import org.sleuthkit.autopsy.events.BlackBoardArtifactTagDeletedEvent; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.Report; import org.sleuthkit.datamodel.SleuthkitCase; @@ -132,17 +139,17 @@ public class Case implements SleuthkitCase.ErrorObserver { * value is a reference to a Report object representing the new report. */ REPORT_ADDED, - /** new value is tag added */ + /** Property name for the event when a new BlackBoardArtifactTag is + * added. The new value is tag added, the old value is empty */ BLACKBOARD_ARTIFACT_TAG_ADDED, - /** - * old value is tag deleted - */ + /** Property name for the event when a new BlackBoardArtifactTag is + * deleted. The new value is empty, the old value is the deleted tag */ BLACKBOARD_ARTIFACT_TAG_DELETED, - /** new value is tag added */ + /** Property name for the event when a new ContentTag is + * added. The new value is tag added, the old value is empty */ CONTENT_TAG_ADDED, - /** - * old value is tag deleted - */ + /** Property name for the event when a new ContentTag is + * deleted. The new value is empty, the old value is the deleted tag */ CONTENT_TAG_DELETED; }; @@ -284,12 +291,13 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Creates a new case (create the XML config file and database) * - * @param caseDir The directory to store case data in. Will be created if it - * doesn't already exist. If it exists, it should have all of the needed sub - * dirs that createCaseDirectory() will create. - * @param caseName the name of case + * @param caseDir The directory to store case data in. Will be created if + * it + * doesn't already exist. If it exists, it should have all of the needed sub + * dirs that createCaseDirectory() will create. + * @param caseName the name of case * @param caseNumber the case number - * @param examiner the examiner for this case + * @param examiner the examiner for this case */ public static void create(String caseDir, String caseName, String caseNumber, String examiner) throws CaseActionException { logger.log(Level.INFO, "Creating new case.\ncaseDir: {0}\ncaseName: {1}", new Object[]{caseDir, caseName}); //NON-NLS @@ -435,7 +443,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Sends out event and reopens windows if needed. * * @param imgPaths the paths of the image that being added - * @param imgId the ID of the image that being added + * @param imgId the ID of the image that being added * @param timeZone the timeZone of the image where it's added */ @Deprecated @@ -493,6 +501,59 @@ public class Case implements SleuthkitCase.ErrorObserver { CoreComponentControl.openCoreWindows(); } + /** + * Notifies the UI that a new ContentTag has been added. + * + * @param newTag new ContentTag added + */ + public void notifyContentTagAdded(ContentTag newTag) { + notify(new ContentTagAddedEvent(newTag)); + } + + /** + * Notifies the UI that a ContentTag has been deleted. + * + * @param deletedTag ContentTag deleted + */ + public void notifyContentTagDeleted(ContentTag deletedTag) { + notify(new ContentTagDeletedEvent(deletedTag)); + } + + /** + * Notifies the UI that a new BlackboardArtifactTag has been added. + * + * @param newTag new BlackboardArtifactTag added + */ + public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) { + notify(new BlackBoardArtifactTagAddedEvent(newTag)); + } + + /** + * Notifies the UI that a BlackboardArtifactTag has been. + * + * @param deletedTag BlackboardArtifactTag deleted + */ + public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { + notify(new BlackBoardArtifactTagDeletedEvent(deletedTag)); + } + + /** + * Notifies the UI about a Case level event. + * + * @param propertyChangeEvent the event to distribute + */ + private void notify(final PropertyChangeEvent propertyChangeEvent) { + try { + pcs.firePropertyChange(propertyChangeEvent); + } catch (Exception e) { + logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS + MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), + NbBundle.getMessage(this.getClass(), + "Case.changeCase.errListenToCaseUpdates.msg"), + MessageNotifyUtil.MessageType.ERROR); + } + } + /** * @return The Services object for this case. */ @@ -557,9 +618,9 @@ public class Case implements SleuthkitCase.ErrorObserver { * Updates the case name. * * @param oldCaseName the old case name that wants to be updated - * @param oldPath the old path that wants to be updated + * @param oldPath the old path that wants to be updated * @param newCaseName the new case name - * @param newPath the new path + * @param newPath the new path */ void updateCaseName(String oldCaseName, String oldPath, String newCaseName, String newPath) throws CaseActionException { try { @@ -818,6 +879,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Get the data model Content objects in the root of this case's hierarchy. * * @return a list of the root objects + * * @throws org.sleuthkit.datamodel.TskCoreException */ public List getDataSources() throws TskCoreException { @@ -951,7 +1013,7 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * to create the case directory * - * @param caseDir Path to the case directory (typically base + case name) + * @param caseDir Path to the case directory (typically base + case name) * @param caseName the case name (used only for error messages) * * @throws CaseActionException throw if could not create the case dir @@ -1171,12 +1233,14 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Adds a report to the case. * - * @param [in] localPath The path of the report file, must be in the case - * directory or one of its subdirectories. - * @param [in] sourceModuleName The name of the module that created the - * report. - * @param [in] reportName The report name, may be empty. + * @param localPath The path of the report file, must be in the case + * directory or one of its subdirectories. + * @param sourceModuleName The name of the module that created the + * report. + * @param reportName The report name, may be empty. + * * @return A Report data transfer object (DTO) for the new row. + * * @throws TskCoreException */ public void addReport(String localPath, String srcModuleName, String reportName) throws TskCoreException { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 4e5aaecdc8..5a52cefde9 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,28 +37,32 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** - * A per case instance of this class functions as an Autopsy service that - * manages the creation, updating, and deletion of tags applied to content and - * blackboard artifacts by users. + * A per case instance of this class functions as an Autopsy service that + * manages the creation, updating, and deletion of tags applied to content and + * blackboard artifacts by users. */ public class TagsManager implements Closeable { + private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS - private final SleuthkitCase tskCase; + private final SleuthkitCase tskCase; private final HashMap uniqueTagNames = new HashMap<>(); private boolean tagNamesInitialized = false; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized. - - // Use this exception and the member hash map to manage uniqueness of hash - // names. This is deemed more proactive and informative than leaving this to - // the UNIQUE constraint on the display_name field of the tag_names table in - // the case database. - public class TagNameAlreadyExistsException extends Exception { - } - + /** - * Package-scope constructor for use of the Services class. An instance of + * Use this exception and the member hash map to manage uniqueness of hash + * names. This is deemed more proactive and informative than leaving this to + * the UNIQUE constraint on the display_name field of the tag_names table in + * the case database. + */ + public static class TagNameAlreadyExistsException extends Exception { + } + + /** + * Package-scope constructor for use of the Services class. An instance of * TagsManager should be created for each case that is opened. - * @param [in] tskCase The SleuthkitCase object for the current case. + * + * @param tskCase The SleuthkitCase object for the current case. */ TagsManager(SleuthkitCase tskCase) { this.tskCase = tskCase; @@ -67,38 +71,44 @@ public class TagsManager implements Closeable { } /** - * Gets a list of all tag names currently available for tagging content or + * Gets a list of all tag names currently available for tagging content or * blackboard artifacts. - * @return A list, possibly empty, of TagName data transfer objects (DTOs). - * @throws TskCoreException + * + * @return A list, possibly empty, of TagName data transfer objects (DTOs). + * + * @throws TskCoreException */ - public synchronized List getAllTagNames() throws TskCoreException { + public synchronized List getAllTagNames() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + return tskCase.getAllTagNames(); } /** - * Gets a list of all tag names currently used for tagging content or + * Gets a list of all tag names currently used for tagging content or * blackboard artifacts. - * @return A list, possibly empty, of TagName data transfer objects (DTOs). - * @throws TskCoreException + * + * @return A list, possibly empty, of TagName data transfer objects (DTOs). + * + * @throws TskCoreException */ - public synchronized List getTagNamesInUse() throws TskCoreException { + public synchronized List getTagNamesInUse() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + return tskCase.getTagNamesInUse(); } - + /** * Checks whether a tag name with a given display name exists. - * @param [in] tagDisplayName The display name for which to check. + * + * @param tagDisplayName The display name for which to check. + * * @return True if the tag name exists, false otherwise. */ public synchronized boolean tagNameExists(String tagDisplayName) { @@ -106,15 +116,19 @@ public class TagsManager implements Closeable { if (!tagNamesInitialized) { getExistingTagNames(); } - + return uniqueTagNames.containsKey(tagDisplayName); } - + /** * Adds a new tag name to the current case and to the tags settings. - * @param [in] displayName The display name for the new tag name. - * @return A TagName data transfer object (DTO) representing the new tag name. - * @throws TagNameAlreadyExistsException, TskCoreException + * + * @param displayName The display name for the new tag name. + * + * @return A TagName data transfer object (DTO) representing the new tag + * name. + * + * @throws TagNameAlreadyExistsException, TskCoreException */ public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, "", TagName.HTML_COLOR.NONE); @@ -122,10 +136,14 @@ public class TagsManager implements Closeable { /** * Adds a new tag name to the current case and to the tags settings. - * @param [in] displayName The display name for the new tag name. - * @param [in] description The description for the new tag name. - * @return A TagName data transfer object (DTO) representing the new tag name. - * @throws TagNameAlreadyExistsException, TskCoreException + * + * @param displayName The display name for the new tag name. + * @param description The description for the new tag name. + * + * @return A TagName data transfer object (DTO) representing the new tag + * name. + * + * @throws TagNameAlreadyExistsException, TskCoreException */ public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, description, TagName.HTML_COLOR.NONE); @@ -133,82 +151,95 @@ public class TagsManager implements Closeable { /** * Adds a new tag name to the current case and to the tags settings. - * @param [in] displayName The display name for the new tag name. - * @param [in] description The description for the new tag name. - * @param [in] color The HTML color to associate with the new tag name. - * @return A TagName data transfer object (DTO) representing the new tag name. - * @throws TagNameAlreadyExistsException, TskCoreException + * + * @param displayName The display name for the new tag name. + * @param description The description for the new tag name. + * @param color The HTML color to associate with the new tag name. + * + * @return A TagName data transfer object (DTO) representing the new tag + * name. + * + * @throws TagNameAlreadyExistsException, TskCoreException */ public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + if (uniqueTagNames.containsKey(displayName)) { throw new TagNameAlreadyExistsException(); } // Add the tag name to the case. - TagName newTagName = tskCase.addTagName(displayName, description, color); + TagName newTagName = tskCase.addTagName(displayName, description, color); // Add the tag name to the tags settings. uniqueTagNames.put(newTagName.getDisplayName(), newTagName); - saveTagNamesToTagsSettings(); + saveTagNamesToTagsSettings(); return newTagName; } - + /** * Tags a content object. - * @param [in] content The content to tag. - * @param [in] tagName The name to use for the tag. - * @return A ContentTag data transfer object (DTO) representing the new tag. - * @throws TskCoreException + * + * @param content The content to tag. + * @param tagName The name to use for the tag. + * + * @return A ContentTag data transfer object (DTO) representing the new tag. + * + * @throws TskCoreException */ public ContentTag addContentTag(Content content, TagName tagName) throws TskCoreException { return addContentTag(content, tagName, "", -1, -1); - } - + } + /** * Tags a content object. - * @param [in] content The content to tag. - * @param [in] tagName The name to use for the tag. - * @param [in] comment A comment to store with the tag. - * @return A ContentTag data transfer object (DTO) representing the new tag. - * @throws TskCoreException + * + * @param content The content to tag. + * @param tagName The name to use for the tag. + * @param comment A comment to store with the tag. + * + * @return A ContentTag data transfer object (DTO) representing the new tag. + * + * @throws TskCoreException */ public ContentTag addContentTag(Content content, TagName tagName, String comment) throws TskCoreException { return addContentTag(content, tagName, comment, -1, -1); - } - + } + /** * Tags a content object or a section of a content object. - * @param [in] content The content to tag. - * @param [in] tagName The name to use for the tag. - * @param [in] comment A comment to store with the tag. - * @param [in] beginByteOffset Designates the beginning of a tagged section. - * @param [in] endByteOffset Designates the end of a tagged section. - * @return A ContentTag data transfer object (DTO) representing the new tag. - * @throws IllegalArgumentException, TskCoreException + * + * @param content The content to tag. + * @param tagName The name to use for the tag. + * @param comment A comment to store with the tag. + * @param beginByteOffset Designates the beginning of a tagged section. + * @param endByteOffset Designates the end of a tagged section. + * + * @return A ContentTag data transfer object (DTO) representing the new tag. + * + * @throws IllegalArgumentException, TskCoreException */ public synchronized ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + if (beginByteOffset >= 0 && endByteOffset >= 1) { if (beginByteOffset > content.getSize() - 1) { throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), - "TagsManager.addContentTag.exception.beginByteOffsetOOR.msg", - beginByteOffset, content.getSize() - 1)); + "TagsManager.addContentTag.exception.beginByteOffsetOOR.msg", + beginByteOffset, content.getSize() - 1)); } if (endByteOffset > content.getSize() - 1) { throw new IllegalArgumentException( NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endByteOffsetOOR.msg", - endByteOffset, content.getSize() - 1)); + endByteOffset, content.getSize() - 1)); } if (endByteOffset < beginByteOffset) { @@ -216,31 +247,35 @@ public class TagsManager implements Closeable { NbBundle.getMessage(this.getClass(), "TagsManager.addContentTag.exception.endLTbegin.msg")); } } - final ContentTag newContentTag = tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); - Case.getPropertyChangeSupport().firePropertyChange(Case.Events.CONTENT_TAG_ADDED.toString(), null, newContentTag); + Case.getCurrentCase().notifyContentTagAdded(newContentTag); + return newContentTag; return newContentTag; } - + /** * Deletes a content tag. - * @param [in] tag The tag to delete. - * @throws TskCoreException + * + * @param tag The tag to delete. + * + * @throws TskCoreException */ public synchronized void deleteContentTag(ContentTag tag) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - + tskCase.deleteContentTag(tag); - Case.getPropertyChangeSupport().firePropertyChange(Case.Events.CONTENT_TAG_DELETED.toString(), tag, null); + Case.getCurrentCase().notifyContentTagDeleted(tag); } /** * Gets all content tags for the current case. + * * @return A list, possibly empty, of content tags. - * @throws TskCoreException + * + * @throws TskCoreException */ public List getAllContentTags() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. @@ -248,72 +283,91 @@ public class TagsManager implements Closeable { getExistingTagNames(); } - return tskCase.getAllContentTags(); + return tskCase.getAllContentTags(); } - + /** * Gets content tags count by tag name. - * @param [in] tagName The tag name of interest. + * + * @param tagName The tag name of interest. + * * @return A count of the content tags with the specified tag name. - * @throws TskCoreException + * + * @throws TskCoreException */ public synchronized long getContentTagsCountByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getContentTagsCountByTagName(tagName); + + return tskCase.getContentTagsCountByTagName(tagName); } - + /** * Gets content tags by tag name. - * @param [in] tagName The tag name of interest. - * @return A list, possibly empty, of the content tags with the specified tag name. - * @throws TskCoreException + * + * @param tagName The tag name of interest. + * + * @return A list, possibly empty, of the content tags with the specified + * tag name. + * + * @throws TskCoreException */ public synchronized List getContentTagsByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getContentTagsByTagName(tagName); + + return tskCase.getContentTagsByTagName(tagName); } - + /** * Gets content tags count by content. - * @param [in] content The content of interest. - * @return A list, possibly empty, of the tags that have been applied to the artifact. - * @throws TskCoreException + * + * @param content The content of interest. + * + * @return A list, possibly empty, of the tags that have been applied to the + * artifact. + * + * @throws TskCoreException */ public synchronized List getContentTagsByContent(Content content) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getContentTagsByContent(content); + + return tskCase.getContentTagsByContent(content); } - + /** * Tags a blackboard artifact object. - * @param [in] artifact The blackboard artifact to tag. - * @param [in] tagName The name to use for the tag. - * @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag. - * @throws TskCoreException + * + * @param artifact The blackboard artifact to tag. + * @param tagName The name to use for the tag. + * + * @return A BlackboardArtifactTag data transfer object (DTO) representing + * the new tag. + * + * @throws TskCoreException */ public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException { - return addBlackboardArtifactTag(artifact, tagName, ""); + return addBlackboardArtifactTag(artifact, tagName, ""); } - + /** * Tags a blackboard artifact object. - * @param [in] artifact The blackboard artifact to tag. - * @param [in] tagName The name to use for the tag. - * @param [in] comment A comment to store with the tag. - * @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag. - * @throws TskCoreException + * + * @param artifact The blackboard artifact to tag. + * @param tagName The name to use for the tag. + * @param comment A comment to store with the tag. + * + * @return A BlackboardArtifactTag data transfer object (DTO) representing + * the new tag. + * + * @throws TskCoreException */ public synchronized BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. @@ -321,15 +375,17 @@ public class TagsManager implements Closeable { getExistingTagNames(); } - final BlackboardArtifactTag newBlackboardArtifactTag = tskCase.addBlackboardArtifactTag(artifact, tagName, comment); - Case.getPropertyChangeSupport().firePropertyChange(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString(), null, newBlackboardArtifactTag); - return newBlackboardArtifactTag; + BlackboardArtifactTag addBlackboardArtifactTag = tskCase.addBlackboardArtifactTag(artifact, tagName, comment); + Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(addBlackboardArtifactTag); + return addBlackboardArtifactTag; } /** * Deletes a blackboard artifact tag. - * @param [in] tag The tag to delete. - * @throws TskCoreException + * + * @param tag The tag to delete. + * + * @throws TskCoreException */ public synchronized void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. @@ -339,12 +395,15 @@ public class TagsManager implements Closeable { Case.getPropertyChangeSupport().firePropertyChange(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString(), tag, null); tskCase.deleteBlackboardArtifactTag(tag); + Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); } - + /** * Gets all blackboard artifact tags for the current case. + * * @return A list, possibly empty, of blackboard artifact tags. - * @throws TskCoreException + * + * @throws TskCoreException */ public List getAllBlackboardArtifactTags() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. @@ -352,100 +411,110 @@ public class TagsManager implements Closeable { getExistingTagNames(); } - return tskCase.getAllBlackboardArtifactTags(); + return tskCase.getAllBlackboardArtifactTags(); } - + /** * Gets blackboard artifact tags count by tag name. - * @param [in] tagName The tag name of interest. - * @return A count of the blackboard artifact tags with the specified tag name. - * @throws TskCoreException + * + * @param tagName The tag name of interest. + * + * @return A count of the blackboard artifact tags with the specified tag + * name. + * + * @throws TskCoreException */ public synchronized long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getBlackboardArtifactTagsCountByTagName(tagName); + + return tskCase.getBlackboardArtifactTagsCountByTagName(tagName); } - + /** * Gets blackboard artifact tags by tag name. - * @param [in] tagName The tag name of interest. - * @return A list, possibly empty, of the blackboard artifact tags with the specified tag name. - * @throws TskCoreException + * + * @param tagName The tag name of interest. + * + * @return A list, possibly empty, of the blackboard artifact tags with the + * specified tag name. + * + * @throws TskCoreException */ - public synchronized List getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException { + public synchronized List getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getBlackboardArtifactTagsByTagName(tagName); + + return tskCase.getBlackboardArtifactTagsByTagName(tagName); } /** * Gets blackboard artifact tags for a particular blackboard artifact. - * @param [in] artifact The blackboard artifact of interest. - * @return A list, possibly empty, of the tags that have been applied to the artifact. - * @throws TskCoreException + * + * @param artifact The blackboard artifact of interest. + * + * @return A list, possibly empty, of the tags that have been applied to the + * artifact. + * + * @throws TskCoreException */ - public synchronized List getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException { + public synchronized List getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - - return tskCase.getBlackboardArtifactTagsByArtifact(artifact); + + return tskCase.getBlackboardArtifactTagsByArtifact(artifact); } - + @Override - public void close() throws IOException { - saveTagNamesToTagsSettings(); - } - + public void close() throws IOException { + saveTagNamesToTagsSettings(); + } + private void getExistingTagNames() { getTagNamesFromCurrentCase(); getTagNamesFromTagsSettings(); getPredefinedTagNames(); - saveTagNamesToTagsSettings(); + saveTagNamesToTagsSettings(); tagNamesInitialized = true; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized. } - + private void getTagNamesFromCurrentCase() { try { List currentTagNames = tskCase.getAllTagNames(); for (TagName tagName : currentTagNames) { uniqueTagNames.put(tagName.getDisplayName(), tagName); } - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); //NON-NLS - } + } } - + private void getTagNamesFromTagsSettings() { String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); - if (null != setting && !setting.isEmpty()) { + if (null != setting && !setting.isEmpty()) { // Read the tag name setting and break it into tag name tuples. - List tagNameTuples = Arrays.asList(setting.split(";")); - + List tagNameTuples = Arrays.asList(setting.split(";")); + // Parse each tuple and add the tag names to the current case, one // at a time to gracefully discard any duplicates or corrupt tuples. - for (String tagNameTuple : tagNameTuples) { + for (String tagNameTuple : tagNameTuples) { String[] tagNameAttributes = tagNameTuple.split(","); - if (!uniqueTagNames.containsKey(tagNameAttributes[0])) { + if (!uniqueTagNames.containsKey(tagNameAttributes[0])) { try { TagName tagName = tskCase.addTagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2])); uniqueTagNames.put(tagName.getDisplayName(), tagName); - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + tagNameAttributes[0], ex); //NON-NLS } } } - } + } } private void getPredefinedTagNames() { @@ -454,13 +523,12 @@ public class TagsManager implements Closeable { TagName tagName = tskCase.addTagName( NbBundle.getMessage(this.getClass(), "TagsManager.predefTagNames.bookmark.text"), "", TagName.HTML_COLOR.NONE); uniqueTagNames.put(tagName.getDisplayName(), tagName); - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add predefined 'Bookmark' tag name", ex); //NON-NLS } } - } - + } + private void saveTagNamesToTagsSettings() { if (!uniqueTagNames.isEmpty()) { StringBuilder setting = new StringBuilder(); @@ -472,7 +540,7 @@ public class TagsManager implements Closeable { setting.append(tagName.getDescription()).append(","); setting.append(tagName.getColor().name()); } - ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); + ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); } - } + } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index cc7958355e..5dccc5252d 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -35,8 +35,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -119,19 +117,14 @@ public class Tags implements AutopsyVisitableItem { private final PropertyChangeListener pcl = new PropertyChangeListener() { @Override - @SuppressWarnings("deprecation") public void propertyChange(PropertyChangeEvent evt) { String eventType = evt.getPropertyName(); - if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { - /* Note: this is a hack. In an ideal world, TagsManager - * would fire events so that the directory tree would - * refresh. But, we haven't had a chance to add that so, we - * fire these events and the tree refreshes based on them. */ - if ((((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT) - || ((ModuleDataEvent) evt.getOldValue()).getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { + if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString()) + || eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString()) + || eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString()) + || eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) { refresh(true); tagResults.update(); - } } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { refresh(true); tagResults.update(); diff --git a/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagAddedEvent.java b/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagAddedEvent.java new file mode 100644 index 0000000000..d50bd2237b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagAddedEvent.java @@ -0,0 +1,33 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.BlackboardArtifactTag; + +/** + * + */ +public class BlackBoardArtifactTagAddedEvent extends TagAddedEvent { + + public BlackBoardArtifactTagAddedEvent(BlackboardArtifactTag newTag) { + super(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString(), newTag + ); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagDeletedEvent.java b/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagDeletedEvent.java new file mode 100644 index 0000000000..b2901ac5dc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/BlackBoardArtifactTagDeletedEvent.java @@ -0,0 +1,32 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.BlackboardArtifactTag; + +/** + * + */ +public class BlackBoardArtifactTagDeletedEvent extends TagDeletedEvent { + + public BlackBoardArtifactTagDeletedEvent(BlackboardArtifactTag oldValue) { + super(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString(), oldValue); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/events/ContentTagAddedEvent.java b/Core/src/org/sleuthkit/autopsy/events/ContentTagAddedEvent.java new file mode 100644 index 0000000000..ffd196a4c7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/ContentTagAddedEvent.java @@ -0,0 +1,35 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.ContentTag; + +/** + * An event that is fired when a ContentTag is added. + */ +@Immutable +public class ContentTagAddedEvent extends TagAddedEvent { + + public ContentTagAddedEvent(ContentTag newTag) { + super(Case.Events.CONTENT_TAG_ADDED.toString(), newTag); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/events/ContentTagDeletedEvent.java b/Core/src/org/sleuthkit/autopsy/events/ContentTagDeletedEvent.java new file mode 100644 index 0000000000..6c6d11745f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/ContentTagDeletedEvent.java @@ -0,0 +1,34 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.ContentTag; + +/** + * An event that is fired when a ContentTag is deleted. + */ +@Immutable +public class ContentTagDeletedEvent extends TagDeletedEvent { + + public ContentTagDeletedEvent(ContentTag deletedTag) { + super(Case.Events.CONTENT_TAG_DELETED.toString(), deletedTag); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java b/Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java new file mode 100644 index 0000000000..b9acb256bb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java @@ -0,0 +1,46 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import java.beans.PropertyChangeEvent; +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.Tag; + +/** + * Base Class for events that are fired when a Tag is added + */ +@Immutable +abstract class TagAddedEvent extends PropertyChangeEvent { + + protected TagAddedEvent(String propertyName, T newValue) { + super(Case.class, propertyName, null, newValue); + } + + /** + * get the Tag that was added + * + * @return the tTag + */ + @SuppressWarnings("unchecked") + public T getAddedTag() { + return (T) getNewValue(); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java b/Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java new file mode 100644 index 0000000000..7d0cfca18e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java @@ -0,0 +1,45 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.events; + +import java.beans.PropertyChangeEvent; +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.Tag; + +/** + * Base Class for events that are fired when a Tag is deleted + */ +@Immutable +abstract class TagDeletedEvent extends PropertyChangeEvent { + + protected TagDeletedEvent(String propertyName, T oldValue) { + super(Case.class, propertyName, oldValue, null); + } + + /** + * get the Tag that was deleted + * + * @return the Tag + */ + @SuppressWarnings("unchecked") + public T getDeletedTag() { + return (T) getOldValue(); + } +} From b5216cc87b0cd8afe9c4ffd0728bb8d2ced1e752 Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 13:53:53 -0400 Subject: [PATCH 108/198] use new Autopsy Tag events, don't fire extra events from ig, but listen to events from autopsy --- .../casemodule/services/TagsManager.java | 1 - .../imagegallery/DrawableTagsManager.java | 82 ++++++++----------- .../imagegallery/ImageGalleryController.java | 30 +++---- .../autopsy/imagegallery/TagsChangeEvent.java | 41 ---------- .../actions/AddDrawableTagAction.java | 9 +- .../imagegallery/actions/AddTagAction.java | 9 +- .../actions/CategorizeAction.java | 27 +++--- .../actions/DeleteFollowUpTagAction.java | 7 +- .../imagegallery/datamodel/Category.java | 12 --- .../datamodel/CategoryChangeEvent.java | 14 +++- .../datamodel/CategoryManager.java | 69 +++++++++++++++- .../imagegallery/datamodel/DrawableFile.java | 2 +- .../imagegallery/grouping/GroupManager.java | 64 +++++++++------ .../imagegallery/gui/DrawableView.java | 8 +- .../imagegallery/gui/DrawableViewBase.java | 18 ++-- .../imagegallery/gui/MetaDataPane.java | 18 ++-- 16 files changed, 208 insertions(+), 203 deletions(-) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 5a52cefde9..72fdf22ca4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -250,7 +250,6 @@ public class TagsManager implements Closeable { final ContentTag newContentTag = tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); Case.getCurrentCase().notifyContentTagAdded(newContentTag); return newContentTag; - return newContentTag; } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 13455d2fb1..0bbc4b9d5a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -27,11 +27,11 @@ import java.util.logging.Level; import java.util.stream.Collectors; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -59,6 +59,32 @@ public class DrawableTagsManager { } + /** + * register an object to receive CategoryChangeEvents + * + * @param listner + */ + public void registerListener(Object listner) { + tagsEventBus.register(listner); + } + + /** + * unregister an object from receiving CategoryChangeEvents + * + * @param listener + */ + public void unregisterListener(Object listener) { + tagsEventBus.unregister(listener); + } + + public void fireTagAddedEvent(ContentTagAddedEvent event) { + tagsEventBus.post(event); + } + + public void fireTagDeletedEvent(ContentTagDeletedEvent event) { + tagsEventBus.post(event); + } + /** * assign a new TagsManager to back this one, ie when the current case * changes @@ -82,24 +108,6 @@ public class DrawableTagsManager { } } - /** - * register an object to receive CategoryChangeEvents - * - * @param listner - */ - public void registerListener(Object listner) { - tagsEventBus.register(listner); - } - - /** - * unregister an object from receiving CategoryChangeEvents - * - * @param listener - */ - public void unregisterListener(Object listener) { - tagsEventBus.unregister(listener); - } - /** * get the (cached) follow up TagName * @@ -120,7 +128,7 @@ public class DrawableTagsManager { synchronized (autopsyTagsManagerLock) { try { return autopsyTagsManager.getAllTagNames().stream() - .filter(Category::isCategoryTagName) + .filter(CategoryManager::isCategoryTagName) .collect(Collectors.toSet()); } catch (TskCoreException | IllegalStateException ex) { Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); @@ -173,12 +181,10 @@ public class DrawableTagsManager { } } - public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { - ContentTag addContentTag; + public ContentTag addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { synchronized (autopsyTagsManagerLock) { - addContentTag = autopsyTagsManager.addContentTag(file, tagName, comment); + return autopsyTagsManager.addContentTag(file, tagName, comment); } - fireTagAdded(addContentTag); } public List getContentTagsByTagName(TagName t) throws TskCoreException { @@ -187,21 +193,6 @@ public class DrawableTagsManager { } } - /** - * Fire the ModuleDataEvent that we use as a place holder for a real Tag - * Event. This is used to refresh the autopsy tag tree and the ui in - * ImageGallery - * - * - * Note: this is a hack. In an ideal world, TagsManager would fire - * events so that the directory tree would refresh. But, we haven't - * had a chance to add that so, we fire these events and the tree - * refreshes based on them. - */ - static public void refreshTagsInAutopsy() { - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - } - public List getAllTagNames() throws TskCoreException { synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getAllTagNames(); @@ -214,18 +205,9 @@ public class DrawableTagsManager { } } - public void fireTagAdded(ContentTag newTag) { - tagsEventBus.post(new TagsChangeEvent(Collections.singleton(newTag.getContent().getId()))); - } - - public void fireTagDeleted(ContentTag oldTag) { - tagsEventBus.post(new TagsChangeEvent(Collections.singleton(oldTag.getContent().getId()))); - } - public void deleteContentTag(ContentTag ct) throws TskCoreException { synchronized (autopsyTagsManagerLock) { autopsyTagsManager.deleteContentTag(ct); } - fireTagDeleted(ct); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 046c88bc7a..6c6bd7c789 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.imagegallery; import java.beans.PropertyChangeEvent; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.BlockingQueue; @@ -58,10 +57,9 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.History; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; @@ -74,7 +72,6 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase; @@ -366,6 +363,8 @@ public final class ImageGalleryController { categoryManager.setDb(db); tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); tagsManager.registerListener(groupManager); + tagsManager.registerListener(categoryManager); + } else { reset(); } @@ -384,6 +383,7 @@ public final class ImageGalleryController { }); tagsManager.clearFollowUpTagName(); tagsManager.unregisterListener(groupManager); + tagsManager.unregisterListener(categoryManager); Toolbar.getDefault(this).reset(); groupManager.clear(); @@ -490,23 +490,15 @@ public final class ImageGalleryController { } break; case CONTENT_TAG_ADDED: - ContentTag newTag = (ContentTag) evt.getNewValue(); - if (Category.isCategoryTagName(newTag.getName())) { - new CategorizeAction(ImageGalleryController.this).addTag(newTag.getName(), ""); - } else { - getTagsManager().fireTagAdded(newTag); + final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt; + if (getDatabase().isInDB((tagAddedEvent).getAddedTag().getContent().getId())) { + getTagsManager().fireTagAddedEvent(tagAddedEvent); } break; case CONTENT_TAG_DELETED: - ContentTag oldTag = (ContentTag) evt.getOldValue(); - final long fileID = oldTag.getContent().getId(); - if (getDatabase().isInDB(fileID)) { - if (Category.isCategoryTagName(oldTag.getName())) { - getCategoryManager().decrementCategoryCount(Category.fromTagName(oldTag.getName())); - getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); - } else { - getTagsManager().fireTagDeleted(oldTag); - } + final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) evt; + if (getDatabase().isInDB((tagDeletedEvent).getDeletedTag().getContent().getId())) { + getTagsManager().fireTagDeletedEvent(tagDeletedEvent); } break; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java deleted file mode 100644 index 0647a18456..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery; - -import java.util.Collection; -import java.util.Collections; -import javax.annotation.concurrent.Immutable; - -/** - * - */ -@Immutable -public class TagsChangeEvent { - - private final Collection fileIDs; - - public Collection getFileIDs() { - return Collections.unmodifiableCollection(fileIDs); - } - - public TagsChangeEvent(Collection fileIDs) { - this.fileIDs = fileIDs; - } - -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index e88c51f12b..be9343f4de 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -28,11 +27,8 @@ import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.openide.util.Utilities; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TagName; @@ -87,10 +83,9 @@ public class AddDrawableTagAction extends AddTagAction { JOptionPane.showMessageDialog(null, "Unable to tag " + fileID + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); } - //make sure rest of ui hears category change. - controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); +// //make sure rest of ui hears category change. +// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } - DrawableTagsManager.refreshTagsInAutopsy(); return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index a82244d368..f20fccfcfd 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -31,7 +31,7 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -95,11 +95,10 @@ abstract class AddTagAction { // a tag with the associated tag name. if (null != tagNames && !tagNames.isEmpty()) { for (final TagName tagName : tagNames) { - if (Category.isNotCategoryTagName(tagName)) { + if (CategoryManager.isNotCategoryTagName(tagName)) { MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); tagNameItem.setOnAction((ActionEvent t) -> { addTag(tagName, NO_COMMENT); - DrawableTagsManager.refreshTagsInAutopsy(); }); quickTagMenu.getItems().add(tagNameItem); } @@ -120,7 +119,6 @@ abstract class AddTagAction { TagName tagName = GetTagNameDialog.doDialog(); if (tagName != null) { addTag(tagName, NO_COMMENT); - } }); }); @@ -134,12 +132,11 @@ abstract class AddTagAction { SwingUtilities.invokeLater(() -> { GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); if (null != tagNameAndComment) { - if (Category.isCategoryTagName(tagNameAndComment.getTagName())) { + if (CategoryManager.isCategoryTagName(tagNameAndComment.getTagName())) { new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } else { new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } - } }); }); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 8918934a6e..067a5cf967 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -32,7 +31,6 @@ import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; @@ -41,7 +39,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -87,6 +84,10 @@ public class CategorizeAction extends AddTagAction { } } + public void enforceOneCat(TagName name, String string) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + /** * Instances of this class implement a context menu user interface for * selecting a category @@ -127,8 +128,8 @@ public class CategorizeAction extends AddTagAction { @Override public void run() { final GroupManager groupManager = controller.getGroupManager(); - final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); final CategoryManager categoryManager = controller.getCategoryManager(); + final DrawableTagsManager tagsManager = controller.getTagsManager(); try { DrawableFile file = controller.getFileFromId(fileID); //drawable db @@ -138,27 +139,27 @@ public class CategorizeAction extends AddTagAction { groupManager.removeFromGroup(new GroupKey(DrawableAttribute.CATEGORY, oldCat), fileID); //memory //remove old category tag if necessary - List allContentTags = sleuthKitCase.getContentTagsByContent(file); //tsk db + List allContentTags = tagsManager.getContentTagsByContent(file); //tsk db + //JMTODO: move this to CategoryManager for (ContentTag ct : allContentTags) { - if (Category.isCategoryTagName(ct.getName())) { - sleuthKitCase.deleteContentTag(ct); //tsk db - categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db + if (CategoryManager.isCategoryTagName(ct.getName())) { + tagsManager.deleteContentTag(ct); //tsk db +// categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db } } - categoryManager.incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db +// categoryManager.incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db if (tagName != categoryManager.getTagName(Category.ZERO)) { // no tags for cat-0 - controller.getTagsManager().addContentTag(file, tagName, comment); //tsk db + tagsManager.addContentTag(file, tagName, comment); //tsk db } - //make sure rest of ui hears category change. - groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui +// //make sure rest of ui hears category change. +// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error categorizing result", ex); JOptionPane.showMessageDialog(null, "Unable to categorize " + fileID + ".", "Categorizing Error", JOptionPane.ERROR_MESSAGE); } - DrawableTagsManager.refreshTagsInAutopsy(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 98fdc316ad..aab8a9c827 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.util.Collections; import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; @@ -26,14 +25,12 @@ import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -53,7 +50,6 @@ public class DeleteFollowUpTagAction extends Action { @Override protected Void doInBackground() throws Exception { - final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); final GroupManager groupManager = controller.getGroupManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); @@ -69,9 +65,8 @@ public class DeleteFollowUpTagAction extends Action { } } - DrawableTagsManager.refreshTagsInAutopsy(); //make sure rest of ui hears category change. - groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); +// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 00750c4ba9..8999fff2f1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -23,7 +23,6 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import javafx.scene.paint.Color; -import org.sleuthkit.datamodel.TagName; /** * Enum to represent the six categories in the DHs image categorization scheme. @@ -49,17 +48,6 @@ public enum Category { public static Category fromDisplayName(String displayName) { return nameMap.get(displayName); } - public static Category fromTagName(TagName tagName) { - return nameMap.get(tagName.getDisplayName()); - } - - public static boolean isCategoryTagName(TagName tName) { - return isCategoryName(tName.getDisplayName()); - } - - public static boolean isNotCategoryTagName(TagName tName) { - return isNotCategoryName(tName.getDisplayName()); - } public static boolean isCategoryName(String tName) { return nameMap.containsKey(tName); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java index 9896325e09..3868864737 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java @@ -30,6 +30,16 @@ import javax.annotation.concurrent.Immutable; public class CategoryChangeEvent { private final Collection fileIDs; + private final Category newCategory; + + public CategoryChangeEvent(Collection fileIDs, Category newCategory) { + this.fileIDs = fileIDs; + this.newCategory = newCategory; + } + + public Category getNewCategory() { + return newCategory; + } /** * @return the fileIDs of the files whose categories have changed @@ -37,8 +47,4 @@ public class CategoryChangeEvent { public Collection getFileIDs() { return Collections.unmodifiableCollection(fileIDs); } - - public CategoryChangeEvent(Collection fileIDs) { - this.fileIDs = fileIDs; - } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index f8b0e6beb1..b6a11d2b25 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -24,11 +24,17 @@ import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; /** * Provides a cached view of the number of files per category, and fires @@ -94,13 +100,13 @@ public class CategoryManager { this.db = db; categoryCounts.invalidateAll(); catTagNameMap.invalidateAll(); - fireChange(Collections.singleton(-1L)); + fireChange(Collections.emptyList(), null); } synchronized public void invalidateCaches() { categoryCounts.invalidateAll(); catTagNameMap.invalidateAll(); - fireChange(Collections.singleton(-1L)); + fireChange(Collections.emptyList(), null); } /** @@ -173,8 +179,8 @@ public class CategoryManager { * * @param fileIDs */ - public void fireChange(Collection fileIDs) { - categoryEventBus.post(new CategoryChangeEvent(fileIDs)); + public void fireChange(Collection fileIDs, Category newCategory) { + categoryEventBus.post(new CategoryChangeEvent(fileIDs, newCategory)); } /** @@ -204,4 +210,59 @@ public class CategoryManager { return catTagNameMap.getUnchecked(cat); } + + public static Category fromTagName(TagName tagName) { + return Category.fromDisplayName(tagName.getDisplayName()); + } + + public static boolean isCategoryTagName(TagName tName) { + return Category.isCategoryName(tName.getDisplayName()); + } + + public static boolean isNotCategoryTagName(TagName tName) { + return Category.isNotCategoryName(tName.getDisplayName()); + + } + + public void handleTagAdded(ContentTagAddedEvent event) { + ContentTag addedTag = event.getAddedTag(); + if (isCategoryTagName(addedTag.getName())) { + final DrawableTagsManager tagsManager = controller.getTagsManager(); + try { + //remove old category tag(s) if necessary + List allContentTags = tagsManager.getContentTagsByContent(addedTag.getContent()); + + for (ContentTag ct : allContentTags) { + if (ct.getId() != addedTag.getId() + && CategoryManager.isCategoryTagName(ct.getName())) { + try { + tagsManager.deleteContentTag(ct); + } catch (TskCoreException tskException) { + LOGGER.log(Level.SEVERE, "Failed to delete content tag. Unable to maintain categories in a consistent state.", tskException); + } + } + } + } catch (TskCoreException tskException) { + LOGGER.log(Level.SEVERE, "Failed to get content tags for content. Unable to maintain category in a consistent state.", tskException); + } + Category newCat = CategoryManager.fromTagName(addedTag.getName()); + if (newCat != Category.ZERO) { + incrementCategoryCount(newCat); + } + + fireChange(Collections.singleton(addedTag.getId()), newCat); + } + } + + public void handleTagDeleted(ContentTagDeletedEvent event) { + ContentTag deleted = event.getDeletedTag(); + if (isCategoryTagName(deleted.getName())) { + + Category deletedCat = CategoryManager.fromTagName(deleted.getName()); + if (deletedCat != Category.ZERO) { + decrementCategoryCount(deletedCat); + } + fireChange(Collections.singleton(deleted.getId()), null); + } + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 3890ca577a..79ea49f879 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -272,7 +272,7 @@ public abstract class DrawableFile extends AbstractFile private void updateCategory() { try { category.set(getSleuthkitCase().getContentTagsByContent(this).stream() - .map(Tag::getName).filter(Category::isCategoryTagName) + .map(Tag::getName).filter(CategoryManager::isCategoryTagName) .map(TagName::getDisplayName) .map(Category::fromDisplayName) .sorted().findFirst() //sort by severity and take the first diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 51a99bd5f7..733baf2813 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -60,12 +60,14 @@ import org.sleuthkit.autopsy.coreutils.LoggedTask; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; -import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -161,7 +163,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { Set> resultSet = new HashSet<>(); for (Comparable val : groupBy.getValue(file)) { if (groupBy == DrawableAttribute.TAGS) { - if (Category.isNotCategoryTagName((TagName) val)) { + if (CategoryManager.isNotCategoryTagName((TagName) val)) { resultSet.add(new GroupKey(groupBy, val)); } } else { @@ -282,6 +284,10 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { }); } } + } else { //group == null + // It may be that this was the last unanalyzed file in the group, so test + // whether the group is now fully analyzed. + popuplateIfAnalyzed(groupKey, null); } return group; @@ -360,7 +366,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { break; case TAGS: values = (List) controller.getTagsManager().getTagNamesInUse().stream() - .filter(Category::isNotCategoryTagName) + .filter(CategoryManager::isNotCategoryTagName) .collect(Collectors.toList()); break; case ANALYZED: @@ -528,14 +534,31 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } @Subscribe - public void handleAutopsyTagChange(TagsChangeEvent evt) { - if (groupBy == DrawableAttribute.TAGS - && evt.getFileIDs().size() == 1 - && evt.getFileIDs().contains(-1L)) { - regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); + public void handleTagAdded(ContentTagAddedEvent evt) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + final long fileID = evt.getAddedTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); + + } + + private void addFileToGroup(DrawableGroup g, final GroupKey groupKey, final long fileID) { + if (g == null) { + //if there wasn't already a group check if there should be one now + popuplateIfAnalyzed(groupKey, null); + } else { + //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. + g.addFile(fileID); } } + @Subscribe + public void handleTagDeleted(ContentTagDeletedEvent evt) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); + final long fileID = evt.getDeletedTag().getContent().getId(); + DrawableGroup g = removeFromGroup(groupKey, fileID); + } + @Override synchronized public void handleFileRemoved(FileUpdateEvent evt) { Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.REMOVE); @@ -545,13 +568,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { Set> groupsForFile = getGroupKeysForFileID(fileId); for (GroupKey gk : groupsForFile) { - DrawableGroup g = removeFromGroup(gk, fileId); - - if (g == null) { - // It may be that this was the last unanalyzed file in the group, so test - // whether the group is now fully analyzed. - popuplateIfAnalyzed(gk, null); - } + removeFromGroup(gk, fileId); } } } @@ -578,29 +595,21 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { //get grouping(s) this file would be in Set> groupsForFile = getGroupKeysForFileID(fileId); - for (GroupKey gk : groupsForFile) { DrawableGroup g = getGroupForKey(gk); - - if (g == null) { - //if there wasn't already a group check if there should be one now - popuplateIfAnalyzed(gk, null); - } else { - //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. - g.addFile(fileId); - } + addFileToGroup(g, gk, fileId); } } //we fire this event for all files so that the category counts get updated during initial db population - controller.getCategoryManager().fireChange(fileIDs); + controller.getCategoryManager().fireChange(fileIDs, null); // if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { // controller.getTagsManager().fireChange(fileIDs); // } } - private void popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { + private DrawableGroup popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { if (Objects.nonNull(task) && (task.isCancelled())) { /* if this method call is part of a ReGroupTask and that task is @@ -609,6 +618,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * this allows us to stop if a regroup task has been cancelled (e.g. * the user picked a different group by attribute, while the * current task was still running) */ + } else { // no task or un-cancelled task if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { /* for attributes other than path we can't be sure a group is @@ -639,12 +649,14 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } markGroupSeen(group, groupSeen); }); + return group; } } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); } } } + return null; } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 99d8671a63..9b442273d1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -12,8 +12,9 @@ import javafx.scene.layout.Region; import javafx.scene.paint.Color; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; @@ -68,7 +69,10 @@ public interface DrawableView { void handleCategoryChanged(CategoryChangeEvent evt); @Subscribe - void handleTagsChanged(TagsChangeEvent evt); + void handleTagAdded(ContentTagAddedEvent evt); + + @Subscribe + void handleTagDeleted(ContentTagDeletedEvent evt); ImageGalleryController getController(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 93026d688d..ea88d2dfbb 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -61,10 +61,11 @@ import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; -import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; @@ -378,16 +379,21 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override - synchronized public void handleTagsChanged(TagsChangeEvent evnt) { - if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { - updateFollowUpIcon(); - } + public void handleTagAdded(ContentTagAddedEvent evt) { + + updateFollowUpIcon(); + } + + @Subscribe + @Override + public void handleTagDeleted(ContentTagDeletedEvent evt) { + updateFollowUpIcon(); } @Subscribe @Override synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { - if (evt.getFileIDs().contains(getFileID()) || evt.getFileIDs().contains(-1L)) { + if (fileID != null && evt.getFileIDs().contains(getFileID())) { updateCategoryBorder(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index 4f4cace550..0681d29eb9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -44,8 +44,9 @@ import javafx.scene.text.Text; import javafx.util.Pair; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -225,16 +226,23 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @Subscribe @Override public void handleCategoryChanged(CategoryChangeEvent evt) { - if (getFile() != null && (evt.getFileIDs().contains(-1L) || evt.getFileIDs().contains(getFileID()))) { + if (getFile() != null && evt.getFileIDs().contains(getFileID())) { updateUI(); } } @Override - @Subscribe - public void handleTagsChanged(TagsChangeEvent evt) { - if (getFile() != null && (evt.getFileIDs().contains(-1L) || evt.getFileIDs().contains(getFileID()))) { + public void handleTagAdded(ContentTagAddedEvent evt) { + if (getFile() != null && evt.getAddedTag().getContent().getId() == getFileID()) { updateUI(); } } + + @Override + public void handleTagDeleted(ContentTagDeletedEvent evt) { + if (getFile() != null && evt.getDeletedTag().getContent().getId() == getFileID()) { + updateUI(); + } + } + } From 2c879f43bf50b409187fc077036f4cc08b2d19b1 Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 17:20:35 -0400 Subject: [PATCH 109/198] remove uneeded notification code; let event handlers do it all. optionalize DrawableView --- Core/nbproject/project.xml | 1 + .../actions/AddDrawableTagAction.java | 3 - .../actions/CategorizeAction.java | 33 +- .../actions/DeleteFollowUpTagAction.java | 11 +- .../datamodel/CategoryManager.java | 3 +- .../imagegallery/grouping/GroupManager.java | 26 +- .../imagegallery/gui/DrawableTile.java | 16 +- .../imagegallery/gui/DrawableView.java | 13 +- .../imagegallery/gui/DrawableViewBase.java | 301 ++++++++++-------- .../imagegallery/gui/MetaDataPane.java | 114 ++++--- .../imagegallery/gui/SlideShowView.java | 81 +++-- 11 files changed, 341 insertions(+), 261 deletions(-) diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index ac5f32a1ac..463e1c1903 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -192,6 +192,7 @@ org.sleuthkit.autopsy.coreutils org.sleuthkit.autopsy.datamodel org.sleuthkit.autopsy.directorytree + org.sleuthkit.autopsy.events org.sleuthkit.autopsy.externalresults org.sleuthkit.autopsy.filesearch org.sleuthkit.autopsy.ingest diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index be9343f4de..3c115d9134 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -82,9 +82,6 @@ public class AddDrawableTagAction extends AddTagAction { LOGGER.log(Level.SEVERE, "Error tagging result", ex); JOptionPane.showMessageDialog(null, "Unable to tag " + fileID + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); } - -// //make sure rest of ui hears category change. -// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 067a5cf967..afe2b3bb5d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.logging.Level; import javafx.event.ActionEvent; @@ -34,11 +33,7 @@ import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -127,33 +122,25 @@ public class CategorizeAction extends AddTagAction { @Override public void run() { - final GroupManager groupManager = controller.getGroupManager(); final CategoryManager categoryManager = controller.getCategoryManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); try { DrawableFile file = controller.getFileFromId(fileID); //drawable db - Category oldCat = file.getCategory(); - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.CATEGORY, oldCat), fileID); //memory - - //remove old category tag if necessary - List allContentTags = tagsManager.getContentTagsByContent(file); //tsk db - - //JMTODO: move this to CategoryManager - for (ContentTag ct : allContentTags) { - if (CategoryManager.isCategoryTagName(ct.getName())) { - tagsManager.deleteContentTag(ct); //tsk db -// categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db - } - } -// categoryManager.incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db if (tagName != categoryManager.getTagName(Category.ZERO)) { // no tags for cat-0 tagsManager.addContentTag(file, tagName, comment); //tsk db + } else { + tagsManager.getContentTagsByContent(file).stream() + .filter(tag -> CategoryManager.isCategoryTagName(tag.getName())) + .forEach((ct) -> { + try { + tagsManager.deleteContentTag(ct); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error removing old categories result", ex); + } + }); } -// //make sure rest of ui hears category change. -// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error categorizing result", ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index aab8a9c827..74082fcd1c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -26,10 +26,7 @@ import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -50,23 +47,17 @@ public class DeleteFollowUpTagAction extends Action { @Override protected Void doInBackground() throws Exception { - final GroupManager groupManager = controller.getGroupManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); try { final TagName followUpTagName = tagsManager.getFollowUpTagName(); - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); - + List contentTagsByContent = tagsManager.getContentTagsByContent(file); for (ContentTag ct : contentTagsByContent) { if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { tagsManager.deleteContentTag(ct); } } - - //make sure rest of ui hears category change. -// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index b6a11d2b25..466278f588 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -224,6 +224,7 @@ public class CategoryManager { } + @Subscribe public void handleTagAdded(ContentTagAddedEvent event) { ContentTag addedTag = event.getAddedTag(); if (isCategoryTagName(addedTag.getName())) { @@ -253,7 +254,7 @@ public class CategoryManager { fireChange(Collections.singleton(addedTag.getId()), newCat); } } - + @Subscribe public void handleTagDeleted(ContentTagDeletedEvent event) { ContentTag deleted = event.getDeletedTag(); if (isCategoryTagName(deleted.getName())) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 733baf2813..9ac899742c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -279,8 +279,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { if (groupKey.getAttribute() != DrawableAttribute.CATEGORY) { if (group.fileIds().isEmpty()) { Platform.runLater(() -> { - analyzedGroups.remove(group); - unSeenGroups.remove(group); + if (analyzedGroups.contains(group)) { + analyzedGroups.remove(group); + } + if (unSeenGroups.contains(group)) { + unSeenGroups.remove(group); + } }); } } @@ -535,10 +539,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); - final long fileID = evt.getAddedTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); + if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + final long fileID = evt.getAddedTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); + } } @@ -554,9 +560,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagDeleted(ContentTagDeletedEvent evt) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); - final long fileID = evt.getDeletedTag().getContent().getId(); - DrawableGroup g = removeFromGroup(groupKey, fileID); + if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); + final long fileID = evt.getDeletedTag().getContent().getId(); + DrawableGroup g = removeFromGroup(groupKey, fileID); + } } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java index 75332ba158..96f05dd9c1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java @@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableViewBase.globalSelectionModel; +import org.sleuthkit.datamodel.AbstractContent; /** * GUI component that represents a single image as a tile with an icon, a label, @@ -109,15 +110,20 @@ public class DrawableTile extends DrawableViewBase { @Override protected Runnable getContentUpdateRunnable() { - Image image = getFile().getThumbnail(); + if (getFile().isPresent()) { + Image image = getFile().get().getThumbnail(); - return () -> { - imageView.setImage(image); - }; + return () -> { + imageView.setImage(image); + }; + } else { + return () -> { //no-op + }; + } } @Override protected String getTextForLabel() { - return getFile().getName(); + return getFile().map(AbstractContent::getName).orElse(""); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 9b442273d1..e4e6faf1de 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -1,6 +1,8 @@ package org.sleuthkit.autopsy.imagegallery.gui; import com.google.common.eventbus.Subscribe; +import java.util.Collection; +import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; import javafx.scene.layout.Border; @@ -51,11 +53,11 @@ public interface DrawableView { Region getCategoryBorderRegion(); - DrawableFile getFile(); + Optional> getFile(); void setFile(final Long fileID); - Long getFileID(); + Optional getFileID(); /** * update the visual representation of the category of the assigned file. @@ -78,7 +80,10 @@ public interface DrawableView { default boolean hasHashHit() { try { - return getFile().getHashHitSetNames().isEmpty() == false; + return getFile().map(DrawableFile::getHashHitSetNames) + .map((Collection t) -> t.isEmpty() == false) + .orElse(false); + } catch (NullPointerException ex) { // I think this happens when we're in the process of removing images from the view while // also trying to update it? @@ -113,7 +118,7 @@ public interface DrawableView { @ThreadConfined(type = ThreadConfined.ThreadType.ANY) default Category updateCategoryBorder() { if (getFile() != null) { - final Category category = getFile().getCategory(); + final Category category = getFile().map(DrawableFile::getCategory).orElse(Category.ZERO); final Border border = hasHashHit() && (category == Category.ZERO) ? HASH_BORDER : getCategoryBorder(category); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index ea88d2dfbb..a1ee32a108 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -23,6 +23,8 @@ import com.google.common.eventbus.Subscribe; import java.util.ArrayList; import java.util.Collection; import java.util.Objects; +import static java.util.Objects.nonNull; +import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; import javafx.beans.Observable; @@ -130,9 +132,33 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie static private ContextMenu contextMenu; - private DrawableFile file; + volatile private Optional> fileOpt = Optional.empty(); - private Long fileID; + volatile private Optional fileIDOpt = Optional.empty(); + + @Override + public Optional getFileID() { + return fileIDOpt; + } + + @Override + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + try { + fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); + } catch (TskCoreException ex) { + Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); + fileOpt = Optional.empty(); + } + return fileOpt; + } + } else { + return Optional.empty(); + } + } /** * the groupPane this {@link DrawableViewBase} is embedded in @@ -158,43 +184,44 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Override public void handle(MouseEvent t) { + getFile().ifPresent(file -> { + final long fileID = file.getId(); + switch (t.getButton()) { + case PRIMARY: + if (t.getClickCount() == 1) { + if (t.isControlDown()) { - switch (t.getButton()) { - case PRIMARY: - if (t.getClickCount() == 1) { - if (t.isControlDown()) { - globalSelectionModel.toggleSelection(fileID); - } else { - groupPane.makeSelection(t.isShiftDown(), fileID); + globalSelectionModel.toggleSelection(fileID); + } else { + groupPane.makeSelection(t.isShiftDown(), fileID); + } + } else if (t.getClickCount() > 1) { + groupPane.activateSlideShowViewer(fileID); } - } else if (t.getClickCount() > 1) { - groupPane.activateSlideShowViewer(fileID); - } - break; - case SECONDARY: - - if (t.getClickCount() == 1) { - if (globalSelectionModel.isSelected(fileID) == false) { - groupPane.makeSelection(false, fileID); + break; + case SECONDARY: + if (t.getClickCount() == 1) { + if (globalSelectionModel.isSelected(fileID) == false) { + groupPane.makeSelection(false, fileID); + } } - } + if (contextMenu != null) { + contextMenu.hide(); + } + final ContextMenu groupContextMenu = groupPane.getContextMenu(); + if (groupContextMenu != null) { + groupContextMenu.hide(); + } + contextMenu = buildContextMenu(file); + contextMenu.show(DrawableViewBase.this, t.getScreenX(), t.getScreenY()); + break; + } + }); - if (contextMenu != null) { - contextMenu.hide(); - } - final ContextMenu groupContextMenu = groupPane.getContextMenu(); - if (groupContextMenu != null) { - groupContextMenu.hide(); - } - contextMenu = buildContextMenu(); - contextMenu.show(DrawableViewBase.this, t.getScreenX(), t.getScreenY()); - - break; - } t.consume(); } - private ContextMenu buildContextMenu() { + private ContextMenu buildContextMenu(DrawableFile file) { final ArrayList menuItems = new ArrayList<>(); menuItems.add(new CategorizeAction(controller).getPopupMenu()); @@ -213,13 +240,13 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie MenuItem contentViewer = new MenuItem("Show Content Viewer"); contentViewer.setOnAction((ActionEvent t) -> { SwingUtilities.invokeLater(() -> { - new NewWindowViewAction("Show Content Viewer", new FileNode(getFile().getAbstractFile())).actionPerformed(null); + new NewWindowViewAction("Show Content Viewer", new FileNode(file.getAbstractFile())).actionPerformed(null); }); }); menuItems.add(contentViewer); MenuItem externalViewer = new MenuItem("Open in External Viewer"); - final ExternalViewerAction externalViewerAction = new ExternalViewerAction("Open in External Viewer", new FileNode(getFile().getAbstractFile())); + final ExternalViewerAction externalViewerAction = new ExternalViewerAction("Open in External Viewer", new FileNode(file.getAbstractFile())); externalViewer.setDisable(externalViewerAction.isEnabled() == false); externalViewer.setOnAction((ActionEvent t) -> { @@ -259,116 +286,106 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @SuppressWarnings("deprecation") protected void initialize() { followUpToggle.setOnAction((ActionEvent event) -> { - if (followUpToggle.isSelected() == true) { - try { - final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); - globalSelectionModel.clearAndSelect(fileID); - new AddDrawableTagAction(controller).addTag(followUpTagName, ""); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); + getFile().ifPresent(file -> { + if (followUpToggle.isSelected() == true) { + try { + final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); + globalSelectionModel.clearAndSelect(file.getId()); + new AddDrawableTagAction(controller).addTag(followUpTagName, ""); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); + } + } else { + new DeleteFollowUpTagAction(controller, file).handle(event); } - } else { - new DeleteFollowUpTagAction(controller, file).handle(event); - } + }); }); } - @Override - public DrawableFile getFile() { - if (fileID != null) { - if (file == null || file.getId() != fileID) { - try { - file = ImageGalleryController.getDefault().getFileFromId(fileID); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileID, ex); - file = null; - } - } - return file; - } else { - return null; - } - } - - protected boolean hasFollowUp() throws TskCoreException { - String followUpTagName = getController().getTagsManager().getFollowUpTagName().getDisplayName(); - Collection tagNames = DrawableAttribute.TAGS.getValue(getFile()); - return tagNames.stream().anyMatch((tn) -> tn.getDisplayName().equals(followUpTagName)); - } - - @Override - synchronized public Long getFileID() { - return fileID; - } - - synchronized protected void updateFollowUpIcon() { - if (file != null) { + protected boolean hasFollowUp() { + if (getFile().isPresent()) { try { - boolean hasFollowUp = hasFollowUp(); - Platform.runLater(() -> { - followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray); - followUpToggle.setSelected(hasFollowUp); - }); + TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); + Collection tagNames = DrawableAttribute.TAGS.getValue(getFile().get()); + return tagNames.stream().anyMatch((tn) -> tn.equals(followUpTagName)); } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + LOGGER.log(Level.WARNING, "failed to get follow up tag name ", ex); + return true; } + } else { + return false; } } @Override - synchronized public void setFile(final Long fileID) { - if (Objects.equals(fileID, this.fileID) == false) { - this.fileID = fileID; - disposeContent(); - - if (this.fileID == null || Case.isCaseOpen() == false) { - if (registered == true) { - getController().getCategoryManager().unregisterListener(this); - getController().getTagsManager().unregisterListener(this); - registered = false; - } - file = null; - Platform.runLater(() -> { - clearContent(); - }); - } else { - if (registered == false) { - getController().getCategoryManager().registerListener(this); - getController().getTagsManager().registerListener(this); - registered = true; - } - file = null; - getFile(); - updateSelectionState(); - updateCategoryBorder(); - updateFollowUpIcon(); - updateUI(); - Platform.runLater(getContentUpdateRunnable()); + public void setFile(final Long newFileID) { + if (fileIDOpt.isPresent()) { + if (Objects.equals(newFileID, fileIDOpt.get()) == false) { + setFileHelper(newFileID); } + } else { + if (nonNull(newFileID)) { + setFileHelper(newFileID); + } + } + } + + private void setFileHelper(final Long newFileID) { + fileIDOpt = Optional.ofNullable(newFileID); + disposeContent(); + + if (fileIDOpt.isPresent() == false || Case.isCaseOpen() == false) { + if (registered == true) { + getController().getCategoryManager().unregisterListener(this); + getController().getTagsManager().unregisterListener(this); + registered = false; + } + fileOpt = Optional.empty(); + Platform.runLater(() -> { + clearContent(); + }); + } else { + if (registered == false) { + getController().getCategoryManager().registerListener(this); + getController().getTagsManager().registerListener(this); + registered = true; + } + fileOpt = Optional.empty(); + + updateSelectionState(); + updateCategoryBorder(); + updateFollowUpIcon(); + updateUI(); + Platform.runLater(getContentUpdateRunnable()); } } private void updateUI() { - final boolean isVideo = getFile().isVideo(); - final boolean hasHashSetHits = hasHashHit(); - final String text = getTextForLabel(); + getFile().ifPresent(file -> { + final boolean isVideo = file.isVideo(); + final boolean hasHashSetHits = hasHashHit(); + final String text = getTextForLabel(); - Platform.runLater(() -> { - fileTypeImageView.setImage(isVideo ? videoIcon : null); - hashHitImageView.setImage(hasHashSetHits ? hashHitIcon : null); - nameLabel.setText(text); - nameLabel.setTooltip(new Tooltip(text)); + Platform.runLater(() -> { + fileTypeImageView.setImage(isVideo ? videoIcon : null); + hashHitImageView.setImage(hasHashSetHits ? hashHitIcon : null); + nameLabel.setText(text); + nameLabel.setTooltip(new Tooltip(text)); + }); }); + } /** * update the visual representation of the selection state of this * DrawableView */ - synchronized protected void updateSelectionState() { - final boolean selected = globalSelectionModel.isSelected(getFileID()); - Platform.runLater(() -> { - setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER); + protected void updateSelectionState() { + getFile().ifPresent(file -> { + final boolean selected = globalSelectionModel.isSelected(file.getId()); + Platform.runLater(() -> { + setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER); + }); }); } @@ -380,22 +397,54 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { + fileIDOpt.ifPresent(fileID -> { + try { + if (fileID == evt.getAddedTag().getContent().getId() + && evt.getAddedTag().getName() == getController().getTagsManager().getFollowUpTagName()) { - updateFollowUpIcon(); + Platform.runLater(() -> { + followUpImageView.setImage(followUpIcon); + followUpToggle.setSelected(true); + }); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + } + }); } @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - updateFollowUpIcon(); + + fileIDOpt.ifPresent(fileID -> { + try { + if (fileID == evt.getDeletedTag().getContent().getId() + && evt.getDeletedTag().getName() == controller.getTagsManager().getFollowUpTagName()) { + updateFollowUpIcon(); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + } + }); + } + + private void updateFollowUpIcon() { + boolean hasFollowUp = hasFollowUp(); + Platform.runLater(() -> { + followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray); + followUpToggle.setSelected(hasFollowUp); + }); } @Subscribe @Override - synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { - if (fileID != null && evt.getFileIDs().contains(getFileID())) { - updateCategoryBorder(); - } + public void handleCategoryChanged(CategoryChangeEvent evt) { + fileIDOpt.ifPresent(fileID -> { + if (evt.getFileIDs().contains(fileID)) { + updateCategoryBorder(); + } + }); } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index 0681d29eb9..87bd64491f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -22,6 +22,9 @@ import com.google.common.eventbus.Subscribe; import java.io.IOException; import java.util.Arrays; import java.util.Collection; +import java.util.Objects; +import static java.util.Objects.nonNull; +import java.util.Optional; import java.util.logging.Level; import java.util.stream.Collectors; import javafx.application.Platform; @@ -68,8 +71,6 @@ public class MetaDataPane extends AnchorPane implements DrawableView { return controller; } - private Long fileID; - @FXML private ImageView imageView; @@ -85,13 +86,6 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @FXML private BorderPane imageBorder; - private DrawableFile file; - - @Override - public Long getFileID() { - return fileID; - } - @FXML @SuppressWarnings("unchecked") void initialize() { @@ -152,29 +146,52 @@ public class MetaDataPane extends AnchorPane implements DrawableView { }); } + volatile private Optional> fileOpt = Optional.empty(); + + volatile private Optional fileIDOpt = Optional.empty(); + @Override - public DrawableFile getFile() { - if (fileID != null) { - if (file == null || file.getId() != fileID) { - try { - file = controller.getFileFromId(fileID); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileID, ex); - return null; - } - } - } else { - return null; - } - return file; + public Optional getFileID() { + return fileIDOpt; } @Override - public void setFile(Long fileID) { - this.fileID = fileID; + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + try { + fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); + } catch (TskCoreException ex) { + Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); + fileOpt = Optional.empty(); + } + return fileOpt; + } + } else { + return Optional.empty(); + } + } - if (fileID == null) { + @Override + public void setFile(Long newFileID) { + if (fileIDOpt.isPresent()) { + if (Objects.equals(newFileID, fileIDOpt.get()) == false) { + setFileHelper(newFileID); + } + } else { + if (nonNull(newFileID)) { + setFileHelper(newFileID); + } + } + setFileHelper(newFileID); + } + + private void setFileHelper(Long newFileID) { + fileIDOpt = Optional.of(newFileID); + if (newFileID == null) { Platform.runLater(() -> { imageView.setImage(null); tableView.getItems().clear(); @@ -182,12 +199,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { }); } else { - try { - file = controller.getFileFromId(fileID); - updateUI(); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Failed to get drawable file from ID", ex); - } + updateUI(); } } @@ -206,15 +218,18 @@ public class MetaDataPane extends AnchorPane implements DrawableView { } public void updateUI() { - final Image icon = getFile().getThumbnail(); - final ObservableList, ? extends Object>> attributesList = getFile().getAttributesList(); + getFile().ifPresent(file -> { + final Image icon = file.getThumbnail(); + final ObservableList, ? extends Object>> attributesList = file.getAttributesList(); - Platform.runLater(() -> { - imageView.setImage(icon); - tableView.getItems().setAll(attributesList); + Platform.runLater(() -> { + imageView.setImage(icon); + tableView.getItems().setAll(attributesList); + }); + + updateCategoryBorder(); }); - updateCategoryBorder(); } @Override @@ -226,23 +241,28 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @Subscribe @Override public void handleCategoryChanged(CategoryChangeEvent evt) { - if (getFile() != null && evt.getFileIDs().contains(getFileID())) { - updateUI(); - } + getFileID().ifPresent(fileID -> { + if (evt.getFileIDs().contains(fileID)) { + updateUI(); + } + }); } @Override public void handleTagAdded(ContentTagAddedEvent evt) { - if (getFile() != null && evt.getAddedTag().getContent().getId() == getFileID()) { - updateUI(); - } + handleTagChanged(evt.getAddedTag().getContent().getId()); } @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - if (getFile() != null && evt.getDeletedTag().getContent().getId() == getFileID()) { - updateUI(); - } + handleTagChanged(evt.getDeletedTag().getContent().getId()); } + private void handleTagChanged(Long tagFileID) { + getFileID().ifPresent(fileID -> { + if (Objects.equals(tagFileID, fileID)) { + updateUI(); + } + }); + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index 7977eb0219..ab74554b39 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.imagegallery.gui; import java.util.ArrayList; +import java.util.function.Function; import java.util.logging.Level; import javafx.application.Platform; import javafx.beans.Observable; @@ -48,14 +49,15 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.ImageFile; import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile; +import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.CAT_BORDER_WIDTH; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.HASH_BORDER; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.getCategoryBorder; import org.sleuthkit.datamodel.TagName; @@ -235,9 +237,9 @@ public class SlideShowView extends DrawableViewBase { @Override synchronized public void setFile(final Long fileID) { super.setFile(fileID); - if (this.getFileID() != null) { - getGroupPane().makeSelection(false, this.getFileID()); - } + getFileID().ifPresent((Long id) -> { + getGroupPane().makeSelection(false, id); + }); } @Override @@ -254,24 +256,33 @@ public class SlideShowView extends DrawableViewBase { @Override protected Runnable getContentUpdateRunnable() { - if (getFile().isVideo()) { - return () -> { - imageBorder.setCenter(MediaControl.create((VideoFile) getFile())); - }; - } else { - ImageView imageView = new ImageView(((ImageFile) getFile()).getFullSizeImage()); - imageView.setPreserveRatio(true); - imageView.fitWidthProperty().bind(imageBorder.widthProperty().subtract(CAT_BORDER_WIDTH * 2)); - imageView.fitHeightProperty().bind(this.heightProperty().subtract(CAT_BORDER_WIDTH * 4).subtract(footer.heightProperty()).subtract(toolBar.heightProperty())); - return () -> { - imageBorder.setCenter(imageView); - }; - } + + return getFile().map(new Function, Runnable>() { + + @Override + public Runnable apply(DrawableFile file) { + + if (file.isVideo()) { + return () -> { + imageBorder.setCenter(MediaControl.create((VideoFile) file)); + }; + } else { + ImageView imageView = new ImageView(((ImageFile) file).getFullSizeImage()); + imageView.setPreserveRatio(true); + imageView.fitWidthProperty().bind(imageBorder.widthProperty().subtract(CAT_BORDER_WIDTH * 2)); + imageView.fitHeightProperty().bind(heightProperty().subtract(CAT_BORDER_WIDTH * 4).subtract(footer.heightProperty()).subtract(toolBar.heightProperty())); + return () -> { + imageBorder.setCenter(imageView); + }; + } + } + }).orElse(() -> { + }); } @Override protected String getTextForLabel() { - return getFile().getName() + " " + getSupplementalText(); + return getFile().map(file -> file.getName() + " " + getSupplementalText()).orElse(""); } @ThreadConfined(type = ThreadType.JFX) @@ -302,18 +313,19 @@ public class SlideShowView extends DrawableViewBase { @Override @ThreadConfined(type = ThreadType.ANY) public Category updateCategoryBorder() { - final Category category = getFile().getCategory(); - final Border border = hasHashHit() && (category == Category.ZERO) - ? HASH_BORDER - : getCategoryBorder(category); - ToggleButton toggleForCategory = getToggleForCategory(category); + return getFile().map(file -> { + final Category category = file.getCategory(); + final Border border1 = hasHashHit() && (category == Category.ZERO) + ? HASH_BORDER + : getCategoryBorder(category); + ToggleButton toggleForCategory = getToggleForCategory(category); + Platform.runLater(() -> { + getCategoryBorderRegion().setBorder(border1); + toggleForCategory.setSelected(true); + }); + return category; + }).orElse(Category.ZERO); - Platform.runLater(() -> { - getCategoryBorderRegion().setBorder(border); - toggleForCategory.setSelected(true); - }); - - return category; } private ToggleButton getToggleForCategory(Category category) { @@ -345,10 +357,13 @@ public class SlideShowView extends DrawableViewBase { @Override public void changed(ObservableValue ov, Boolean t, Boolean t1) { - if (t1) { - FileIDSelectionModel.getInstance().clearAndSelect(getFileID()); - new CategorizeAction(getController()).addTag(getController().getTagsManager().getTagName(cat), ""); - } + getFileID().ifPresent(fileID -> { + if (t1) { + FileIDSelectionModel.getInstance().clearAndSelect(fileID); + new CategorizeAction(getController()).addTag(getController().getTagsManager().getTagName(cat), ""); + } + }); + } } } From ff11258e9c750213fb897a29ddc8c63db1f9572f Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 13:33:07 -0400 Subject: [PATCH 110/198] fix bugs updating tags/categpries in slideshowview and metadata pane make new abstract base calss DrawableUIBase and move fileid and file object access to it. --- .../actions/DeleteFollowUpTagAction.java | 2 - .../datamodel/CategoryManager.java | 4 +- .../imagegallery/gui/DrawableTile.java | 7 +- ...bleViewBase.java => DrawableTileBase.java} | 121 +++++------------- .../imagegallery/gui/DrawableUIBase.java | 97 ++++++++++++++ .../imagegallery/gui/DrawableView.java | 18 +-- .../imagegallery/gui/MetaDataPane.java | 70 ++-------- .../imagegallery/gui/SlideShowView.java | 23 ++-- 8 files changed, 161 insertions(+), 181 deletions(-) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{DrawableViewBase.java => DrawableTileBase.java} (79%) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 74082fcd1c..934a3fb258 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -37,11 +37,9 @@ import org.sleuthkit.datamodel.TskCoreException; public class DeleteFollowUpTagAction extends Action { private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTagAction.class.getName()); - private final long fileID; public DeleteFollowUpTagAction(final ImageGalleryController controller, final DrawableFile file) { super("Delete Follow Up Tag"); - this.fileID = file.getId(); setEventHandler((ActionEvent t) -> { new SwingWorker() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 466278f588..4d2591aa1e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -251,7 +251,7 @@ public class CategoryManager { incrementCategoryCount(newCat); } - fireChange(Collections.singleton(addedTag.getId()), newCat); + fireChange(Collections.singleton(addedTag.getContent().getId()), newCat); } } @Subscribe @@ -263,7 +263,7 @@ public class CategoryManager { if (deletedCat != Category.ZERO) { decrementCategoryCount(deletedCat); } - fireChange(Collections.singleton(deleted.getId()), null); + fireChange(Collections.singleton(deleted.getContent().getId()), null); } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java index 96f05dd9c1..86a0b2ddee 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java @@ -32,7 +32,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableViewBase.globalSelectionModel; +import static org.sleuthkit.autopsy.imagegallery.gui.DrawableTileBase.globalSelectionModel; import org.sleuthkit.datamodel.AbstractContent; /** @@ -43,7 +43,7 @@ import org.sleuthkit.datamodel.AbstractContent; * * TODO: refactor this to extend from {@link Control}? -jm */ -public class DrawableTile extends DrawableViewBase { +public class DrawableTile extends DrawableTileBase { private static final DropShadow LAST_SELECTED_EFFECT = new DropShadow(10, Color.BLUE); @@ -67,7 +67,6 @@ public class DrawableTile extends DrawableViewBase { assert imageBorder != null : "fx:id=\"imageAnchor\" was not injected: check your FXML file 'DrawableTile.fxml'."; assert imageView != null : "fx:id=\"imageView\" was not injected: check your FXML file 'DrawableTile.fxml'."; assert nameLabel != null : "fx:id=\"nameLabel\" was not injected: check your FXML file 'DrawableTile.fxml'."; - //set up properties and binding setCache(true); setCacheHint(CacheHint.SPEED); @@ -87,9 +86,11 @@ public class DrawableTile extends DrawableViewBase { public DrawableTile(GroupPane gp) { super(gp); + FXMLConstructor.construct(this, "DrawableTile.fxml"); } + @Override @ThreadConfined(type = ThreadType.JFX) protected void clearContent() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java similarity index 79% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java index a1ee32a108..80c73b1ae9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java @@ -22,8 +22,6 @@ package org.sleuthkit.autopsy.imagegallery.gui; import com.google.common.eventbus.Subscribe; import java.util.ArrayList; import java.util.Collection; -import java.util.Objects; -import static java.util.Objects.nonNull; import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; @@ -39,7 +37,6 @@ import javafx.scene.control.Tooltip; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; -import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Border; import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderStroke; @@ -66,13 +63,11 @@ import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.TagName; @@ -84,9 +79,9 @@ import org.sleuthkit.datamodel.TskCoreException; * of {@link DrawableView}s should implement the interface directly * */ -public abstract class DrawableViewBase extends AnchorPane implements DrawableView { +public abstract class DrawableTileBase extends DrawableUIBase { - private static final Logger LOGGER = Logger.getLogger(DrawableViewBase.class.getName()); + private static final Logger LOGGER = Logger.getLogger(DrawableTileBase.class.getName()); private static final Border UNSELECTED_BORDER = new Border(new BorderStroke(Color.GRAY, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3))); @@ -99,6 +94,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie protected static final Image followUpGray = new Image("org/sleuthkit/autopsy/imagegallery/images/flag_gray.png"); protected static final FileIDSelectionModel globalSelectionModel = FileIDSelectionModel.getInstance(); + private static ContextMenu contextMenu; /** * displays the icon representing video files @@ -130,50 +126,16 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @FXML protected BorderPane imageBorder; - static private ContextMenu contextMenu; - - volatile private Optional> fileOpt = Optional.empty(); - - volatile private Optional fileIDOpt = Optional.empty(); - - @Override - public Optional getFileID() { - return fileIDOpt; - } - - @Override - public Optional> getFile() { - if (fileIDOpt.isPresent()) { - if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { - return fileOpt; - } else { - try { - fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); - } catch (TskCoreException ex) { - Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); - fileOpt = Optional.empty(); - } - return fileOpt; - } - } else { - return Optional.empty(); - } - } - /** - * the groupPane this {@link DrawableViewBase} is embedded in + * the groupPane this {@link DrawableTileBase} is embedded in */ final private GroupPane groupPane; - private boolean registered = false; - private final ImageGalleryController controller; + volatile private boolean registered = false; - GroupPane getGroupPane() { - return groupPane; - } + protected DrawableTileBase(GroupPane groupPane) { + super(groupPane.getController()); - protected DrawableViewBase(GroupPane groupPane) { this.groupPane = groupPane; - this.controller = groupPane.getController(); globalSelectionModel.getSelected().addListener((Observable observable) -> { updateSelectionState(); }); @@ -213,7 +175,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie groupContextMenu.hide(); } contextMenu = buildContextMenu(file); - contextMenu.show(DrawableViewBase.this, t.getScreenX(), t.getScreenY()); + contextMenu.show(DrawableTileBase.this, t.getScreenX(), t.getScreenY()); break; } }); @@ -224,9 +186,9 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie private ContextMenu buildContextMenu(DrawableFile file) { final ArrayList menuItems = new ArrayList<>(); - menuItems.add(new CategorizeAction(controller).getPopupMenu()); + menuItems.add(new CategorizeAction(getController()).getPopupMenu()); - menuItems.add(new AddDrawableTagAction(controller).getPopupMenu()); + menuItems.add(new AddDrawableTagAction(getController()).getPopupMenu()); final MenuItem extractMenuItem = new MenuItem("Extract File(s)"); extractMenuItem.setOnAction((ActionEvent t) -> { @@ -274,6 +236,10 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie }); } + GroupPane getGroupPane() { + return groupPane; + } + @ThreadConfined(type = ThreadType.UI) protected abstract void clearContent(); @@ -283,31 +249,29 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie protected abstract String getTextForLabel(); - @SuppressWarnings("deprecation") protected void initialize() { followUpToggle.setOnAction((ActionEvent event) -> { getFile().ifPresent(file -> { if (followUpToggle.isSelected() == true) { try { - final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); globalSelectionModel.clearAndSelect(file.getId()); - new AddDrawableTagAction(controller).addTag(followUpTagName, ""); + new AddDrawableTagAction(getController()).addTag(getController().getTagsManager().getFollowUpTagName(), ""); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); } } else { - new DeleteFollowUpTagAction(controller, file).handle(event); + new DeleteFollowUpTagAction(getController(), file).handle(event); } }); }); } protected boolean hasFollowUp() { - if (getFile().isPresent()) { + if (getFileID().isPresent()) { try { TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); - Collection tagNames = DrawableAttribute.TAGS.getValue(getFile().get()); - return tagNames.stream().anyMatch((tn) -> tn.equals(followUpTagName)); + return DrawableAttribute.TAGS.getValue(getFile().get()).stream() + .anyMatch(followUpTagName::equals); } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "failed to get follow up tag name ", ex); return true; @@ -318,29 +282,17 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie } @Override - public void setFile(final Long newFileID) { - if (fileIDOpt.isPresent()) { - if (Objects.equals(newFileID, fileIDOpt.get()) == false) { - setFileHelper(newFileID); - } - } else { - if (nonNull(newFileID)) { - setFileHelper(newFileID); - } - } - } - - private void setFileHelper(final Long newFileID) { - fileIDOpt = Optional.ofNullable(newFileID); + protected void setFileHelper(final Long newFileID) { + setFileIDOpt(Optional.ofNullable(newFileID)); disposeContent(); - if (fileIDOpt.isPresent() == false || Case.isCaseOpen() == false) { + if (getFileID().isPresent() == false || Case.isCaseOpen() == false) { if (registered == true) { getController().getCategoryManager().unregisterListener(this); getController().getTagsManager().unregisterListener(this); registered = false; } - fileOpt = Optional.empty(); + setFileOpt(Optional.empty()); Platform.runLater(() -> { clearContent(); }); @@ -350,10 +302,10 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie getController().getTagsManager().registerListener(this); registered = true; } - fileOpt = Optional.empty(); + setFileOpt(Optional.empty()); updateSelectionState(); - updateCategoryBorder(); + updateCategory(); updateFollowUpIcon(); updateUI(); Platform.runLater(getContentUpdateRunnable()); @@ -397,10 +349,10 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { - fileIDOpt.ifPresent(fileID -> { + getFileID().ifPresent(fileID -> { try { if (fileID == evt.getAddedTag().getContent().getId() - && evt.getAddedTag().getName() == getController().getTagsManager().getFollowUpTagName()) { + && evt.getAddedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { Platform.runLater(() -> { followUpImageView.setImage(followUpIcon); @@ -417,10 +369,10 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - fileIDOpt.ifPresent(fileID -> { + getFileID().ifPresent(fileID -> { try { if (fileID == evt.getDeletedTag().getContent().getId() - && evt.getDeletedTag().getName() == controller.getTagsManager().getFollowUpTagName()) { + && evt.getDeletedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { updateFollowUpIcon(); } } catch (TskCoreException ex) { @@ -436,19 +388,4 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie followUpToggle.setSelected(hasFollowUp); }); } - - @Subscribe - @Override - public void handleCategoryChanged(CategoryChangeEvent evt) { - fileIDOpt.ifPresent(fileID -> { - if (evt.getFileIDs().contains(fileID)) { - updateCategoryBorder(); - } - }); - } - - @Override - public ImageGalleryController getController() { - return controller; - } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java new file mode 100644 index 0000000000..ec794eabae --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java @@ -0,0 +1,97 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery.gui; + +import java.util.Objects; +import static java.util.Objects.nonNull; +import java.util.Optional; +import java.util.logging.Level; +import javafx.scene.layout.AnchorPane; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * + */ +abstract public class DrawableUIBase extends AnchorPane implements DrawableView { + + private final ImageGalleryController controller; + + volatile private Optional> fileOpt = Optional.empty(); + + volatile private Optional fileIDOpt = Optional.empty(); + + public DrawableUIBase(ImageGalleryController controller) { + this.controller = controller; + } + + @Override + public ImageGalleryController getController() { + return controller; + } + + @Override + public Optional getFileID() { + return fileIDOpt; + } + + void setFileIDOpt(Optional fileIDOpt) { + this.fileIDOpt = fileIDOpt; + } + + void setFileOpt(Optional> fileOpt) { + this.fileOpt = fileOpt; + } + + @Override + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + try { + fileOpt = Optional.of(getController().getFileFromId(fileIDOpt.get())); + } catch (TskCoreException ex) { + Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); + fileOpt = Optional.empty(); + } + return fileOpt; + } + } else { + return Optional.empty(); + } + } + + protected abstract void setFileHelper(Long newFileID); + + @Override + public void setFile(Long newFileID) { + if (getFileID().isPresent()) { + if (Objects.equals(newFileID, getFileID().get()) == false) { + setFileHelper(newFileID); + } + } else if (nonNull(newFileID)) { + setFileHelper(newFileID); + } + } + + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index e4e6faf1de..709679173e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -68,7 +68,13 @@ public interface DrawableView { * @param evt the CategoryChangeEvent to handle */ @Subscribe - void handleCategoryChanged(CategoryChangeEvent evt); + default void handleCategoryChanged(CategoryChangeEvent evt) { + getFileID().ifPresent(fileID -> { + if (evt.getFileIDs().contains(fileID)) { + updateCategory(); + } + }); + } @Subscribe void handleTagAdded(ContentTagAddedEvent evt); @@ -116,16 +122,12 @@ public interface DrawableView { } @ThreadConfined(type = ThreadConfined.ThreadType.ANY) - default Category updateCategoryBorder() { - if (getFile() != null) { + default Category updateCategory() { + if (getFile().isPresent()) { final Category category = getFile().map(DrawableFile::getCategory).orElse(Category.ZERO); - final Border border = hasHashHit() && (category == Category.ZERO) - ? HASH_BORDER - : getCategoryBorder(category); - + final Border border = hasHashHit() && (category == Category.ZERO) ? HASH_BORDER : getCategoryBorder(category); Platform.runLater(() -> { getCategoryBorderRegion().setBorder(border); - getCategoryBorderRegion().requestLayout(); }); return category; } else { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index 87bd64491f..d89db4116c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -23,9 +23,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.Objects; -import static java.util.Objects.nonNull; import java.util.Optional; -import java.util.logging.Level; import java.util.stream.Collectors; import javafx.application.Platform; import javafx.beans.property.SimpleObjectProperty; @@ -39,7 +37,6 @@ import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.image.Image; import javafx.scene.image.ImageView; -import javafx.scene.layout.AnchorPane; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Region; import static javafx.scene.layout.Region.USE_COMPUTED_SIZE; @@ -53,24 +50,15 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; /** * Shows details of the selected file. */ -public class MetaDataPane extends AnchorPane implements DrawableView { +public class MetaDataPane extends DrawableUIBase { private static final Logger LOGGER = Logger.getLogger(MetaDataPane.class.getName()); - private final ImageGalleryController controller; - - @Override - public ImageGalleryController getController() { - return controller; - } - @FXML private ImageView imageView; @@ -141,56 +129,14 @@ public class MetaDataPane extends AnchorPane implements DrawableView { tableView.getColumns().setAll(Arrays.asList(attributeColumn, valueColumn)); //listen for selection change - controller.getSelectionModel().lastSelectedProperty().addListener((observable, oldFileID, newFileID) -> { + getController().getSelectionModel().lastSelectedProperty().addListener((observable, oldFileID, newFileID) -> { setFile(newFileID); }); } - volatile private Optional> fileOpt = Optional.empty(); - - volatile private Optional fileIDOpt = Optional.empty(); - @Override - public Optional getFileID() { - return fileIDOpt; - } - - @Override - public Optional> getFile() { - if (fileIDOpt.isPresent()) { - if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { - return fileOpt; - } else { - try { - fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); - } catch (TskCoreException ex) { - Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); - fileOpt = Optional.empty(); - } - return fileOpt; - } - } else { - return Optional.empty(); - } - } - - @Override - public void setFile(Long newFileID) { - - if (fileIDOpt.isPresent()) { - if (Objects.equals(newFileID, fileIDOpt.get()) == false) { - setFileHelper(newFileID); - } - } else { - if (nonNull(newFileID)) { - setFileHelper(newFileID); - } - } - setFileHelper(newFileID); - } - - private void setFileHelper(Long newFileID) { - fileIDOpt = Optional.of(newFileID); + synchronized protected void setFileHelper(Long newFileID) { + setFileIDOpt(Optional.ofNullable(newFileID)); if (newFileID == null) { Platform.runLater(() -> { imageView.setImage(null); @@ -204,7 +150,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { } public MetaDataPane(ImageGalleryController controller) { - this.controller = controller; + super(controller); FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MetaDataPane.fxml")); fxmlLoader.setRoot(this); @@ -224,12 +170,12 @@ public class MetaDataPane extends AnchorPane implements DrawableView { Platform.runLater(() -> { imageView.setImage(icon); + tableView.getItems().clear(); tableView.getItems().setAll(attributesList); }); - updateCategoryBorder(); + updateCategory(); }); - } @Override @@ -248,11 +194,13 @@ public class MetaDataPane extends AnchorPane implements DrawableView { }); } + @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { handleTagChanged(evt.getAddedTag().getContent().getId()); } + @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { handleTagChanged(evt.getDeletedTag().getContent().getId()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index ab74554b39..99944d6d19 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -58,8 +58,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.ImageFile; import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.CAT_BORDER_WIDTH; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.HASH_BORDER; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.getCategoryBorder; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -68,7 +66,7 @@ import org.sleuthkit.datamodel.TskCoreException; * GroupPane. TODO: Extract a subclass for video files in slideshow mode-jm * TODO: reduce coupling to GroupPane */ -public class SlideShowView extends DrawableViewBase { +public class SlideShowView extends DrawableTileBase { private static final Logger LOGGER = Logger.getLogger(SlideShowView.class.getName()); @@ -223,6 +221,7 @@ public class SlideShowView extends DrawableViewBase { SlideShowView(GroupPane gp) { super(gp); + FXMLConstructor.construct(this, "SlideShow.fxml"); } @@ -237,6 +236,7 @@ public class SlideShowView extends DrawableViewBase { @Override synchronized public void setFile(final Long fileID) { super.setFile(fileID); + getFileID().ifPresent((Long id) -> { getGroupPane().makeSelection(false, id); }); @@ -288,7 +288,7 @@ public class SlideShowView extends DrawableViewBase { @ThreadConfined(type = ThreadType.JFX) private void cycleSlideShowImage(int d) { stopVideo(); - if (getFileID() != null) { + if (getFileID().isPresent()) { int index = getGroupPane().getGrouping().fileIds().indexOf(getFileID()); final int size = getGroupPane().getGrouping().fileIds().size(); index = (index + d) % size; @@ -312,20 +312,17 @@ public class SlideShowView extends DrawableViewBase { @Override @ThreadConfined(type = ThreadType.ANY) - public Category updateCategoryBorder() { - return getFile().map(file -> { - final Category category = file.getCategory(); - final Border border1 = hasHashHit() && (category == Category.ZERO) - ? HASH_BORDER - : getCategoryBorder(category); + public Category updateCategory() { + if (getFile().isPresent()) { + final Category category = super.updateCategory(); ToggleButton toggleForCategory = getToggleForCategory(category); Platform.runLater(() -> { - getCategoryBorderRegion().setBorder(border1); toggleForCategory.setSelected(true); }); return category; - }).orElse(Category.ZERO); - + } else { + return Category.ZERO; + } } private ToggleButton getToggleForCategory(Category category) { From 68d28db500b45881e2ee7cea98b95b8ec626b20a Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 14:11:44 -0400 Subject: [PATCH 111/198] rename method in CategoryManager to be more descriptive; fix tag and category grouping when tags aer added / removed --- .../datamodel/CategoryManager.java | 6 ++-- .../imagegallery/grouping/GroupManager.java | 35 +++++++++++-------- .../imagegallery/gui/SlideShowView.java | 28 +++++++-------- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 4d2591aa1e..3a1a81e72d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -211,7 +211,7 @@ public class CategoryManager { } - public static Category fromTagName(TagName tagName) { + public static Category categoryFromTagName(TagName tagName) { return Category.fromDisplayName(tagName.getDisplayName()); } @@ -246,7 +246,7 @@ public class CategoryManager { } catch (TskCoreException tskException) { LOGGER.log(Level.SEVERE, "Failed to get content tags for content. Unable to maintain category in a consistent state.", tskException); } - Category newCat = CategoryManager.fromTagName(addedTag.getName()); + Category newCat = CategoryManager.categoryFromTagName(addedTag.getName()); if (newCat != Category.ZERO) { incrementCategoryCount(newCat); } @@ -259,7 +259,7 @@ public class CategoryManager { ContentTag deleted = event.getDeletedTag(); if (isCategoryTagName(deleted.getName())) { - Category deletedCat = CategoryManager.fromTagName(deleted.getName()); + Category deletedCat = CategoryManager.categoryFromTagName(deleted.getName()); if (deletedCat != Category.ZERO) { decrementCategoryCount(deletedCat); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 9ac899742c..90adfa76b8 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -539,20 +539,25 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { - if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); - final long fileID = evt.getAddedTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); + GroupKey groupKey = null; + if (groupBy == DrawableAttribute.TAGS) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + } else if (groupBy == DrawableAttribute.CATEGORY) { + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getAddedTag().getName())); } + final long fileID = evt.getAddedTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); } + @SuppressWarnings("AssignmentToMethodParameter") private void addFileToGroup(DrawableGroup g, final GroupKey groupKey, final long fileID) { if (g == null) { //if there wasn't already a group check if there should be one now - popuplateIfAnalyzed(groupKey, null); - } else { + g = popuplateIfAnalyzed(groupKey, null); + } + if (g != null) { //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. g.addFile(fileID); } @@ -560,11 +565,14 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagDeleted(ContentTagDeletedEvent evt) { - if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); - final long fileID = evt.getDeletedTag().getContent().getId(); - DrawableGroup g = removeFromGroup(groupKey, fileID); + GroupKey groupKey = null; + if (groupBy == DrawableAttribute.TAGS) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); + } else if (groupBy == DrawableAttribute.CATEGORY) { + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getDeletedTag().getName())); } + final long fileID = evt.getDeletedTag().getContent().getId(); + DrawableGroup g = removeFromGroup(groupKey, fileID); } @Override @@ -631,7 +639,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { /* for attributes other than path we can't be sure a group is * fully analyzed because we don't know all the files that - * will be a part of that group */ + * will be a part of that group,. just show them no matter what. */ try { Set fileIDs = getFileIDsInGroup(groupKey); @@ -643,9 +651,8 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { group = groupMap.get(groupKey); group.setFiles(ObjectUtils.defaultIfNull(fileIDs, Collections.emptySet())); } else { - group = new DrawableGroup(groupKey, fileIDs, groupSeen); - group.seenProperty().addListener((observable, oldSeen, newSeen) -> { + group.seenProperty().addListener((o, oldSeen, newSeen) -> { markGroupSeen(group, newSeen); }); groupMap.put(groupKey, group); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index 99944d6d19..d7d0f684ed 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -25,6 +25,7 @@ import javafx.application.Platform; import javafx.beans.Observable; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; +import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; @@ -282,24 +283,20 @@ public class SlideShowView extends DrawableTileBase { @Override protected String getTextForLabel() { - return getFile().map(file -> file.getName() + " " + getSupplementalText()).orElse(""); + return getFile().map(file -> file.getName()).orElse("") + " " + getSupplementalText(); } @ThreadConfined(type = ThreadType.JFX) - private void cycleSlideShowImage(int d) { + private void cycleSlideShowImage(int direction) { stopVideo(); - if (getFileID().isPresent()) { - int index = getGroupPane().getGrouping().fileIds().indexOf(getFileID()); - final int size = getGroupPane().getGrouping().fileIds().size(); - index = (index + d) % size; - if (index < 0) { - index += size; - } - setFile(getGroupPane().getGrouping().fileIds().get(index)); + final int groupSize = getGroupPane().getGrouping().fileIds().size(); + final Integer nextIndex = getFileID().map(fileID -> { + final int currentIndex = getGroupPane().getGrouping().fileIds().indexOf(fileID); + return (currentIndex + direction + groupSize) % groupSize; + }).orElse(0); + setFile(getGroupPane().getGrouping().fileIds().get(nextIndex) + ); - } else { - setFile(getGroupPane().getGrouping().fileIds().get(0)); - } } /** @@ -307,7 +304,10 @@ public class SlideShowView extends DrawableTileBase { * of y" */ private String getSupplementalText() { - return " ( " + (getGroupPane().getGrouping().fileIds().indexOf(getFileID()) + 1) + " of " + getGroupPane().getGrouping().fileIds().size() + " in group )"; + final ObservableList fileIds = getGroupPane().getGrouping().fileIds(); + return getFileID().map(fileID -> " ( " + (fileIds.indexOf(fileID) + 1) + " of " + fileIds.size() + " in group )") + .orElse(""); + } @Override From 7dfc17268e07391e1491b0f361951cd21e0ac695 Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 10:22:18 -0400 Subject: [PATCH 112/198] Tag Events - created new Case.Event enum values for BlackBoard/Content tags added/deleted - created new PropertyChangeEvent subclasses for BlackBoard/Content tags added/deleted - replaced ModuleDataEvent hack with new Tag Events - removed [in] from javadocs, other minor cleanup --- .../autopsy/events/AutopsyEvent.java | 19 ++++++++++++++ .../autopsy/events/TagAddedEvent.java | 6 ++--- .../autopsy/events/TagDeletedEvent.java | 6 ++--- .../sleuthkit/autopsy/events/TagEvent.java | 26 +++++++++++++++++++ 4 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/events/AutopsyEvent.java create mode 100644 Core/src/org/sleuthkit/autopsy/events/TagEvent.java diff --git a/Core/src/org/sleuthkit/autopsy/events/AutopsyEvent.java b/Core/src/org/sleuthkit/autopsy/events/AutopsyEvent.java new file mode 100644 index 0000000000..fdaf727867 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/AutopsyEvent.java @@ -0,0 +1,19 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.events; + +import java.beans.PropertyChangeEvent; + +/** + * This is a place holder class to be overwritten by the version in the + * Collaborative branch. + */ +abstract class AutopsyEvent extends PropertyChangeEvent { + + AutopsyEvent(Object source, String propertyName, Object oldValue, Object newValue) { + super(source, propertyName, oldValue, newValue); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java b/Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java index b9acb256bb..217af496cc 100644 --- a/Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java +++ b/Core/src/org/sleuthkit/autopsy/events/TagAddedEvent.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.events; -import java.beans.PropertyChangeEvent; import javax.annotation.concurrent.Immutable; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.datamodel.Tag; @@ -27,7 +26,7 @@ import org.sleuthkit.datamodel.Tag; * Base Class for events that are fired when a Tag is added */ @Immutable -abstract class TagAddedEvent extends PropertyChangeEvent { +abstract class TagAddedEvent extends TagEvent { protected TagAddedEvent(String propertyName, T newValue) { super(Case.class, propertyName, null, newValue); @@ -39,7 +38,8 @@ abstract class TagAddedEvent extends PropertyChangeEvent { * @return the tTag */ @SuppressWarnings("unchecked") - public T getAddedTag() { + @Override + public T getTag() { return (T) getNewValue(); } diff --git a/Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java b/Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java index 7d0cfca18e..6a0a1c5668 100644 --- a/Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java +++ b/Core/src/org/sleuthkit/autopsy/events/TagDeletedEvent.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.events; -import java.beans.PropertyChangeEvent; import javax.annotation.concurrent.Immutable; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.datamodel.Tag; @@ -27,7 +26,7 @@ import org.sleuthkit.datamodel.Tag; * Base Class for events that are fired when a Tag is deleted */ @Immutable -abstract class TagDeletedEvent extends PropertyChangeEvent { +abstract class TagDeletedEvent extends TagEvent { protected TagDeletedEvent(String propertyName, T oldValue) { super(Case.class, propertyName, oldValue, null); @@ -39,7 +38,8 @@ abstract class TagDeletedEvent extends PropertyChangeEvent { * @return the Tag */ @SuppressWarnings("unchecked") - public T getDeletedTag() { + @Override + public T getTag() { return (T) getOldValue(); } } diff --git a/Core/src/org/sleuthkit/autopsy/events/TagEvent.java b/Core/src/org/sleuthkit/autopsy/events/TagEvent.java new file mode 100644 index 0000000000..b80725782d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/events/TagEvent.java @@ -0,0 +1,26 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.events; + +import org.sleuthkit.datamodel.Tag; + +/** + * + */ +abstract public class TagEvent extends AutopsyEvent { + + public TagEvent(Object source, String propertyName, Object oldValue, Object newValue) { + super(source, propertyName, oldValue, newValue); + } + + /** + * get the Tag that this event is for + * + * @return the Tag + */ + public abstract T getTag(); + +} From ab8e68435da49c62daffef14ac5c6ce4646e44a9 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:11:16 -0400 Subject: [PATCH 113/198] reduce duplicate code --- .../imagegallery/ImageGalleryController.java | 4 +-- .../datamodel/CategoryManager.java | 4 +-- .../imagegallery/grouping/GroupManager.java | 12 +++---- .../imagegallery/gui/DrawableTileBase.java | 34 ++++++++++--------- .../imagegallery/gui/MetaDataPane.java | 17 +++++++--- 5 files changed, 40 insertions(+), 31 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 6c6bd7c789..d81ff29938 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -491,13 +491,13 @@ public final class ImageGalleryController { break; case CONTENT_TAG_ADDED: final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt; - if (getDatabase().isInDB((tagAddedEvent).getAddedTag().getContent().getId())) { + if (getDatabase().isInDB((tagAddedEvent).getTag().getContent().getId())) { getTagsManager().fireTagAddedEvent(tagAddedEvent); } break; case CONTENT_TAG_DELETED: final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) evt; - if (getDatabase().isInDB((tagDeletedEvent).getDeletedTag().getContent().getId())) { + if (getDatabase().isInDB((tagDeletedEvent).getTag().getContent().getId())) { getTagsManager().fireTagDeletedEvent(tagDeletedEvent); } break; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 3a1a81e72d..309173f153 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -226,7 +226,7 @@ public class CategoryManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent event) { - ContentTag addedTag = event.getAddedTag(); + ContentTag addedTag = event.getTag(); if (isCategoryTagName(addedTag.getName())) { final DrawableTagsManager tagsManager = controller.getTagsManager(); try { @@ -256,7 +256,7 @@ public class CategoryManager { } @Subscribe public void handleTagDeleted(ContentTagDeletedEvent event) { - ContentTag deleted = event.getDeletedTag(); + ContentTag deleted = event.getTag(); if (isCategoryTagName(deleted.getName())) { Category deletedCat = CategoryManager.categoryFromTagName(deleted.getName()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 90adfa76b8..d7819c6d5e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -541,11 +541,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public void handleTagAdded(ContentTagAddedEvent evt) { GroupKey groupKey = null; if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } else if (groupBy == DrawableAttribute.CATEGORY) { - groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getAddedTag().getName())); + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); } - final long fileID = evt.getAddedTag().getContent().getId(); + final long fileID = evt.getTag().getContent().getId(); DrawableGroup g = getGroupForKey(groupKey); addFileToGroup(g, groupKey, fileID); @@ -567,11 +567,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public void handleTagDeleted(ContentTagDeletedEvent evt) { GroupKey groupKey = null; if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } else if (groupBy == DrawableAttribute.CATEGORY) { - groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getDeletedTag().getName())); + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); } - final long fileID = evt.getDeletedTag().getContent().getId(); + final long fileID = evt.getTag().getContent().getId(); DrawableGroup g = removeFromGroup(groupKey, fileID); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java index 80c73b1ae9..428bd0b5f4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java @@ -62,6 +62,7 @@ import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.events.TagEvent; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; @@ -70,6 +71,7 @@ import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -349,36 +351,36 @@ public abstract class DrawableTileBase extends DrawableUIBase { @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { - getFileID().ifPresent(fileID -> { - try { - if (fileID == evt.getAddedTag().getContent().getId() - && evt.getAddedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { - Platform.runLater(() -> { - followUpImageView.setImage(followUpIcon); - followUpToggle.setSelected(true); - }); - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); - } + handleTagEvent(evt, () -> { + Platform.runLater(() -> { + followUpImageView.setImage(followUpIcon); + followUpToggle.setSelected(true); + }); }); } @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { + handleTagEvent(evt, this::updateFollowUpIcon); + } + void handleTagEvent(TagEvent evt, Runnable runnable) { getFileID().ifPresent(fileID -> { try { - if (fileID == evt.getDeletedTag().getContent().getId() - && evt.getDeletedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { - updateFollowUpIcon(); + final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); + final ContentTag deletedTag = evt.getTag(); + + if (fileID == deletedTag.getContent().getId() + && deletedTag.getName().equals(followUpTagName)) { + runnable.run(); } } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + LOGGER.log(Level.SEVERE, "Failed to get followup tag name. Unable to update follow up status for file. ", ex); } }); + } private void updateFollowUpIcon() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index d89db4116c..780513d16a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -46,10 +46,12 @@ import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.events.TagEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; /** @@ -197,19 +199,24 @@ public class MetaDataPane extends DrawableUIBase { @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { - handleTagChanged(evt.getAddedTag().getContent().getId()); + handleTagEvent(evt, this::updateUI); } @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - handleTagChanged(evt.getDeletedTag().getContent().getId()); + handleTagEvent(evt, this::updateUI); } - private void handleTagChanged(Long tagFileID) { + /** + * + * @param tagFileID the value of tagEvent + * @param runnable the value of runnable + */ + void handleTagEvent(TagEvent tagEvent, final Runnable runnable) { getFileID().ifPresent(fileID -> { - if (Objects.equals(tagFileID, fileID)) { - updateUI(); + if (Objects.equals(tagEvent.getTag().getContent().getId(), fileID)) { + runnable.run(); } }); } From 8918bea329fe49caed88e2f35f692ad6b60ccfee Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:22:14 -0400 Subject: [PATCH 114/198] move DrawableView and GroupPane to a new package --- .../ImageGalleryTopComponent.java | 4 +- .../autopsy/imagegallery/gui/GroupView.java | 8 --- .../gui/{ => drawableviews}/DrawableTile.fxml | 0 .../gui/{ => drawableviews}/DrawableTile.java | 5 +- .../{ => drawableviews}/DrawableTileBase.java | 2 +- .../{ => drawableviews}/DrawableUIBase.java | 2 +- .../gui/{ => drawableviews}/DrawableView.java | 2 +- .../gui/{ => drawableviews}/GroupPane.fxml | 0 .../gui/{ => drawableviews}/GroupPane.java | 6 +- .../gui/{ => drawableviews}/MetaDataPane.fxml | 0 .../gui/{ => drawableviews}/MetaDataPane.java | 32 +++++----- .../gui/{ => drawableviews}/SlideShow.fxml | 0 .../{ => drawableviews}/SlideShowView.java | 63 ++++++++++--------- 13 files changed, 62 insertions(+), 62 deletions(-) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupView.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableTile.fxml (100%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableTile.java (95%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableTileBase.java (99%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableUIBase.java (97%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableView.java (98%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/GroupPane.fxml (100%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/GroupPane.java (99%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/MetaDataPane.fxml (100%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/MetaDataPane.java (98%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/SlideShow.fxml (100%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/SlideShowView.java (95%) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java index 850230cb88..658e523be9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java @@ -35,8 +35,8 @@ import org.openide.windows.Mode; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.gui.GroupPane; -import org.sleuthkit.autopsy.imagegallery.gui.MetaDataPane; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.GroupPane; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.MetaDataPane; import org.sleuthkit.autopsy.imagegallery.gui.StatusBar; import org.sleuthkit.autopsy.imagegallery.gui.SummaryTablePane; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupView.java deleted file mode 100644 index 73d2f3373c..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupView.java +++ /dev/null @@ -1,8 +0,0 @@ - -package org.sleuthkit.autopsy.imagegallery.gui; - - - -public interface GroupView { - -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml similarity index 100% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.fxml rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.java similarity index 95% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.java index 86a0b2ddee..86eed0a814 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import java.util.Objects; import java.util.logging.Level; @@ -32,7 +32,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableTileBase.globalSelectionModel; +import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; +import static org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableTileBase.globalSelectionModel; import org.sleuthkit.datamodel.AbstractContent; /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java similarity index 99% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index 428bd0b5f4..ed12891589 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.eventbus.Subscribe; import java.util.ArrayList; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java similarity index 97% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java index ec794eabae..0657385aff 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import java.util.Objects; import static java.util.Objects.nonNull; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java similarity index 98% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java index 709679173e..6b9a532e86 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java @@ -1,4 +1,4 @@ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.eventbus.Subscribe; import java.util.Collection; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml similarity index 100% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.fxml rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java similarity index 99% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 09042abaf4..266b578f46 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -16,8 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.SlideShowView; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableTile; import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.Arrays; @@ -116,6 +118,8 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewMode; import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils; +import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.fxml similarity index 100% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.fxml rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.fxml diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java similarity index 98% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index 780513d16a..4814357a68 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.eventbus.Subscribe; import java.io.IOException; @@ -76,6 +76,20 @@ public class MetaDataPane extends DrawableUIBase { @FXML private BorderPane imageBorder; + public MetaDataPane(ImageGalleryController controller) { + super(controller); + + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MetaDataPane.fxml")); + fxmlLoader.setRoot(this); + fxmlLoader.setController(this); + + try { + fxmlLoader.load(); + } catch (IOException exception) { + throw new RuntimeException(exception); + } + } + @FXML @SuppressWarnings("unchecked") void initialize() { @@ -137,7 +151,7 @@ public class MetaDataPane extends DrawableUIBase { } @Override - synchronized protected void setFileHelper(Long newFileID) { + protected synchronized void setFileHelper(Long newFileID) { setFileIDOpt(Optional.ofNullable(newFileID)); if (newFileID == null) { Platform.runLater(() -> { @@ -151,20 +165,6 @@ public class MetaDataPane extends DrawableUIBase { } } - public MetaDataPane(ImageGalleryController controller) { - super(controller); - - FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MetaDataPane.fxml")); - fxmlLoader.setRoot(this); - fxmlLoader.setController(this); - - try { - fxmlLoader.load(); - } catch (IOException exception) { - throw new RuntimeException(exception); - } - } - public void updateUI() { getFile().ifPresent(file -> { final Image icon = file.getThumbnail(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShow.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml similarity index 100% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShow.fxml rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java similarity index 95% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java index d7d0f684ed..2b29e57d39 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import java.util.ArrayList; import java.util.function.Function; @@ -58,13 +58,16 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.ImageFile; import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.CAT_BORDER_WIDTH; +import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils; +import org.sleuthkit.autopsy.imagegallery.gui.MediaControl; +import static org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableView.CAT_BORDER_WIDTH; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** * Displays the files of a group one at a time. Designed to be embedded in a * GroupPane. TODO: Extract a subclass for video files in slideshow mode-jm + * * TODO: reduce coupling to GroupPane */ public class SlideShowView extends DrawableTileBase { @@ -73,40 +76,36 @@ public class SlideShowView extends DrawableTileBase { @FXML private ToggleButton cat0Toggle; - + @FXML + private ToggleButton cat1Toggle; @FXML private ToggleButton cat2Toggle; + @FXML + private ToggleButton cat3Toggle; + @FXML + private ToggleButton cat4Toggle; + @FXML + private ToggleButton cat5Toggle; @FXML private SplitMenuButton tagSplitButton; - @FXML - private ToggleButton cat3Toggle; - @FXML private Region spring; - @FXML private Button leftButton; - - @FXML - private ToggleButton cat4Toggle; - - @FXML - private ToggleButton cat5Toggle; - - @FXML - private ToggleButton cat1Toggle; - @FXML private Button rightButton; - @FXML private ToolBar toolBar; - @FXML private BorderPane footer; + SlideShowView(GroupPane gp) { + super(gp); + FXMLConstructor.construct(this, "SlideShow.fxml"); + } + @FXML @Override protected void initialize() { @@ -145,6 +144,8 @@ public class SlideShowView extends DrawableTileBase { tagSplitButton.getItems().setAll(selTagMenues); } }); + + //configure category toggles cat0Toggle.setBorder(new Border(new BorderStroke(Category.ZERO.getColor(), BorderStrokeStyle.SOLID, new CornerRadii(1), new BorderWidths(1)))); cat1Toggle.setBorder(new Border(new BorderStroke(Category.ONE.getColor(), BorderStrokeStyle.SOLID, new CornerRadii(1), new BorderWidths(1)))); cat2Toggle.setBorder(new Border(new BorderStroke(Category.TWO.getColor(), BorderStrokeStyle.SOLID, new CornerRadii(1), new BorderWidths(1)))); @@ -176,9 +177,7 @@ public class SlideShowView extends DrawableTileBase { //set up key listener equivalents of buttons addEventFilter(KeyEvent.KEY_PRESSED, (KeyEvent t) -> { - if (t.getEventType() == KeyEvent.KEY_PRESSED) { - switch (t.getCode()) { case LEFT: cycleSlideShowImage(-1); @@ -220,20 +219,14 @@ public class SlideShowView extends DrawableTileBase { } } - SlideShowView(GroupPane gp) { - super(gp); - - FXMLConstructor.construct(this, "SlideShow.fxml"); - - } - - @ThreadConfined(type = ThreadType.UI) + @ThreadConfined(type = ThreadType.JFX) public void stopVideo() { if (imageBorder.getCenter() instanceof MediaControl) { ((MediaControl) imageBorder.getCenter()).stopVideo(); } } + /** {@inheritDoc } */ @Override synchronized public void setFile(final Long fileID) { super.setFile(fileID); @@ -255,6 +248,7 @@ public class SlideShowView extends DrawableTileBase { imageBorder.setCenter(null); } + /** {@inheritDoc } */ @Override protected Runnable getContentUpdateRunnable() { @@ -281,11 +275,20 @@ public class SlideShowView extends DrawableTileBase { }); } + /** {@inheritDoc } */ @Override protected String getTextForLabel() { return getFile().map(file -> file.getName()).orElse("") + " " + getSupplementalText(); } + /** + * cycle the image displayed in thes SlideShowview, to the next/previous one + * in the group. + * + * @param direction the direction to cycle: + * -1 => left / back + * 1 => right / forward + */ @ThreadConfined(type = ThreadType.JFX) private void cycleSlideShowImage(int direction) { stopVideo(); @@ -296,7 +299,6 @@ public class SlideShowView extends DrawableTileBase { }).orElse(0); setFile(getGroupPane().getGrouping().fileIds().get(nextIndex) ); - } /** @@ -310,6 +312,7 @@ public class SlideShowView extends DrawableTileBase { } + /** {@inheritDoc } */ @Override @ThreadConfined(type = ThreadType.ANY) public Category updateCategory() { From 20eaa0d82aa87e05e0b0ba43ee6d37bf7a0a651e Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:23:36 -0400 Subject: [PATCH 115/198] remove unneeded interface --- .../imagegallery/gui/drawableviews/GroupPane.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 266b578f46..b95e5d51f6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -18,8 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; -import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.SlideShowView; -import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableTile; import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.Arrays; @@ -102,7 +100,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.directorytree.ExtractAction; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -130,13 +127,13 @@ import org.sleuthkit.datamodel.TskCoreException; * * * TODO: Extract the The GridView instance to a separate class analogous to the - * SlideShow. Move selection model into controlsfx GridView and submit pull + * SlideShow. + * + * TODO: Move selection model into controlsfx GridView and submit pull * request to them. * https://bitbucket.org/controlsfx/controlsfx/issue/4/add-a-multipleselectionmodel-to-gridview - * - * */ -public class GroupPane extends BorderPane implements GroupView { +public class GroupPane extends BorderPane { private static final Logger LOGGER = Logger.getLogger(GroupPane.class.getName()); From 8be4600f5c223ef9729969d03990f2d2d727fc80 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:42:48 -0400 Subject: [PATCH 116/198] move classes to better packages; remove FileUpdateEvent --- .../autopsy/imagegallery/FileUpdateEvent.java | 93 ------------------- .../imagegallery/ImageGalleryController.java | 5 +- .../imagegallery/actions/AddTagAction.java | 2 +- .../actions/CategorizeAction.java | 2 +- .../actions/DeleteFollowUpTagAction.java | 2 +- .../imagegallery/actions/NextUnseenGroup.java | 2 +- .../datamodel/CategoryChangeEvent.java | 50 ---------- .../datamodel/CategoryManager.java | 34 ++++++- .../imagegallery/datamodel/DrawableDB.java | 39 ++------ .../{ => datamodel}/DrawableTagsManager.java | 3 +- .../datamodel/HashSetManager.java | 1 + .../grouping/DrawableGroup.java | 2 +- .../{ => datamodel}/grouping/GroupKey.java | 2 +- .../grouping/GroupManager.java | 30 ++---- .../{ => datamodel}/grouping/GroupSortBy.java | 2 +- .../datamodel/grouping/GroupViewMode.java | 7 ++ .../grouping/GroupViewState.java | 2 +- .../imagegallery/grouping/GroupViewMode.java | 7 -- .../imagegallery/gui/SortByListCell.java | 2 +- .../imagegallery/gui/SummaryTablePane.java | 3 +- .../autopsy/imagegallery/gui/Toolbar.java | 4 +- .../gui/drawableviews/DrawableView.java | 3 +- .../gui/drawableviews/GroupPane.java | 6 +- .../gui/drawableviews/MetaDataPane.java | 4 +- .../gui/navpanel/GroupTreeCell.java | 2 +- .../gui/navpanel/GroupTreeItem.java | 2 +- .../imagegallery/gui/navpanel/NavPanel.java | 4 +- .../imagegallery/gui/navpanel/TreeNode.java | 2 +- 28 files changed, 88 insertions(+), 229 deletions(-) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/DrawableTagsManager.java (98%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/DrawableGroup.java (98%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/GroupKey.java (97%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/GroupManager.java (96%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/GroupSortBy.java (99%) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewMode.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/GroupViewState.java (97%) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewMode.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java deleted file mode 100644 index c2803a5090..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery; - -import java.util.Collection; -import java.util.Collections; -import java.util.EventListener; -import java.util.HashSet; -import java.util.Set; -import javax.annotation.concurrent.Immutable; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; - -/** represents a change in the database for one or more files. */ -@Immutable -public class FileUpdateEvent { - - /** the obj_ids of affected files */ - private final Set fileIDs; - - /** the attribute that was modified */ - private final DrawableAttribute changedAttribute; - - /** the type of update ( updated/removed) */ - private final UpdateType updateType; - - public UpdateType getUpdateType() { - return updateType; - } - - public Collection getFileIDs() { - return Collections.unmodifiableCollection(fileIDs); - } - - public DrawableAttribute getChangedAttribute() { - return changedAttribute; - } - - public static FileUpdateEvent newRemovedEvent(Collection updatedFiles) { - return new FileUpdateEvent(updatedFiles, UpdateType.REMOVE, null); - } - - /** - * - * @param updatedFiles the files that have been added or changed in the - * database - * @param changedAttribute the attribute that was changed for the files, or - * null if this represents new files - * - * @return a new FileUpdateEvent - */ - public static FileUpdateEvent newUpdateEvent(Collection updatedFiles, DrawableAttribute changedAttribute) { - return new FileUpdateEvent(updatedFiles, UpdateType.UPDATE, changedAttribute); - } - - private FileUpdateEvent(Collection updatedFiles, UpdateType updateType, DrawableAttribute changedAttribute) { - this.fileIDs = new HashSet<>(updatedFiles); - this.updateType = updateType; - this.changedAttribute = changedAttribute; - } - - static public enum UpdateType { - - /** files have been added or updated in the db */ - UPDATE, - /** files have been removed - * from the db */ - REMOVE; - } - - /** Interface for listening to FileUpdateEvents */ - public static interface FileUpdateListener extends EventListener { - - public void handleFileUpdate(FileUpdateEvent evt); - - public void handleFileRemoved(FileUpdateEvent evt); - } -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index d81ff29938..44fa8950a3 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import java.beans.PropertyChangeEvent; import java.util.ArrayList; import java.util.List; @@ -63,8 +64,8 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index f20fccfcfd..60f9f43749 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -29,7 +29,7 @@ import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.datamodel.TagName; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index afe2b3bb5d..518a49b87a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -28,7 +28,7 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 934a3fb258..fb729807c0 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -24,7 +24,7 @@ import javafx.event.ActionEvent; import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.ContentTag; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java index 550581d8b2..6a68810457 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java @@ -28,7 +28,7 @@ import javafx.scene.image.ImageView; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; /** * Marks the currently fisplayed group as "seen" and advances to the next unseen diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java deleted file mode 100644 index 3868864737..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery.datamodel; - -import java.util.Collection; -import java.util.Collections; -import javax.annotation.concurrent.Immutable; - -/** - * Event broadcast to various UI componenets when one or more files' category - * has been changed - */ -@Immutable -public class CategoryChangeEvent { - - private final Collection fileIDs; - private final Category newCategory; - - public CategoryChangeEvent(Collection fileIDs, Category newCategory) { - this.fileIDs = fileIDs; - this.newCategory = newCategory; - } - - public Category getNewCategory() { - return newCategory; - } - - /** - * @return the fileIDs of the files whose categories have changed - */ - public Collection getFileIDs() { - return Collections.unmodifiableCollection(fileIDs); - } -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 309173f153..f84f759d37 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -27,11 +27,13 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; +import javax.annotation.concurrent.Immutable; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -254,6 +256,7 @@ public class CategoryManager { fireChange(Collections.singleton(addedTag.getContent().getId()), newCat); } } + @Subscribe public void handleTagDeleted(ContentTagDeletedEvent event) { ContentTag deleted = event.getTag(); @@ -266,4 +269,33 @@ public class CategoryManager { fireChange(Collections.singleton(deleted.getContent().getId()), null); } } + + /** + * Event broadcast to various UI componenets when one or more files' + * category + * has been changed + */ + @Immutable + public static class CategoryChangeEvent { + + private final Collection fileIDs; + private final Category newCategory; + + public CategoryChangeEvent(Collection fileIDs, Category newCategory) { + super(); + this.fileIDs = fileIDs; + this.newCategory = newCategory; + } + + public Category getNewCategory() { + return newCategory; + } + + /** + * @return the fileIDs of the files whose categories have changed + */ + public Collection getFileIDs() { + return Collections.unmodifiableCollection(fileIDs); + } + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 9dfbbdc239..87fa001827 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -46,13 +46,12 @@ import org.apache.commons.lang3.StringUtils; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupSortBy; -import static org.sleuthkit.autopsy.imagegallery.grouping.GroupSortBy.GROUP_BY_VALUE; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupKey; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy; +import static org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy.GROUP_BY_VALUE; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -125,11 +124,6 @@ public final class DrawableDB { */ private final Map, PreparedStatement> groupStatementMap = new HashMap<>(); - /** - * list of observers to be notified if the database changes - */ - private final HashSet updateListeners = new HashSet<>(); - private GroupManager groupManager; private final Path dbPath; @@ -201,6 +195,7 @@ public final class DrawableDB { this.dbPath = dbPath; this.controller = controller; this.tskCase = controller.getSleuthKitCase(); + this.groupManager = controller.getGroupManager(); Files.createDirectories(dbPath.getParent()); if (initializeDBSchema()) { updateFileStmt = prepareStatement( @@ -644,22 +639,6 @@ public final class DrawableDB { tr.commit(notify); } - public void addUpdatedFileListener(FileUpdateEvent.FileUpdateListener l) { - updateListeners.add(l); - } - - private void fireUpdatedFiles(Collection fileIDs) { - for (FileUpdateEvent.FileUpdateListener listener : updateListeners) { - listener.handleFileUpdate(FileUpdateEvent.newUpdateEvent(fileIDs, null)); - } - } - - private void fireRemovedFiles(Collection fileIDs) { - for (FileUpdateEvent.FileUpdateListener listener : updateListeners) { - listener.handleFileRemoved(FileUpdateEvent.newRemovedEvent(fileIDs)); - } - } - public Boolean isFileAnalyzed(DrawableFile f) { return isFileAnalyzed(f.getId()); } @@ -1149,7 +1128,7 @@ public final class DrawableDB { * in the drawable db? */ @Nonnull - Set getHashSetsForFile(long fileID) { + public Set getHashSetsForFile(long fileID) { try { Set hashNames = new HashSet<>(); List arts = tskCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, fileID); @@ -1312,8 +1291,10 @@ public final class DrawableDB { close(); if (notify) { - fireUpdatedFiles(updatedFiles); - fireRemovedFiles(removedFiles); + if (groupManager != null) { + groupManager.handleFileUpdate(updatedFiles); + groupManager.handleFileRemoved(removedFiles); + } } } catch (SQLException ex) { if (Case.isCaseOpen()) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java similarity index 98% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index 0bbc4b9d5a..57d7152967 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery; +package org.sleuthkit.autopsy.imagegallery.datamodel; import com.google.common.eventbus.EventBus; import java.util.Collection; @@ -30,7 +30,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java index 1ca547c81e..1071a6ee0a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java @@ -4,6 +4,7 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.util.Set; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; /** * Manages a cache of hashset hits as a map from fileID to hashset names. diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java similarity index 98% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java index 0ad8b2640e..ac0493d75e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import java.util.Objects; import java.util.Set; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupKey.java similarity index 97% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupKey.java index cd41534078..ce64bebaa3 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupKey.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import java.util.Map; import java.util.Objects; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java similarity index 96% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index d7819c6d5e..ad99d94407 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import com.google.common.eventbus.Subscribe; import java.sql.ResultSet; @@ -50,7 +50,6 @@ import javax.annotation.concurrent.GuardedBy; import javax.swing.SortOrder; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; @@ -62,8 +61,6 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; @@ -71,6 +68,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -84,7 +82,7 @@ import org.sleuthkit.datamodel.TskCoreException; * extent {@link SleuthkitCase} ) to facilitate creation, retrieval, updating, * and sorting of {@link DrawableGroup}s. */ -public class GroupManager implements FileUpdateEvent.FileUpdateListener { +public class GroupManager { private static final Logger LOGGER = Logger.getLogger(GroupManager.class.getName()); @@ -123,7 +121,6 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public void setDB(DrawableDB db) { this.db = db; - db.addUpdatedFileListener(this); regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); } @@ -575,11 +572,10 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { DrawableGroup g = removeFromGroup(groupKey, fileID); } - @Override - synchronized public void handleFileRemoved(FileUpdateEvent evt) { - Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.REMOVE); + @Subscribe + synchronized public void handleFileRemoved(Collection removedFileIDs) { - for (final long fileId : evt.getFileIDs()) { + for (final long fileId : removedFileIDs) { //get grouping(s) this file would be in Set> groupsForFile = getGroupKeysForFileID(fileId); @@ -595,17 +591,15 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * * @param evt */ - @Override - synchronized public void handleFileUpdate(FileUpdateEvent evt) { - Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.UPDATE); - Collection fileIDs = evt.getFileIDs(); + @Subscribe + synchronized public void handleFileUpdate(Collection updatedFileIDs) { /** * TODO: is there a way to optimize this to avoid quering to db * so much. the problem is that as a new files are analyzed they * might be in new groups( if we are grouping by say make or * model) -jm */ - for (long fileId : fileIDs) { + for (long fileId : updatedFileIDs) { controller.getHashSetManager().invalidateHashSetsForFile(fileId); @@ -618,11 +612,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } //we fire this event for all files so that the category counts get updated during initial db population - controller.getCategoryManager().fireChange(fileIDs, null); - -// if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { -// controller.getTagsManager().fireChange(fileIDs); -// } + controller.getCategoryManager().fireChange(updatedFileIDs, null); } private DrawableGroup popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupSortBy.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java similarity index 99% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupSortBy.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java index fa2b3e88d0..a7bdbb342e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupSortBy.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import java.util.Arrays; import java.util.Comparator; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewMode.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewMode.java new file mode 100644 index 0000000000..17a970ca13 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewMode.java @@ -0,0 +1,7 @@ +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; + +public enum GroupViewMode { + + TILE, SLIDE_SHOW + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewState.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewState.java similarity index 97% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewState.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewState.java index 4d4905a80a..86679340ab 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewState.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewState.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import java.util.Objects; import java.util.Optional; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewMode.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewMode.java deleted file mode 100644 index 5506223429..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewMode.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.sleuthkit.autopsy.imagegallery.grouping; - -public enum GroupViewMode { - - TILE, SLIDE_SHOW - -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortByListCell.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortByListCell.java index 22985ff341..c9845fff3a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortByListCell.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortByListCell.java @@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.imagegallery.gui; import javafx.scene.control.ListCell; import javafx.scene.image.ImageView; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupSortBy; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy; public class SortByListCell extends ListCell { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java index 955cf0760f..6fe4ce9b44 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java @@ -36,7 +36,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; /** * Displays summary statistics (counts) for each group @@ -88,7 +87,7 @@ public class SummaryTablePane extends AnchorPane { * listen to Category updates and rebuild the table */ @Subscribe - public void handleCategoryChanged(CategoryChangeEvent evt) { + public void handleCategoryChanged(org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager.CategoryChangeEvent evt) { final ObservableList> data = FXCollections.observableArrayList(); if (Case.isCaseOpen()) { for (Category cat : Category.values()) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index 2131ff73fc..33083c45b4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -41,7 +41,7 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javax.swing.SortOrder; import org.openide.util.Exceptions; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -49,7 +49,7 @@ import org.sleuthkit.autopsy.imagegallery.ThumbnailCache; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupSortBy; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java index 6b9a532e86..4d7f31a52a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java @@ -18,7 +18,6 @@ import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -68,7 +67,7 @@ public interface DrawableView { * @param evt the CategoryChangeEvent to handle */ @Subscribe - default void handleCategoryChanged(CategoryChangeEvent evt) { + default void handleCategoryChanged(org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager.CategoryChangeEvent evt) { getFileID().ifPresent(fileID -> { if (evt.getFileIDs().contains(fileID)) { updateCategory(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index b95e5d51f6..4c2a056d46 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -112,9 +112,9 @@ import org.sleuthkit.autopsy.imagegallery.actions.NextUnseenGroup; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewMode; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewMode; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.datamodel.TagName; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index 4814357a68..5ebc6c1984 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -49,8 +49,8 @@ import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.events.TagEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -188,7 +188,7 @@ public class MetaDataPane extends DrawableUIBase { /** {@inheritDoc } */ @Subscribe @Override - public void handleCategoryChanged(CategoryChangeEvent evt) { + public void handleCategoryChanged(CategoryManager.CategoryChangeEvent evt) { getFileID().ifPresent(fileID -> { if (evt.getFileIDs().contains(fileID)) { updateUI(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java index 5deaf88aa8..8103a55cf6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java @@ -31,7 +31,7 @@ import javafx.scene.image.ImageView; import javax.annotation.Nonnull; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; /** * A cell in the NavPanel tree that listens to its associated group's fileids diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java index 37925b47bb..3bd5ff72bf 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java @@ -27,7 +27,7 @@ import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.scene.control.TreeItem; import org.apache.commons.lang3.StringUtils; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; /** * A node in the nav/hash tree. Manages inserts and removals. Has parents and diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java index efc855e8ca..64aa5a681e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java @@ -45,8 +45,8 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; /** * Display two trees. one shows all folders (groups) and calls out folders with diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/TreeNode.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/TreeNode.java index 0c7b2c2806..b230409075 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/TreeNode.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/TreeNode.java @@ -18,7 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.gui.navpanel; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; /** * From 3e45191012bfa9fc28b29870fdf479106440e6e1 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 16:42:44 -0400 Subject: [PATCH 117/198] better handling of exceptions in event bus eventhandlers --- .../datamodel/CategoryManager.java | 11 ++++++-- .../datamodel/DrawableTagsManager.java | 18 ++++++++---- .../datamodel/grouping/GroupManager.java | 28 +++++++++++-------- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index f84f759d37..31be08e71a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -20,20 +20,21 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.google.common.eventbus.AsyncEventBus; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.concurrent.Executors; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import javax.annotation.concurrent.Immutable; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -66,7 +67,11 @@ public class CategoryManager { /** * Used to distribute {@link CategoryChangeEvent}s */ - private final EventBus categoryEventBus = new EventBus("Category Event Bus"); + private final EventBus categoryEventBus = new AsyncEventBus(Executors.newSingleThreadExecutor( + new BasicThreadFactory.Builder().namingPattern("Category Event Bus").uncaughtExceptionHandler((Thread t, Throwable e) -> { + LOGGER.log(Level.SEVERE, "uncaught exception in event bus handler", e); + }).build() + )); /** * For performance reasons, keep current category counts in memory. All of diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index 57d7152967..af5a0ebced 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -18,19 +18,20 @@ */ package org.sleuthkit.autopsy.imagegallery.datamodel; +import com.google.common.eventbus.AsyncEventBus; import com.google.common.eventbus.EventBus; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -42,13 +43,20 @@ import org.sleuthkit.datamodel.TskCoreException; */ public class DrawableTagsManager { + private static final Logger LOGGER = Logger.getLogger(DrawableTagsManager.class.getName()); + private static final String FOLLOW_UP = "Follow Up"; final private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; /** Used to distribute {@link TagsChangeEvent}s */ - private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); + private final EventBus tagsEventBus = new AsyncEventBus( + Executors.newSingleThreadExecutor( + new BasicThreadFactory.Builder().namingPattern("Tags Event Bus").uncaughtExceptionHandler((Thread t, Throwable e) -> { + LOGGER.log(Level.SEVERE, "uncaught exception in event bus handler", e); + }).build() + )); /** The tag name corresponding to the "built-in" tag "Follow Up" */ private TagName followUpTagName; @@ -130,7 +138,7 @@ public class DrawableTagsManager { .filter(CategoryManager::isCategoryTagName) .collect(Collectors.toSet()); } catch (TskCoreException | IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + LOGGER.log(Level.WARNING, "couldn't access case", ex); } return Collections.emptySet(); } @@ -166,7 +174,7 @@ public class DrawableTagsManager { throw new TskCoreException("tagame exists but wasn't found", ex); } } catch (IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); + LOGGER.log(Level.SEVERE, "Case was closed out from underneath", ex); throw new TskCoreException("Case was closed out from underneath", ex); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index ad99d94407..dc27ac136b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -537,15 +537,16 @@ public class GroupManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { GroupKey groupKey = null; - if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); - } else if (groupBy == DrawableAttribute.CATEGORY) { + if (groupBy == DrawableAttribute.CATEGORY && CategoryManager.isCategoryTagName(evt.getTag().getName())) { groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); + } + if (groupKey != null) { + final long fileID = evt.getTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); } - final long fileID = evt.getTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); - } @SuppressWarnings("AssignmentToMethodParameter") @@ -563,13 +564,16 @@ public class GroupManager { @Subscribe public void handleTagDeleted(ContentTagDeletedEvent evt) { GroupKey groupKey = null; - if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); - } else if (groupBy == DrawableAttribute.CATEGORY) { + if (groupBy == DrawableAttribute.CATEGORY && CategoryManager.isCategoryTagName(evt.getTag().getName())) { groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); + } + + if (groupKey != null) { + final long fileID = evt.getTag().getContent().getId(); + DrawableGroup g = removeFromGroup(groupKey, fileID); } - final long fileID = evt.getTag().getContent().getId(); - DrawableGroup g = removeFromGroup(groupKey, fileID); } @Subscribe From c93f80fd5846ec9a83cf9da059f1051c77156ce1 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 15:46:12 -0400 Subject: [PATCH 118/198] only add new cat tag if there is no existing cat tag. put adding and removing fileids to/from group on jfx thread; remove file from groups when adding to new catagory based on new tag --- .../imagegallery/ImageGalleryController.java | 2 +- .../actions/CategorizeAction.java | 23 +++++++++---- .../datamodel/CategoryManager.java | 6 ++-- .../datamodel/grouping/GroupManager.java | 32 ++++++++++++------- 4 files changed, 41 insertions(+), 22 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 44fa8950a3..e71aaf434c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import java.beans.PropertyChangeEvent; import java.util.ArrayList; import java.util.List; @@ -63,6 +62,7 @@ import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 518a49b87a..f7c20ab56b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -19,8 +19,10 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.logging.Level; +import java.util.stream.Collectors; import javafx.event.ActionEvent; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; @@ -28,12 +30,14 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -127,11 +131,10 @@ public class CategorizeAction extends AddTagAction { try { DrawableFile file = controller.getFileFromId(fileID); //drawable db - - if (tagName != categoryManager.getTagName(Category.ZERO)) { // no tags for cat-0 - tagsManager.addContentTag(file, tagName, comment); //tsk db - } else { - tagsManager.getContentTagsByContent(file).stream() + final List fileTags = tagsManager.getContentTagsByContent(file); + if (tagName == categoryManager.getTagName(Category.ZERO)) { + // delete all cat tags for cat-0 + fileTags.stream() .filter(tag -> CategoryManager.isCategoryTagName(tag.getName())) .forEach((ct) -> { try { @@ -140,6 +143,14 @@ public class CategorizeAction extends AddTagAction { LOGGER.log(Level.SEVERE, "Error removing old categories result", ex); } }); + } else { + //add cat tag if no existing cat tag for that cat + if (fileTags.stream() + .map(Tag::getName) + .filter(tagName::equals) + .collect(Collectors.toList()).isEmpty()) { + tagsManager.addContentTag(file, tagName, comment); + } } } catch (TskCoreException ex) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 31be08e71a..3377fdce6e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -233,14 +233,12 @@ public class CategoryManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent event) { - ContentTag addedTag = event.getTag(); + final ContentTag addedTag = event.getTag(); if (isCategoryTagName(addedTag.getName())) { final DrawableTagsManager tagsManager = controller.getTagsManager(); try { //remove old category tag(s) if necessary - List allContentTags = tagsManager.getContentTagsByContent(addedTag.getContent()); - - for (ContentTag ct : allContentTags) { + for (ContentTag ct : tagsManager.getContentTagsByContent(addedTag.getContent())) { if (ct.getId() != addedTag.getId() && CategoryManager.isCategoryTagName(ct.getName())) { try { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index dc27ac136b..8b7844d9c4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -270,7 +270,9 @@ public class GroupManager { //get grouping this file would be in final DrawableGroup group = getGroupForKey(groupKey); if (group != null) { - group.removeFile(fileID); + Platform.runLater(() -> { + group.removeFile(fileID); + }); // If we're grouping by category, we don't want to remove empty groups. if (groupKey.getAttribute() != DrawableAttribute.CATEGORY) { @@ -536,16 +538,21 @@ public class GroupManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { - GroupKey groupKey = null; + GroupKey newGroupKey = null; + final long fileID = evt.getTag().getContent().getId(); if (groupBy == DrawableAttribute.CATEGORY && CategoryManager.isCategoryTagName(evt.getTag().getName())) { - groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + newGroupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + for (GroupKey oldGroupKey : groupMap.keySet()) { + if (oldGroupKey.equals(newGroupKey) == false) { + removeFromGroup(oldGroupKey, fileID); + } + } } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); + newGroupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } - if (groupKey != null) { - final long fileID = evt.getTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); + if (newGroupKey != null) { + DrawableGroup g = getGroupForKey(newGroupKey); + addFileToGroup(g, newGroupKey, fileID); } } @@ -555,9 +562,13 @@ public class GroupManager { //if there wasn't already a group check if there should be one now g = popuplateIfAnalyzed(groupKey, null); } - if (g != null) { + DrawableGroup group = g; + if (group != null) { //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. - g.addFile(fileID); + Platform.runLater(() -> { + group.addFile(fileID); + }); + } } @@ -569,7 +580,6 @@ public class GroupManager { } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } - if (groupKey != null) { final long fileID = evt.getTag().getContent().getId(); DrawableGroup g = removeFromGroup(groupKey, fileID); From 5dfae177dbec07dc50f622d1c235f2505858ed1c Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 16:12:55 -0400 Subject: [PATCH 119/198] clean up add tag action, use invokeLater not invokeAndWait; getNonCategoryTagNames returns TagNames in alphabetical order by displayname --- .../imagegallery/actions/AddTagAction.java | 63 +++++++------------ .../datamodel/DrawableTagsManager.java | 14 ++++- 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 60f9f43749..4ae762217c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -18,22 +18,17 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.util.List; +import java.util.Collection; import java.util.Set; -import java.util.logging.Level; import javafx.event.ActionEvent; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; import javax.swing.SwingUtilities; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; /** * An abstract base class for actions that allow users to tag SleuthKit data @@ -77,42 +72,31 @@ abstract class AddTagAction { TagMenu(ImageGalleryController controller) { super(getActionDisplayName()); - // Get the current set of tag names. - DrawableTagsManager tagsManager = controller.getTagsManager(); - List tagNames = null; - try { - tagNames = tagsManager.getAllTagNames(); - } catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); - } - // Create a "Quick Tag" sub-menu. Menu quickTagMenu = new Menu("Quick Tag"); getItems().add(quickTagMenu); - // Each tag name in the current set of tags gets its own menu item in - // the "Quick Tags" sub-menu. Selecting one of these menu items adds - // a tag with the associated tag name. - if (null != tagNames && !tagNames.isEmpty()) { - for (final TagName tagName : tagNames) { - if (CategoryManager.isNotCategoryTagName(tagName)) { - MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); - tagNameItem.setOnAction((ActionEvent t) -> { - addTag(tagName, NO_COMMENT); - }); - quickTagMenu.getItems().add(tagNameItem); - } - } - } else { + /* Each non-Category tag name in the current set of tags gets its + * own menu item in the "Quick Tags" sub-menu. Selecting one of + * these menu items adds a tag with the associated tag name. */ + Collection tagNames = controller.getTagsManager().getNonCategoryTagNames(); + if (tagNames.isEmpty()) { MenuItem empty = new MenuItem("No tags"); empty.setDisable(true); quickTagMenu.getItems().add(empty); + } else { + for (final TagName tagName : tagNames) { + MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); + tagNameItem.setOnAction((ActionEvent t) -> { + addTag(tagName, NO_COMMENT); + }); + quickTagMenu.getItems().add(tagNameItem); + } } - // quickTagMenu.addSeparator(); - // The "Quick Tag" menu also gets an "Choose Tag..." menu item. - // Selecting this item initiates a dialog that can be used to create - // or select a tag name and adds a tag with the resulting name. + /* The "Quick Tag" menu also gets an "New Tag..." menu item. + * Selecting this item initiates a dialog that can be used to create + * or select a tag name and adds a tag with the resulting name. */ MenuItem newTagMenuItem = new MenuItem("New Tag..."); newTagMenuItem.setOnAction((ActionEvent t) -> { SwingUtilities.invokeLater(() -> { @@ -124,18 +108,19 @@ abstract class AddTagAction { }); quickTagMenu.getItems().add(newTagMenuItem); - // Create a "Choose Tag and Comment..." menu item. Selecting this item initiates - // a dialog that can be used to create or select a tag name with an - // optional comment and adds a tag with the resulting name. + /* Create a "Tag and Comment..." menu item. Selecting this item + * initiates a dialog that can be used to create or select a tag + * name with an optional comment and adds a tag with the resulting + * name. */ MenuItem tagAndCommentItem = new MenuItem("Tag and Comment..."); tagAndCommentItem.setOnAction((ActionEvent t) -> { SwingUtilities.invokeLater(() -> { GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); if (null != tagNameAndComment) { - if (CategoryManager.isCategoryTagName(tagNameAndComment.getTagName())) { - new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); + if (CategoryManager.isCategoryTagName(tagNameAndComment.getTagName())) { + new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } else { - new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); + new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } } }); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index af5a0ebced..547ab7a858 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -27,6 +27,7 @@ import java.util.Objects; import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; +import javax.annotation.Nonnull; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; @@ -131,12 +132,21 @@ public class DrawableTagsManager { } } + /** + * get all the TagNames that are not categories + * + * @return all the TagNames that are not categories, in alphabetical order + * by displayName, or, an empty set if there was an exception looking them + * up from the db. + */ + @Nonnull public Collection getNonCategoryTagNames() { synchronized (autopsyTagsManagerLock) { try { return autopsyTagsManager.getAllTagNames().stream() - .filter(CategoryManager::isCategoryTagName) - .collect(Collectors.toSet()); + .filter(CategoryManager::isNotCategoryTagName) + .distinct().sorted() + .collect(Collectors.toList()); } catch (TskCoreException | IllegalStateException ex) { LOGGER.log(Level.WARNING, "couldn't access case", ex); } From 33586fd071b5f32f2aa85e2bdc8800e39abdd8c5 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 16:23:59 -0400 Subject: [PATCH 120/198] SlideShow toggle is disabled initialy; fix relative paths to images in fxml --- .../gui/drawableviews/DrawableTile.fxml | 112 +++++++++--------- .../gui/drawableviews/GroupPane.fxml | 12 +- .../gui/drawableviews/SlideShow.fxml | 12 +- 3 files changed, 69 insertions(+), 67 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml index 4d34061c77..acfcdc1336 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml @@ -7,60 +7,62 @@ - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+
-
-
- -
-
-
-
-
- - - + + + +
diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml index 6eb799970d..4760d1f0cf 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml @@ -23,7 +23,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -53,7 +53,7 @@ - + @@ -108,16 +108,16 @@ - + - + - + diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml index fb9e0aade4..fd3862afee 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml @@ -18,7 +18,7 @@ - + @@ -42,7 +42,7 @@ - + @@ -88,12 +88,12 @@ - + - + @@ -110,7 +110,7 @@ - + @@ -135,7 +135,7 @@ - + From c5622c2282f3812ae32bb35cb48d630f99aae3a9 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 16:27:03 -0400 Subject: [PATCH 121/198] SlideShow toggle is disabled when there is no group selected; fix relative paths to images in fxml --- .../autopsy/imagegallery/gui/drawableviews/GroupPane.fxml | 2 +- .../autopsy/imagegallery/gui/drawableviews/GroupPane.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml index 4760d1f0cf..6dfe0d02ed 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml @@ -113,7 +113,7 @@ - + diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 4c2a056d46..ab011fc493 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -590,6 +590,7 @@ public class GroupPane extends BorderPane { Platform.runLater(() -> { gridView.getItems().setAll(Collections.emptyList()); setCenter(null); + slideShowToggle.setDisable(true); groupLabel.setText(""); resetScrollBar(); if (false == Case.isCaseOpen()) { From 2ee9b50c62dcea5bf5bcacd92998b2ed93342b08 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 24 Jun 2015 10:13:59 -0400 Subject: [PATCH 122/198] remove TagAction class since it provides no value --- .../autopsy/actions/AddTagAction.java | 68 +++++++++++-------- .../DeleteBlackboardArtifactTagAction.java | 8 +-- .../actions/DeleteContentTagAction.java | 8 +-- .../sleuthkit/autopsy/actions/TagAction.java | 45 ------------ 4 files changed, 46 insertions(+), 83 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/actions/TagAction.java diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index 9c552247fd..7f4f813495 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -22,6 +22,7 @@ import java.awt.event.ActionEvent; import java.util.Collections; import java.util.List; import java.util.logging.Level; +import javax.swing.AbstractAction; import javax.swing.JMenu; import javax.swing.JMenuItem; import org.openide.util.NbBundle; @@ -33,45 +34,54 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** - * An abstract base class for Actions that allow users to tag SleuthKit data - * model objects. + * An abstract base class for Actions that allow users to tag SleuthKit data + * model objects. */ -abstract class AddTagAction extends TagAction implements Presenter.Popup { +abstract class AddTagAction extends AbstractAction implements Presenter.Popup { + private static final String NO_COMMENT = ""; - + AddTagAction(String menuText) { super(menuText); } - + @Override - public JMenuItem getPopupPresenter() { + public JMenuItem getPopupPresenter() { return new TagMenu(); } - - @Override - protected void doAction(ActionEvent event) { - } - + /** - * Template method to allow derived classes to provide a string for for a - * menu item label. + * Subclasses of AddTagAction, should not override actionPerformed, but + * instead override addTag. + * + * @param event + */ + @Override + @SuppressWarnings("NoopMethodInAbstractClass") + public void actionPerformed(ActionEvent event) { + } + + /** + * Template method to allow derived classes to provide a string for a menu + * item label. */ abstract protected String getActionDisplayName(); - + /** - * Template method to allow derived classes to add the indicated tag and - * comment to one or more a SleuthKit data model objects. + * Template method to allow derived classes to add the indicated tag and + * comment to one or more SleuthKit data model objects. */ abstract protected void addTag(TagName tagName, String comment); /** - * Instances of this class implement a context menu user interface for - * creating or selecting a tag name for a tag and specifying an optional tag - * comment. + * Instances of this class implement a context menu user interface for + * creating or selecting a tag name for a tag and specifying an optional tag + * comment. */ // @@@ This user interface has some significant usability issues and needs // to be reworked. private class TagMenu extends JMenu { + TagMenu() { super(getActionDisplayName()); @@ -81,15 +91,14 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { try { tagNames = tagsManager.getAllTagNames(); Collections.sort(tagNames); - } - catch (TskCoreException ex) { + } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS } - + // Create a "Quick Tag" sub-menu. JMenu quickTagMenu = new JMenu(NbBundle.getMessage(this.getClass(), "AddTagAction.quickTag")); - add(quickTagMenu); - + add(quickTagMenu); + // Each tag name in the current set of tags gets its own menu item in // the "Quick Tags" sub-menu. Selecting one of these menu items adds // a tag with the associated tag name. @@ -101,11 +110,10 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { }); quickTagMenu.add(tagNameItem); } - } - else { + } else { JMenuItem empty = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.noTags")); empty.setEnabled(false); - quickTagMenu.add(empty); + quickTagMenu.add(empty); } quickTagMenu.addSeparator(); @@ -133,7 +141,7 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } }); - add(tagAndCommentItem); + add(tagAndCommentItem); } - } -} \ No newline at end of file + } +} diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java index 5c7369c603..ac9e29fe59 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java @@ -21,19 +21,19 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import java.util.Collection; import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; +import javax.swing.AbstractAction; import javax.swing.JOptionPane; - import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this Action allow users to delete tags applied to blackboard artifacts. */ -public class DeleteBlackboardArtifactTagAction extends TagAction { +public class DeleteBlackboardArtifactTagAction extends AbstractAction { private static final String MENU_TEXT = NbBundle.getMessage(DeleteBlackboardArtifactTagAction.class, "DeleteBlackboardArtifactTagAction.deleteTags"); @@ -54,7 +54,7 @@ public class DeleteBlackboardArtifactTagAction extends TagAction { } @Override - protected void doAction(ActionEvent event) { + public void actionPerformed(ActionEvent event) { Collection selectedTags = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactTag.class); for (BlackboardArtifactTag tag : selectedTags) { try { diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java index d69e60bb31..c716311eea 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java @@ -21,19 +21,19 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import java.util.Collection; import java.util.logging.Level; -import org.sleuthkit.autopsy.coreutils.Logger; +import javax.swing.AbstractAction; import javax.swing.JOptionPane; - import org.openide.util.NbBundle; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this Action allow users to delete tags applied to content. */ -public class DeleteContentTagAction extends TagAction { +public class DeleteContentTagAction extends AbstractAction { private static final String MENU_TEXT = NbBundle.getMessage(DeleteContentTagAction.class, "DeleteContentTagAction.deleteTags"); @@ -54,7 +54,7 @@ public class DeleteContentTagAction extends TagAction { } @Override - protected void doAction(ActionEvent e) { + public void actionPerformed(ActionEvent e) { Collection selectedTags = Utilities.actionsGlobalContext().lookupAll(ContentTag.class); for (ContentTag tag : selectedTags) { try { diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagAction.java b/Core/src/org/sleuthkit/autopsy/actions/TagAction.java deleted file mode 100755 index ed53af2c6f..0000000000 --- a/Core/src/org/sleuthkit/autopsy/actions/TagAction.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013-15 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.actions; - -import java.awt.event.ActionEvent; -import javax.swing.AbstractAction; - -/** - * Abstract base class for Actions involving tags. - */ -abstract class TagAction extends AbstractAction { - - public TagAction(String menuText) { - super(menuText); - } - - @Override - public void actionPerformed(ActionEvent event) { - doAction(event); - } - - /** - * Derived classes must implement this Template Method for - * actionPerformed(). - * - * @param event ActionEvent object passed to actionPerformed() - */ - abstract protected void doAction(ActionEvent event); -} From 2e034c19fdfa6a8a3609d06e24ebfec26944a8e6 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 24 Jun 2015 10:17:51 -0400 Subject: [PATCH 123/198] use private notifyPropertyChangeEvent() method in notifyNewDataSource --- .../sleuthkit/autopsy/casemodule/Case.java | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 19ec87e3cc..9b7c010bec 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -488,16 +488,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @param newDataSource new data source added */ void notifyNewDataSource(Content newDataSource) { - - try { - pcs.firePropertyChange(Events.DATA_SOURCE_ADDED.toString(), null, newDataSource); - } catch (Exception e) { - logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), - NbBundle.getMessage(this.getClass(), - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } + notifyPropertyChangeEvent(new PropertyChangeEvent(Case.class, Events.DATA_SOURCE_ADDED.toString(), null, newDataSource)); CoreComponentControl.openCoreWindows(); } @@ -507,7 +498,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @param newTag new ContentTag added */ public void notifyContentTagAdded(ContentTag newTag) { - notify(new ContentTagAddedEvent(newTag)); + notifyPropertyChangeEvent(new ContentTagAddedEvent(newTag)); } /** @@ -516,7 +507,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @param deletedTag ContentTag deleted */ public void notifyContentTagDeleted(ContentTag deletedTag) { - notify(new ContentTagDeletedEvent(deletedTag)); + notifyPropertyChangeEvent(new ContentTagDeletedEvent(deletedTag)); } /** @@ -525,7 +516,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @param newTag new BlackboardArtifactTag added */ public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) { - notify(new BlackBoardArtifactTagAddedEvent(newTag)); + notifyPropertyChangeEvent(new BlackBoardArtifactTagAddedEvent(newTag)); } /** @@ -534,7 +525,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @param deletedTag BlackboardArtifactTag deleted */ public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { - notify(new BlackBoardArtifactTagDeletedEvent(deletedTag)); + notifyPropertyChangeEvent(new BlackBoardArtifactTagDeletedEvent(deletedTag)); } /** @@ -542,7 +533,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * * @param propertyChangeEvent the event to distribute */ - private void notify(final PropertyChangeEvent propertyChangeEvent) { + private void notifyPropertyChangeEvent(final PropertyChangeEvent propertyChangeEvent) { try { pcs.firePropertyChange(propertyChangeEvent); } catch (Exception e) { From bce619b50e9e7369c09688e3142ab6f998fc408e Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 24 Jun 2015 10:29:03 -0400 Subject: [PATCH 124/198] catch IllegalStateException from Case.getCurrentCase() in TagsManager methods --- .../casemodule/services/Bundle.properties | 6 ++++- .../casemodule/services/TagsManager.java | 24 +++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 5242f90667..b267fde0a2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -14,4 +14,8 @@ FileManager.addLocalDirInt2.exception.closed.msg=Attempted to use FileManager af TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} out of content size range (0 - {1}) TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} out of content size range (0 - {1}) TagsManager.addContentTag.exception.endLTbegin.msg=endByteOffset < beginByteOffset -TagsManager.predefTagNames.bookmark.text=Bookmark \ No newline at end of file +TagsManager.predefTagNames.bookmark.text=Bookmark +TagsManager.addContentTag.noCaseWarning=Failed to add publish new content tag event. There is no case open. +TagsManager.deleteContentTag.noCaseWarning=Failed to add publish content tag deleted event. There is no case open. +TagsManager.addBlackboardArtifactTag.noCaseWarning=Failed to add publish new blackboard artifact tag event. There is no case open. +TagsManager.deleteBlackboardArtifactTag.noCaseWarning=Failed to add publish blackboard artifact tag deleted event. There is no case open. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 72fdf22ca4..f94976b572 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -248,7 +248,11 @@ public class TagsManager implements Closeable { } } final ContentTag newContentTag = tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); - Case.getCurrentCase().notifyContentTagAdded(newContentTag); + try { + Case.getCurrentCase().notifyContentTagAdded(newContentTag); + } catch (IllegalArgumentException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.addContentTag.noCaseWarning")); + } return newContentTag; } @@ -266,7 +270,11 @@ public class TagsManager implements Closeable { } tskCase.deleteContentTag(tag); - Case.getCurrentCase().notifyContentTagDeleted(tag); + try { + Case.getCurrentCase().notifyContentTagDeleted(tag); + } catch (IllegalArgumentException e) { + Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteContentTag.noCaseWarning")); + } } /** @@ -375,7 +383,11 @@ public class TagsManager implements Closeable { } BlackboardArtifactTag addBlackboardArtifactTag = tskCase.addBlackboardArtifactTag(artifact, tagName, comment); - Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(addBlackboardArtifactTag); + try { + Case.getCurrentCase().notifyBlackBoardArtifactTagAdded(addBlackboardArtifactTag); + } catch (IllegalArgumentException e) { + Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.addBlackboardArtifactTag.noCaseWarning")); + } return addBlackboardArtifactTag; } @@ -394,7 +406,11 @@ public class TagsManager implements Closeable { Case.getPropertyChangeSupport().firePropertyChange(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString(), tag, null); tskCase.deleteBlackboardArtifactTag(tag); - Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); + try { + Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); + } catch (IllegalArgumentException e) { + Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.deleteBlackboardArtifactTag.noCaseWarning")); + } } /** From aff60bd329175908c8361356bbed35fcaba15018 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 24 Jun 2015 12:58:17 -0400 Subject: [PATCH 125/198] fix hashset display move return out of loop so we get all hashset names; use getHashSetsForFileFromAutopsy directly rather than circuitously through HashSetManager --- .../imagegallery/datamodel/DrawableDB.java | 45 +++++++++---------- .../datamodel/HashSetManager.java | 2 +- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 87fa001827..c330fa6865 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -582,27 +582,25 @@ public final class DrawableDB { stmt.setBoolean(8, f.isAnalyzed()); stmt.executeUpdate(); - final Collection hashSetNames = DrawableAttribute.HASHSET.getValue(f); + final Collection hashSetNames = getHashSetsForFileFromAutopsy(f.getId()); - if (hashSetNames.isEmpty() == false) { - for (String name : hashSetNames) { + for (String name : hashSetNames) { - // "insert or ignore into hash_sets (hash_set_name) values (?)" - insertHashSetStmt.setString(1, name); - insertHashSetStmt.executeUpdate(); + // "insert or ignore into hash_sets (hash_set_name) values (?)" + insertHashSetStmt.setString(1, name); + insertHashSetStmt.executeUpdate(); - //TODO: use nested select to get hash_set_id rather than seperate statement/query - //"select hash_set_id from hash_sets where hash_set_name = ?" - selectHashSetStmt.setString(1, name); - try (ResultSet rs = selectHashSetStmt.executeQuery()) { - while (rs.next()) { - int hashsetID = rs.getInt("hash_set_id"); - //"insert or ignore into hash_set_hits (hash_set_id, obj_id) values (?,?)"; - insertHashHitStmt.setInt(1, hashsetID); - insertHashHitStmt.setLong(2, f.getId()); - insertHashHitStmt.executeUpdate(); - break; - } + //TODO: use nested select to get hash_set_id rather than seperate statement/query + //"select hash_set_id from hash_sets where hash_set_name = ?" + selectHashSetStmt.setString(1, name); + try (ResultSet rs = selectHashSetStmt.executeQuery()) { + while (rs.next()) { + int hashsetID = rs.getInt("hash_set_id"); + //"insert or ignore into hash_set_hits (hash_set_id, obj_id) values (?,?)"; + insertHashHitStmt.setInt(1, hashsetID); + insertHashHitStmt.setLong(2, f.getId()); + insertHashHitStmt.executeUpdate(); + break; } } } @@ -1095,6 +1093,8 @@ public final class DrawableDB { removeFileStmt.setLong(1, id); removeFileStmt.executeUpdate(); tr.addRemovedFile(id); + + //TODO: delete from hash_set_hits table also... } catch (SQLException ex) { LOGGER.log(Level.WARNING, "failed to delete row for obj_id = " + id, ex); } finally { @@ -1122,16 +1122,13 @@ public final class DrawableDB { * * @return a set of names, each of which is a hashset that the given file is * in. - * - * - * //TODO: why does this go to the SKC? don't we already have this info - * in the drawable db? */ @Nonnull - public Set getHashSetsForFile(long fileID) { + public Set getHashSetsForFileFromAutopsy(long fileID) { try { Set hashNames = new HashSet<>(); List arts = tskCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, fileID); + for (BlackboardArtifact a : arts) { List attrs = a.getAttributes(); for (BlackboardAttribute attr : attrs) { @@ -1139,8 +1136,8 @@ public final class DrawableDB { hashNames.add(attr.getValueString()); } } - return hashNames; } + return hashNames; } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "failed to get hash sets for file", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java index 1071a6ee0a..b8f48b50d4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java @@ -36,7 +36,7 @@ public class HashSetManager { * @return the names of the hashsets the given fileID is in */ private Set getHashSetsForFileHelper(long fileID) { - return db.getHashSetsForFile(fileID); + return db.getHashSetsForFileFromAutopsy(fileID); } /** From 67ff3ee7cdfdbccee50c1d7c0875b087c9d89cc8 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Wed, 24 Jun 2015 15:30:11 -0400 Subject: [PATCH 126/198] Text FileReport added to databse. Logger format changed --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 11 ++++++++++- Core/src/org/sleuthkit/autopsy/coreutils/Logger.java | 2 +- .../org/sleuthkit/autopsy/report/FileReportText.java | 7 +++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index db1250ebf7..759c431a52 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -25,6 +25,8 @@ import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.nio.file.InvalidPathException; +import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.GregorianCalendar; @@ -1163,7 +1165,14 @@ public class Case implements SleuthkitCase.ErrorObserver { * @throws TskCoreException */ public void addReport(String localPath, String srcModuleName, String reportName) throws TskCoreException { - Report report = this.db.addReport(localPath, srcModuleName, reportName); + String normalizedLocalPath; + try { + normalizedLocalPath = Paths.get(localPath).normalize().toString(); + } catch (InvalidPathException ex) { + logger.log(Level.WARNING, "Invalid local path provided: " + localPath, ex); + normalizedLocalPath = localPath; + } + Report report = this.db.addReport(normalizedLocalPath, srcModuleName, reportName); try { Case.pcs.firePropertyChange(Events.REPORT_ADDED.toString(), null, report); } catch (Exception ex) { diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java b/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java index 494c86cf7f..8ae2480883 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java @@ -79,7 +79,7 @@ public final class Logger extends java.util.logging.Logger { + record.getSourceMethodName() + "\n" + record.getLevel() + ": " + this.formatMessage(record) + "\n" - + record.getThrown().toString() + ": " + + record.getThrown().toString() + ":\n" + StackTrace + "\n"; } else { diff --git a/Core/src/org/sleuthkit/autopsy/report/FileReportText.java b/Core/src/org/sleuthkit/autopsy/report/FileReportText.java index 2dd7e8b676..d7eac93477 100755 --- a/Core/src/org/sleuthkit/autopsy/report/FileReportText.java +++ b/Core/src/org/sleuthkit/autopsy/report/FileReportText.java @@ -30,7 +30,9 @@ import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; /** * A Tab-delimited text report of the files in the case. @@ -68,8 +70,13 @@ import org.sleuthkit.datamodel.AbstractFile; if (out != null) { try { out.close(); + Case.getCurrentCase().addReport(reportPath, NbBundle.getMessage(this.getClass(), + "FileReportText.getName.text"), ""); } catch (IOException ex) { logger.log(Level.WARNING, "Could not close output writer when ending report.", ex); //NON-NLS + } catch (TskCoreException ex) { + String errorMessage = String.format("Error adding %s to case as a report", reportPath); //NON-NLS + logger.log(Level.SEVERE, errorMessage, ex); } } } From a7a0c803c434d98dddfe7e62c55fc9c269cbab18 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Wed, 24 Jun 2015 15:39:33 -0400 Subject: [PATCH 127/198] Show max file count window only once - not each refresh --- .../autopsy/datamodel/DeletedContent.java | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index 37f7140d37..94e46b0986 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -35,6 +35,7 @@ import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; +import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -111,6 +112,7 @@ public class DeletedContent implements AutopsyVisitableItem { private static final String NAME = NbBundle.getMessage(DeletedContent.class, "DeletedContent.deletedContentsNode.name"); private SleuthkitCase skCase; + DeletedContentsNode(SleuthkitCase skCase) { super(Children.create(new DeletedContentsChildren(skCase), true), Lookups.singleton(NAME)); @@ -151,6 +153,8 @@ public class DeletedContent implements AutopsyVisitableItem { private SleuthkitCase skCase; private Observable notifier; + // true if we have already told user that not all files will be shown + private static boolean maxFilesDialogShown = false; public DeletedContentsChildren(SleuthkitCase skCase) { this.skCase = skCase; @@ -195,6 +199,7 @@ public class DeletedContent implements AutopsyVisitableItem { if (evt.getNewValue() == null) { removeListeners(); } + maxFilesDialogShown = false; } } }; @@ -333,14 +338,19 @@ public class DeletedContent implements AutopsyVisitableItem { List queryList = runFsQuery(); if (queryList.size() == MAX_OBJECTS) { queryList.remove(queryList.size() - 1); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - JOptionPane.showMessageDialog(null, NbBundle.getMessage(this.getClass(), - "DeletedContent.createKeys.maxObjects.msg", - MAX_OBJECTS - 1)); - } - }); + + // only show the dialog once - not each time we refresh + if (maxFilesDialogShown == false) { + maxFilesDialogShown = true; + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), NbBundle.getMessage(this.getClass(), + "DeletedContent.createKeys.maxObjects.msg", + MAX_OBJECTS - 1)); + } + }); + } } list.addAll(queryList); return true; From 9b021d5adbc17c43a840e234565e4a7fd185cad4 Mon Sep 17 00:00:00 2001 From: Sidhesh Mhatre Date: Wed, 24 Jun 2015 15:42:45 -0400 Subject: [PATCH 128/198] Throw TskCoreException if localPath is invalid --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 759c431a52..f763c708a4 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -1169,8 +1169,9 @@ public class Case implements SleuthkitCase.ErrorObserver { try { normalizedLocalPath = Paths.get(localPath).normalize().toString(); } catch (InvalidPathException ex) { - logger.log(Level.WARNING, "Invalid local path provided: " + localPath, ex); - normalizedLocalPath = localPath; + String errorMsg = "Invalid local path provided: " + localPath; // NON-NLS + logger.log(Level.WARNING, errorMsg, ex); + throw new TskCoreException(errorMsg); } Report report = this.db.addReport(normalizedLocalPath, srcModuleName, reportName); try { From 10f66173a02a6269a0d3bcbc1fa1f1cadf50d40f Mon Sep 17 00:00:00 2001 From: Sidhesh Mhatre Date: Wed, 24 Jun 2015 16:19:16 -0400 Subject: [PATCH 129/198] Not logging invalidpathException --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index f763c708a4..298435eeb0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -1170,8 +1170,7 @@ public class Case implements SleuthkitCase.ErrorObserver { normalizedLocalPath = Paths.get(localPath).normalize().toString(); } catch (InvalidPathException ex) { String errorMsg = "Invalid local path provided: " + localPath; // NON-NLS - logger.log(Level.WARNING, errorMsg, ex); - throw new TskCoreException(errorMsg); + throw new TskCoreException(errorMsg, ex); } Report report = this.db.addReport(normalizedLocalPath, srcModuleName, reportName); try { From e1e5e78bd040c91bab9a0243fe1150c0ee7d5f38 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 16 Jun 2015 11:14:44 -0400 Subject: [PATCH 130/198] make new DeleteFollowUpTag action; use Set instead of List to prevent duplicate files in groups --- .../actions/DeleteFollowUpTag.java | 86 +++++++++++++++++++ .../imagegallery/datamodel/DrawableDB.java | 10 +-- .../imagegallery/grouping/DrawableGroup.java | 4 +- .../imagegallery/grouping/GroupManager.java | 30 ++++--- .../imagegallery/gui/DrawableViewBase.java | 55 ++++++------ 5 files changed, 138 insertions(+), 47 deletions(-) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java new file mode 100644 index 0000000000..0399b545ed --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java @@ -0,0 +1,86 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery.actions; + +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import javafx.event.ActionEvent; +import org.controlsfx.control.action.Action; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; +import org.sleuthkit.autopsy.ingest.IngestServices; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * + */ +public class DeleteFollowUpTag extends Action { + + private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTag.class.getName()); + private final long fileID; + private final DrawableFile file; + + public DeleteFollowUpTag(DrawableFile file) { + super("Delete Follow Up Tag"); + this.file = file; + this.fileID = file.getId(); + + setEventHandler((ActionEvent t) -> { + deleteFollowupTag(); + }); + } + + /** + * + * @param fileID1 the value of fileID1 + * + * @throws IllegalStateException + */ + private void deleteFollowupTag() throws IllegalStateException { + + final ImageGalleryController controller = ImageGalleryController.getDefault(); + final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + try { + // remove file from old category group + controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); + + List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); + for (ContentTag ct : contentTagsByContent) { + if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { + sleuthKitCase.deleteContentTag(ct); + } + } + IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); + } + } +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index a5f91bb9d3..ac1f6c99eb 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -698,7 +698,7 @@ public final class DrawableDB { public Boolean isGroupAnalyzed(GroupKey gk) { dbReadLock(); try { - List fileIDsInGroup = getFileIDsInGroup(gk); + Set fileIDsInGroup = getFileIDsInGroup(gk); try { // In testing, this method appears to be a lot faster than doing one large select statement @@ -747,10 +747,10 @@ public final class DrawableDB { * * @throws TskCoreException */ - public List findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException { + public Set findAllFileIdsWhere(String sqlWhereClause) throws TskCoreException { Statement statement = null; ResultSet rs = null; - List ret = new ArrayList<>(); + Set ret = new HashSet<>(); dbReadLock(); try { statement = con.createStatement(); @@ -984,7 +984,7 @@ public final class DrawableDB { } } - public List getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { + public Set getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { if (groupKey.getAttribute().isDBColumn) { switch (groupKey.getAttribute().attrName) { @@ -994,7 +994,7 @@ public final class DrawableDB { return groupManager.getFileIDsWithTag((TagName) groupKey.getValue()); } } - List files = new ArrayList<>(); + Set files = new HashSet<>(); dbReadLock(); try { PreparedStatement statement = getGroupStatment(groupKey.getAttribute()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index e6d1f3dad8..b59a1b8edd 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -18,8 +18,8 @@ */ package org.sleuthkit.autopsy.imagegallery.grouping; -import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.logging.Level; import javafx.beans.property.ReadOnlyBooleanWrapper; import javafx.collections.FXCollections; @@ -70,7 +70,7 @@ public class DrawableGroup implements Comparable { return groupKey.getValueDisplayName(); } - DrawableGroup(GroupKey groupKey, List filesInGroup, boolean seen) { + DrawableGroup(GroupKey groupKey, Set filesInGroup, boolean seen) { this.groupKey = groupKey; this.fileIDs.setAll(filesInGroup); this.seen.set(seen); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index ec35f6bb60..68e1044dbc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -40,6 +40,7 @@ import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javax.swing.SortOrder; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.netbeans.api.progress.ProgressHandle; @@ -241,8 +242,9 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * * @return the new DrawableGroup for the given key */ - public DrawableGroup makeGroup(GroupKey groupKey, List files) { - List newFiles = files == null ? new ArrayList<>() : files; + public DrawableGroup makeGroup(GroupKey groupKey, Set files) { + + Set newFiles = ObjectUtils.defaultIfNull(files, new HashSet()); final boolean groupSeen = db.isGroupSeen(groupKey); DrawableGroup g = new DrawableGroup(groupKey, newFiles, groupSeen); @@ -303,7 +305,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } - public synchronized void populateAnalyzedGroup(final GroupKey groupKey, List filesInGroup) { + public synchronized void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup) { populateAnalyzedGroup(groupKey, filesInGroup, null); } @@ -314,7 +316,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @param groupKey * @param filesInGroup */ - private synchronized
> void populateAnalyzedGroup(final GroupKey groupKey, List filesInGroup, ReGroupTask task) { + private synchronized > void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup, ReGroupTask task) { /* if this is not part of a regroup task or it is but the task is not * cancelled... @@ -352,7 +354,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * this * group if they are all analyzed */ - public List checkAnalyzed(final GroupKey groupKey) { + public Set checkAnalyzed(final GroupKey groupKey) { try { /* for attributes other than path we can't be sure a group is fully * analyzed because we don't know all the files that will be a part @@ -464,7 +466,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } - public List getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { + public Set getFileIDsInGroup(GroupKey groupKey) throws TskCoreException { switch (groupKey.getAttribute().attrName) { //these cases get special treatment case CATEGORY: @@ -481,12 +483,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { // @@@ This was kind of slow in the profiler. Maybe we should cache it. // Unless the list of file IDs is necessary, use countFilesWithCategory() to get the counts. - public List getFileIDsWithCategory(Category category) throws TskCoreException { + public Set getFileIDsWithCategory(Category category) throws TskCoreException { try { if (category == Category.ZERO) { - List files = new ArrayList<>(); + Set files = new HashSet<>(); TagName[] tns = {Category.FOUR.getTagName(), Category.THREE.getTagName(), Category.TWO.getTagName(), Category.ONE.getTagName(), Category.FIVE.getTagName()}; for (TagName tn : tns) { List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tn); @@ -500,7 +502,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { return db.findAllFileIdsWhere("obj_id NOT IN (" + StringUtils.join(files, ',') + ")"); } else { - List files = new ArrayList<>(); + Set files = new HashSet<>(); List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(category.getTagName()); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { @@ -516,9 +518,9 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } - public List getFileIDsWithTag(TagName tagName) throws TskCoreException { + public Set getFileIDsWithTag(TagName tagName) throws TskCoreException { try { - List files = new ArrayList<>(); + Set files = new HashSet<>(); List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { @@ -636,7 +638,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { // It may be that this was the last unanalyzed file in the group, so test // whether the group is now fully analyzed. //TODO: use method in groupmanager ? - List checkAnalyzed = checkAnalyzed(gk); + Set checkAnalyzed = checkAnalyzed(gk); if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui populateAnalyzedGroup(gk, checkAnalyzed); } @@ -674,7 +676,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } else { //if there wasn't already a group check if there should be one now //TODO: use method in groupmanager ? - List checkAnalyzed = checkAnalyzed(gk); + Set checkAnalyzed = checkAnalyzed(gk); if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui populateAnalyzedGroup(gk, checkAnalyzed); } @@ -759,7 +761,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { //check if this group is analyzed final GroupKey groupKey = new GroupKey<>(groupBy, val); - List checkAnalyzed = checkAnalyzed(groupKey); + Set checkAnalyzed = checkAnalyzed(groupKey); if (checkAnalyzed != null) { // != null => the group is analyzed, so add it to the ui // makeGroup will create the group and add it to the map groupMap, but does not diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 23164f41fb..e866742505 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -22,8 +22,6 @@ package org.sleuthkit.autopsy.imagegallery.gui; import com.google.common.eventbus.Subscribe; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.List; import java.util.Objects; import java.util.logging.Level; import javafx.application.Platform; @@ -64,21 +62,16 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; +import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTag; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -272,28 +265,38 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie LOGGER.log(Level.SEVERE, "Failed to add follow up tag. Could not load TagName.", ex); } } else { - //TODO: convert this to an action! - final ImageGalleryController controller = ImageGalleryController.getDefault(); - try { - // remove file from old category group - controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); - - List contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(file); - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { - Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(ct); - } - } - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); - } + new DeleteFollowUpTag(file).handle(t); +// deleteFollowupTag(fileID); } - }); } +// /** +// * +// * @param fileID1 the value of fileID1 +// * +// * @throws IllegalStateException +// */ +// private void deleteFollowupTag(final Long fileID1) throws IllegalStateException { +// //TODO: convert this to an action! +// final ImageGalleryController controller = ImageGalleryController.getDefault(); +// try { +// // remove file from old category group +// controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID1); +// +// List contentTagsByContent = controller.getSleuthKitCase().getContentTagsByContent(file); +// for (ContentTag ct : contentTagsByContent) { +// if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { +// controller.getSleuthKitCase().deleteContentTag(ct); +// } +// } +// IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS +// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID1), DrawableAttribute.TAGS)); +// } catch (TskCoreException ex) { +// LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); +// } +// } + @Override public DrawableFile getFile() { if (fileID != null) { From edfe858dd869e7ab4ed17abf91de25a6a9725c93 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 16 Jun 2015 12:51:06 -0400 Subject: [PATCH 131/198] cleanup Follow Up tag and Category TagNames (prevent short name version from being added, by removing commas) --- .../imagegallery/ImageGalleryController.java | 1 + .../autopsy/imagegallery/TagUtils.java | 31 +++++++++++-------- .../actions/DeleteFollowUpTag.java | 2 ++ .../imagegallery/datamodel/Category.java | 19 +++++++----- .../datamodel/CategoryManager.java | 2 ++ 5 files changed, 35 insertions(+), 20 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index b93f362dae..8864ddc264 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -371,6 +371,7 @@ public final class ImageGalleryController { historyManager.clear(); }); Category.clearTagNames(); + TagUtils.clearFollowUpTagName(); Toolbar.getDefault().reset(); groupManager.clear(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java index b5eb4cfc25..8e9e8cfc98 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java @@ -20,10 +20,12 @@ package org.sleuthkit.autopsy.imagegallery; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; +import java.util.stream.Collectors; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.control.MenuItem; @@ -43,34 +45,36 @@ import org.sleuthkit.datamodel.TskCoreException; */ public class TagUtils { - private static final String follow_Up = "Follow Up"; + private static final String FOLLOW_UP = "Follow Up"; private static TagName followUpTagName; + /** + * Use when closing a case to make sure everything is re-initialized in the + * next case. + */ + public static void clearFollowUpTagName() { + followUpTagName = null; + } + private final static List listeners = new ArrayList<>(); synchronized public static TagName getFollowUpTagName() throws TskCoreException { if (followUpTagName == null) { - followUpTagName = getTagName(follow_Up); + followUpTagName = getTagName(FOLLOW_UP); } return followUpTagName; } static public Collection getNonCategoryTagNames() { - List nonCatTagNames = new ArrayList<>(); - List allTagNames; try { - allTagNames = Case.getCurrentCase().getServices().getTagsManager().getAllTagNames(); - for (TagName tn : allTagNames) { - if (tn.getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) { - nonCatTagNames.add(tn); - } - } + return Case.getCurrentCase().getServices().getTagsManager().getAllTagNames().stream() + .filter(Category::isCategoryTagName) + .collect(Collectors.toSet()); } catch (TskCoreException | IllegalStateException ex) { Logger.getLogger(TagUtils.class.getName()).log(Level.WARNING, "couldn't access case", ex); } - - return nonCatTagNames; + return Collections.emptySet(); } synchronized static public TagName getTagName(String displayName) throws TskCoreException { @@ -94,7 +98,7 @@ public class TagUtils { } public static void fireChange(Collection ids) { - Set listenersCopy = new HashSet(listeners); + Set listenersCopy = new HashSet<>(listeners); synchronized (listeners) { listenersCopy.addAll(listeners); } @@ -132,6 +136,7 @@ public class TagUtils { } public static interface TagListener { + public void handleTagsChanged(Collection ids); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java index 0399b545ed..0fe88de953 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java @@ -78,6 +78,8 @@ public class DeleteFollowUpTag extends Action { } } IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + + //make sure rest of ui hears category change. controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 780e851876..4839537731 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -34,16 +34,17 @@ import org.sleuthkit.datamodel.TskCoreException; */ public enum Category implements Comparable { - ZERO(Color.LIGHTGREY, 0, "CAT-0, Uncategorized"), - ONE(Color.RED, 1, "CAT-1, Child Exploitation (Illegal)"), - TWO(Color.ORANGE, 2, "CAT-2, Child Exploitation (Non-Illegal/Age Difficult)"), - THREE(Color.YELLOW, 3, "CAT-3, CGI/Animation (Child Exploitive)"), - FOUR(Color.BISQUE, 4, "CAT-4, Exemplar/Comparison (Internal Use Only)"), - FIVE(Color.GREEN, 5, "CAT-5, Non-pertinent"); + ZERO(Color.LIGHTGREY, 0, "CAT-0: Uncategorized"), + ONE(Color.RED, 1, "CAT-1: Child Exploitation (Illegal)"), + TWO(Color.ORANGE, 2, "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"), + THREE(Color.YELLOW, 3, "CAT-3: CGI/Animation (Child Exploitive)"), + FOUR(Color.BISQUE, 4, "CAT-4: Exemplar/Comparison (Internal Use Only)"), + FIVE(Color.GREEN, 5, "CAT-5: Non-pertinent"); /** map from displayName to enum value */ private static final Map nameMap - = Stream.of(values()).collect(Collectors.toMap(Category::getDisplayName, + = Stream.of(values()).collect(Collectors.toMap( + Category::getDisplayName, Function.identity())); public static final String CATEGORY_PREFIX = "CAT-"; @@ -65,6 +66,10 @@ public enum Category implements Comparable { Category.FIVE.tagName = null; } + public static boolean isCategoryTagName(TagName tName) { + return nameMap.containsKey(tName.getDisplayName()); + } + private TagName tagName; private final Color color; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 699af41bbb..f6e0404c6e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -26,6 +26,7 @@ import java.util.Collection; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.TagUtils; /** * Provides a cached view of the number of files per category, and fires @@ -75,6 +76,7 @@ public class CategoryManager { this.db = db; categoryCounts.invalidateAll(); Category.clearTagNames(); + TagUtils.clearFollowUpTagName(); } /** From d587e1c53e6e72de5a447f4e0fe24590c17aacdf Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 16 Jun 2015 16:53:16 -0400 Subject: [PATCH 132/198] clean up and refactor code related to Tagging and actions; move away from singleton by injecting controller rather than using getDefault(); use EventBus in DrawableTagsManager (used to be TagUtils) requires equal and hashcode method implemented on TagName --- .../imagegallery/DrawableTagsManager.java | 161 ++++++++++++++++++ .../imagegallery/ImageGalleryController.java | 14 +- .../ImageGalleryTopComponent.java | 3 +- .../autopsy/imagegallery/TagUtils.java | 142 --------------- .../autopsy/imagegallery/TagsChangeEvent.java | 41 +++++ .../actions/AddDrawableTagAction.java | 45 ++--- .../imagegallery/actions/AddTagAction.java | 9 +- .../actions/CategorizeAction.java | 41 +++-- ...eFollowUpTag.java => DeleteTagAction.java} | 42 +++-- .../imagegallery/datamodel/Category.java | 19 --- .../datamodel/CategoryChangeEvent.java | 10 +- .../datamodel/CategoryManager.java | 29 +++- .../imagegallery/datamodel/DrawableDB.java | 15 +- .../imagegallery/grouping/GroupKey.java | 2 +- .../imagegallery/grouping/GroupManager.java | 36 ++-- .../imagegallery/gui/DrawableTile.java | 7 +- .../imagegallery/gui/DrawableView.java | 12 +- .../imagegallery/gui/DrawableViewBase.java | 62 +++---- .../autopsy/imagegallery/gui/GroupPane.java | 39 +++-- .../autopsy/imagegallery/gui/GuiUtils.java | 62 +++++++ .../imagegallery/gui/MetaDataPane.java | 20 ++- .../imagegallery/gui/SlideShowView.java | 12 +- .../autopsy/imagegallery/gui/Toolbar.java | 28 +-- 23 files changed, 494 insertions(+), 357 deletions(-) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/{DeleteFollowUpTag.java => DeleteTagAction.java} (66%) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java new file mode 100644 index 0000000000..3c1dd42de3 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -0,0 +1,161 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery; + +import com.google.common.eventbus.EventBus; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.stream.Collectors; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Manages Tags, Tagging, and the relationship between Categories and Tags in + * the autopsy Db. delegates some, work to the backing {@link TagsManager}. + */ +public class DrawableTagsManager { + + private static final String FOLLOW_UP = "Follow Up"; + + private TagsManager autopsyTagsManager; + + /** Used to distribute {@link TagsChangeEvent}s */ + private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); + + /** The tag name corresponging to the "built-in" tag "Follow Up" */ + private TagName followUpTagName; + + public DrawableTagsManager(TagsManager autopsyTagsManager) { + this.autopsyTagsManager = autopsyTagsManager; + + } + + /** + * assign a new TagsManager to back this one, ie when the current case + * changes + * + * @param autopsyTagsManager + */ + public synchronized void setAutopsyTagsManager(TagsManager autopsyTagsManager) { + this.autopsyTagsManager = autopsyTagsManager; + clearFollowUpTagName(); + } + + /** + * Use when closing a case to make sure everything is re-initialized in the + * next case. + */ + public synchronized void clearFollowUpTagName() { + followUpTagName = null; + } + + /** + * fire a CategoryChangeEvent with the given fileIDs + * + * @param fileIDs + */ + public final void fireChange(Collection fileIDs) { + tagsEventBus.post(new TagsChangeEvent(fileIDs)); + } + + /** + * register an object to receive CategoryChangeEvents + * + * @param listner + */ + public void registerListener(Object listner) { + tagsEventBus.register(listner); + } + + /** + * unregister an object from receiving CategoryChangeEvents + * + * @param listener + */ + public void unregisterListener(Object listener) { + tagsEventBus.unregister(listener); + } + + /** + * get the (cached) follow up TagName + * + * @return + * + * @throws TskCoreException + */ + synchronized public TagName getFollowUpTagName() throws TskCoreException { + if (followUpTagName == null) { + followUpTagName = getTagName(FOLLOW_UP); + } + return followUpTagName; + } + + public Collection getNonCategoryTagNames() { + try { + return autopsyTagsManager.getAllTagNames().stream() + .filter(Category::isCategoryTagName) + .collect(Collectors.toSet()); + } catch (TskCoreException | IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + } + return Collections.emptySet(); + } + + public synchronized TagName getTagName(String displayName) throws TskCoreException { + try { + for (TagName tn : autopsyTagsManager.getAllTagNames()) { + if (displayName.equals(tn.getDisplayName())) { + return tn; + } + } + try { + return autopsyTagsManager.addTagName(displayName); + } catch (TagsManager.TagNameAlreadyExistsException ex) { + throw new TskCoreException("tagame exists but wasn't found", ex); + } + } catch (IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); + throw new TskCoreException("Case was closed out from underneath", ex); + } + } + + public synchronized TagName getTagName(Category cat) { + try { + return getTagName(cat.getDisplayName()); + } catch (TskCoreException ex) { + return null; + } + } + + public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { + autopsyTagsManager.addContentTag(file, tagName, comment); + } + + public List getContentTagsByTagName(TagName t) throws TskCoreException { + return autopsyTagsManager.getContentTagsByTagName(t); + } + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 8864ddc264..ae7a169e96 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -126,7 +126,8 @@ public final class ImageGalleryController { private final GroupManager groupManager = new GroupManager(this); private final HashSetManager hashSetManager = new HashSetManager(); - private final CategoryManager categoryManager = new CategoryManager(); + private final CategoryManager categoryManager = new CategoryManager(this); + private final DrawableTagsManager tagsManager = new DrawableTagsManager(null); private StackPane fullUIStackPane; @@ -344,7 +345,7 @@ public final class ImageGalleryController { * @param theNewCase the case to configure the controller for */ public synchronized void setCase(Case theNewCase) { - this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), getSleuthKitCase()); + this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); @@ -356,6 +357,7 @@ public final class ImageGalleryController { groupManager.setDB(db); hashSetManager.setDb(db); categoryManager.setDb(db); + tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); SummaryTablePane.getDefault().refresh(); } @@ -371,9 +373,9 @@ public final class ImageGalleryController { historyManager.clear(); }); Category.clearTagNames(); - TagUtils.clearFollowUpTagName(); + tagsManager.clearFollowUpTagName(); - Toolbar.getDefault().reset(); + Toolbar.getDefault(this).reset(); groupManager.clear(); if (db != null) { db.closeDBCon(); @@ -489,6 +491,10 @@ public final class ImageGalleryController { return categoryManager; } + public DrawableTagsManager getTagsManager() { + return tagsManager; + } + // @@@ REVIEW IF THIS SHOLD BE STATIC... //TODO: concept seems like the controller deal with how much work to do at a given time // @@@ review this class for synchronization issues (i.e. reset and cancel being called, add, etc.) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java index 6aa431fb4c..e5c2bb3bd6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java @@ -34,7 +34,6 @@ import org.openide.util.NbBundle.Messages; import org.openide.windows.Mode; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.gui.GroupPane; import org.sleuthkit.autopsy.imagegallery.gui.MetaDataPane; @@ -145,7 +144,7 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl fullUIStack.getChildren().add(borderPane); splitPane = new SplitPane(); borderPane.setCenter(splitPane); - borderPane.setTop(Toolbar.getDefault()); + borderPane.setTop(Toolbar.getDefault(controller)); borderPane.setBottom(new StatusBar(controller)); metaDataTable = new MetaDataPane(controller); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java deleted file mode 100644 index 8e9e8cfc98..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagUtils.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import java.util.stream.Collectors; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.scene.control.MenuItem; -import javafx.scene.control.SplitMenuButton; -import javafx.scene.image.ImageView; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Contains static methods for dealing with Tags in ImageGallery - */ -public class TagUtils { - - private static final String FOLLOW_UP = "Follow Up"; - - private static TagName followUpTagName; - - /** - * Use when closing a case to make sure everything is re-initialized in the - * next case. - */ - public static void clearFollowUpTagName() { - followUpTagName = null; - } - - private final static List listeners = new ArrayList<>(); - - synchronized public static TagName getFollowUpTagName() throws TskCoreException { - if (followUpTagName == null) { - followUpTagName = getTagName(FOLLOW_UP); - } - return followUpTagName; - } - - static public Collection getNonCategoryTagNames() { - try { - return Case.getCurrentCase().getServices().getTagsManager().getAllTagNames().stream() - .filter(Category::isCategoryTagName) - .collect(Collectors.toSet()); - } catch (TskCoreException | IllegalStateException ex) { - Logger.getLogger(TagUtils.class.getName()).log(Level.WARNING, "couldn't access case", ex); - } - return Collections.emptySet(); - } - - synchronized static public TagName getTagName(String displayName) throws TskCoreException { - try { - final TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - - for (TagName tn : tagsManager.getAllTagNames()) { - if (displayName.equals(tn.getDisplayName())) { - return tn; - } - } - try { - return tagsManager.addTagName(displayName); - } catch (TagsManager.TagNameAlreadyExistsException ex) { - throw new TskCoreException("tagame exists but wasn't found", ex); - } - } catch (IllegalStateException ex) { - Logger.getLogger(TagUtils.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); - throw new TskCoreException("Case was closed out from underneath", ex); - } - } - - public static void fireChange(Collection ids) { - Set listenersCopy = new HashSet<>(listeners); - synchronized (listeners) { - listenersCopy.addAll(listeners); - } - for (TagListener list : listenersCopy) { - list.handleTagsChanged(ids); - } - } - - public static void registerListener(TagListener aThis) { - synchronized (listeners) { - listeners.add(aThis); - } - } - - public static void unregisterListener(TagListener aThis) { - synchronized (listeners) { - listeners.remove(aThis); - } - } - - /** - * @param tn the value of tn - */ - static public MenuItem createSelTagMenuItem(final TagName tn, final SplitMenuButton tagSelectedMenuButton) { - final MenuItem menuItem = new MenuItem(tn.getDisplayName(), new ImageView(DrawableAttribute.TAGS.getIcon())); - menuItem.setOnAction(new EventHandler() { - @Override - public void handle(ActionEvent t) { - AddDrawableTagAction.getInstance().addTag(tn, ""); - tagSelectedMenuButton.setText(tn.getDisplayName()); - tagSelectedMenuButton.setOnAction(this); - } - }); - return menuItem; - } - - public static interface TagListener { - - public void handleTagsChanged(Collection ids); - } -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java new file mode 100644 index 0000000000..0647a18456 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java @@ -0,0 +1,41 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery; + +import java.util.Collection; +import java.util.Collections; +import javax.annotation.concurrent.Immutable; + +/** + * + */ +@Immutable +public class TagsChangeEvent { + + private final Collection fileIDs; + + public Collection getFileIDs() { + return Collections.unmodifiableCollection(fileIDs); + } + + public TagsChangeEvent(Collection fileIDs) { + this.fileIDs = fileIDs; + } + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index a098e1a1c9..394f348466 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -27,7 +27,6 @@ import javafx.scene.control.Menu; import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.openide.util.Utilities; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; @@ -45,50 +44,41 @@ import org.sleuthkit.datamodel.TskCoreException; * diverged from autopsy action, make this extend from controlsfx Action */ public class AddDrawableTagAction extends AddTagAction { - + private static final Logger LOGGER = Logger.getLogger(AddDrawableTagAction.class.getName()); - // This class is a singleton to support multi-selection of nodes, since - // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every - // node in the array returns a reference to the same action object from Node.getActions(boolean). - private static AddDrawableTagAction instance; - - public static synchronized AddDrawableTagAction getInstance() { - if (null == instance) { - instance = new AddDrawableTagAction(); - } - return instance; + private final ImageGalleryController controller; + + public AddDrawableTagAction(ImageGalleryController controller) { + this.controller = controller; } - - private AddDrawableTagAction() { - } - + public Menu getPopupMenu() { - return new TagMenu(); + return new TagMenu(controller); } - + @Override protected String getActionDisplayName() { return Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File"; } - + @Override public void addTag(TagName tagName, String comment) { Set selectedFiles = new HashSet<>(FileIDSelectionModel.getInstance().getSelected()); addTagsToFiles(tagName, comment, selectedFiles); } - + @Override - public void addTagsToFiles(TagName tagName, String comment, Set selectedFiles){ + public void addTagsToFiles(TagName tagName, String comment, Set selectedFiles) { new SwingWorker() { - + @Override protected Void doInBackground() throws Exception { for (Long fileID : selectedFiles) { try { - DrawableFile file = ImageGalleryController.getDefault().getFileFromId(fileID); + DrawableFile file = controller.getFileFromId(fileID); LOGGER.log(Level.INFO, "tagging {0} with {1} and comment {2}", new Object[]{file.getName(), tagName.getDisplayName(), comment}); - Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment); + controller.getTagsManager().addContentTag(file, tagName, comment); } catch (IllegalStateException ex) { LOGGER.log(Level.SEVERE, "Case was closed out from underneath Updatefile task", ex); } catch (TskCoreException ex) { @@ -97,14 +87,12 @@ public class AddDrawableTagAction extends AddTagAction { } //make sure rest of ui hears category change. - ImageGalleryController.getDefault().getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); - + controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } - refreshDirectoryTree(); return null; } - + @Override protected void done() { super.done(); @@ -114,7 +102,6 @@ public class AddDrawableTagAction extends AddTagAction { LOGGER.log(Level.SEVERE, "unexpected exception while tagging files", ex); } } - }.execute(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 42cd0ecfd1..94fd9f070a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -30,6 +30,7 @@ import org.sleuthkit.autopsy.actions.GetTagNameDialog; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -43,7 +44,7 @@ import org.sleuthkit.datamodel.TskCoreException; * * //TODO: this class started as a cut and paste from * org.sleuthkit.autopsy.actions.AddTagAction and needs to be - * refactor or reintegrated to the AddTagAction hierarchy of Autopysy. + * refactored or reintegrated to the AddTagAction hierarchy of Autopysy. */ abstract class AddTagAction { @@ -86,7 +87,7 @@ abstract class AddTagAction { // to be reworked. protected class TagMenu extends Menu { - TagMenu() { + TagMenu(ImageGalleryController controller) { super(getActionDisplayName()); // Get the current set of tag names. @@ -147,9 +148,9 @@ abstract class AddTagAction { GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); if (null != tagNameAndComment) { if (tagNameAndComment.getTagName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { - new CategorizeAction().addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); + new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } else { - AddDrawableTagAction.getInstance().addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); + new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } refreshDirectoryTree(); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 79a04f535d..358516694e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -29,16 +29,18 @@ import javafx.scene.control.MenuItem; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -54,13 +56,13 @@ public class CategorizeAction extends AddTagAction { private final ImageGalleryController controller; - public CategorizeAction() { + public CategorizeAction(ImageGalleryController controller) { super(); - this.controller = ImageGalleryController.getDefault(); + this.controller = controller; } - static public Menu getPopupMenu() { - return new CategoryMenu(); + public Menu getPopupMenu() { + return new CategoryMenu(controller); } @Override @@ -90,7 +92,7 @@ public class CategorizeAction extends AddTagAction { */ static private class CategoryMenu extends Menu { - CategoryMenu() { + CategoryMenu(ImageGalleryController controller) { super("Categorize"); // Each category get an item in the sub-menu. Selecting one of these menu items adds @@ -99,8 +101,8 @@ public class CategorizeAction extends AddTagAction { MenuItem categoryItem = new MenuItem(cat.getDisplayName()); categoryItem.setOnAction((ActionEvent t) -> { - final CategorizeAction categorizeAction = new CategorizeAction(); - categorizeAction.addTag(cat.getTagName(), NO_COMMENT); + final CategorizeAction categorizeAction = new CategorizeAction(controller); + categorizeAction.addTag(controller.getCategoryManager().getTagName(cat), NO_COMMENT); }); categoryItem.setAccelerator(new KeyCodeCombination(KeyCode.getKeyCode(Integer.toString(cat.getCategoryNumber())))); getItems().add(categoryItem); @@ -123,29 +125,34 @@ public class CategorizeAction extends AddTagAction { @Override public void run() { + final GroupManager groupManager = controller.getGroupManager(); + final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + final CategoryManager categoryManager = controller.getCategoryManager(); + try { DrawableFile file = controller.getFileFromId(fileID); //drawable db Category oldCat = file.getCategory(); + // remove file from old category group - controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.CATEGORY, oldCat), fileID); //memory + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.CATEGORY, oldCat), fileID); //memory //remove old category tag if necessary - List allContentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(file); //tsk db + List allContentTags = sleuthKitCase.getContentTagsByContent(file); //tsk db + for (ContentTag ct : allContentTags) { //this is bad: treating tags as categories as long as their names start with prefix //TODO: abandon using tags for categories and instead add a new column to DrawableDB if (ct.getName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { - Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(ct); //tsk db - controller.getCategoryManager().decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db + sleuthKitCase.deleteContentTag(ct); //tsk db + categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db } - } - controller.getCategoryManager().incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db - if (tagName != Category.ZERO.getTagName()) { // no tags for cat-0 - Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment); //tsk db + categoryManager.incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db + if (tagName != categoryManager.getTagName(Category.ZERO)) { // no tags for cat-0 + controller.getTagsManager().addContentTag(file, tagName, comment); //tsk db } //make sure rest of ui hears category change. - controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui + groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error categorizing result", ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java similarity index 66% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java index 0fe88de953..38a8e40256 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java @@ -19,17 +19,16 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.Collections; -import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -39,21 +38,26 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** + * Action to delete the follow up tag a + * * */ -public class DeleteFollowUpTag extends Action { +public class DeleteTagAction extends Action { - private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTag.class.getName()); + private static final Logger LOGGER = Logger.getLogger(DeleteTagAction.class.getName()); private final long fileID; private final DrawableFile file; + private final ImageGalleryController controller; + private final ContentTag tag; - public DeleteFollowUpTag(DrawableFile file) { + public DeleteTagAction(ImageGalleryController controller, DrawableFile file, ContentTag tag) { super("Delete Follow Up Tag"); + this.controller = controller; this.file = file; this.fileID = file.getId(); - + this.tag = tag; setEventHandler((ActionEvent t) -> { - deleteFollowupTag(); + deleteTag(); }); } @@ -63,24 +67,26 @@ public class DeleteFollowUpTag extends Action { * * @throws IllegalStateException */ - private void deleteFollowupTag() throws IllegalStateException { + private void deleteTag() throws IllegalStateException { - final ImageGalleryController controller = ImageGalleryController.getDefault(); final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + final GroupManager groupManager = controller.getGroupManager(); + try { // remove file from old category group - controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); - - List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { - sleuthKitCase.deleteContentTag(ct); - } - } + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, tag.getName()), fileID); + sleuthKitCase.deleteContentTag(tag); +// +// List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); +// for (ContentTag ct : contentTagsByContent) { +// if (ct.getName().getDisplayName().equals(tagsManager.getFollowUpTagName().getDisplayName())) { +// sleuthKitCase.deleteContentTag(ct); +// } +// } IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS //make sure rest of ui hears category change. - controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 4839537731..0ded98426f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -20,14 +20,10 @@ package org.sleuthkit.autopsy.imagegallery.datamodel; import java.util.Map; import java.util.function.Function; -import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; import javafx.scene.paint.Color; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; /** * Enum to represent the six categories in the DHs image categorization scheme. @@ -101,19 +97,4 @@ public enum Category implements Comparable { return displayName; } - /** - * get the TagName used to store this Category in the main autopsy db. - * - * @return the TagName used for this Category - */ - public TagName getTagName() { - if (tagName == null) { - try { - tagName = TagUtils.getTagName(displayName); - } catch (TskCoreException ex) { - Logger.getLogger(Category.class.getName()).log(Level.SEVERE, "failed to get TagName for " + displayName, ex); - } - } - return tagName; - } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java index f53acac5f5..9896325e09 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java @@ -29,16 +29,16 @@ import javax.annotation.concurrent.Immutable; @Immutable public class CategoryChangeEvent { - private final Collection ids; + private final Collection fileIDs; /** * @return the fileIDs of the files whose categories have changed */ - public Collection getIds() { - return Collections.unmodifiableCollection(ids); + public Collection getFileIDs() { + return Collections.unmodifiableCollection(fileIDs); } - public CategoryChangeEvent(Collection ids) { - this.ids = ids; + public CategoryChangeEvent(Collection fileIDs) { + this.fileIDs = fileIDs; } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index f6e0404c6e..08ba1b17a5 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -26,7 +26,8 @@ import java.util.Collection; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.datamodel.TagName; /** * Provides a cached view of the number of files per category, and fires @@ -43,6 +44,7 @@ import org.sleuthkit.autopsy.imagegallery.TagUtils; public class CategoryManager { private static final java.util.logging.Logger LOGGER = Logger.getLogger(CategoryManager.class.getName()); + private final ImageGalleryController controller; /** * the DrawableDB that backs the category counts cache. The counts are @@ -63,6 +65,20 @@ public class CategoryManager { */ private final LoadingCache categoryCounts = CacheBuilder.newBuilder().build(CacheLoader.from(this::getCategoryCountHelper)); + /** + * cached TagNames corresponding to Categories, looked up from + * autopsyTagManager at initial request or if invalidated by case change. + */ + private final LoadingCache catTagNameMap = CacheBuilder.newBuilder().build(CacheLoader.from(cat + -> getController().getTagsManager().getTagName(cat))); + + public CategoryManager(ImageGalleryController controller) { + this.controller = controller; + } + + private ImageGalleryController getController() { + return controller; + } /** * assign a new db. the counts cache is invalidated and all subsequent db @@ -75,8 +91,8 @@ public class CategoryManager { public void setDb(DrawableDB db) { this.db = db; categoryCounts.invalidateAll(); + catTagNameMap.invalidateAll(); Category.clearTagNames(); - TagUtils.clearFollowUpTagName(); } /** @@ -171,4 +187,13 @@ public class CategoryManager { categoryEventBus.unregister(listener); } + /** + * get the TagName used to store this Category in the main autopsy db. + * + * @return the TagName used for this Category + */ + public TagName getTagName(Category cat) { + return catTagNameMap.getUnchecked(cat); + + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index ac1f6c99eb..b043bf126d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -47,6 +47,7 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; @@ -147,6 +148,7 @@ public final class DrawableDB { } } private final SleuthkitCase tskCase; + private final ImageGalleryController controller; //////////////general database logic , mostly borrowed from sleuthkitcase /** @@ -195,9 +197,10 @@ public final class DrawableDB { * * @throws SQLException if there is problem creating or configuring the db */ - private DrawableDB(Path dbPath, SleuthkitCase tskCase) throws SQLException, ExceptionInInitializerError, IOException { + private DrawableDB(Path dbPath, ImageGalleryController controller) throws SQLException, ExceptionInInitializerError, IOException { this.dbPath = dbPath; - this.tskCase = tskCase; + this.controller = controller; + this.tskCase = controller.getSleuthKitCase(); Files.createDirectories(dbPath.getParent()); if (initializeDBSchema()) { updateFileStmt = prepareStatement( @@ -286,10 +289,10 @@ public final class DrawableDB { * * @return */ - public static DrawableDB getDrawableDB(Path dbPath, SleuthkitCase tskCase) { + public static DrawableDB getDrawableDB(Path dbPath, ImageGalleryController controller) { try { - return new DrawableDB(dbPath.resolve("drawable.db"), tskCase); + return new DrawableDB(dbPath.resolve("drawable.db"), controller); } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "sql error creating database connection", ex); return null; @@ -1055,7 +1058,7 @@ public final class DrawableDB { public List> getFilesWithCategory(Category cat) throws TskCoreException, IllegalArgumentException { try { List> files = new ArrayList<>(); - List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(cat.getTagName()); + List contentTags = tskCase.getContentTagsByTagName(controller.getTagsManager().getTagName(cat)); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile) { files.add(DrawableFile.create((AbstractFile) ct.getContent(), isFileAnalyzed(ct.getContent().getId()), @@ -1240,7 +1243,7 @@ public final class DrawableDB { */ public long getCategoryCount(Category cat) { try { - return Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(cat.getTagName()).stream() + return tskCase.getContentTagsByTagName(controller.getTagsManager().getTagName(cat)).stream() .map(ContentTag::getContent) .map(Content::getId) .filter(this::isInDB) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java index 789cac7375..cd41534078 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java @@ -56,7 +56,7 @@ public class GroupKey> implements Comparable @Override public String toString() { - return "GroupKey: " + getAttribute() + " = " + getValue(); + return "GroupKey: " + getAttribute().attrName + " = " + getValue(); } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 68e1044dbc..dab1f9743f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -34,6 +34,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; +import java.util.stream.Stream; import javafx.application.Platform; import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleWrapper; @@ -51,10 +52,10 @@ import org.sleuthkit.autopsy.coreutils.LoggedTask; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; @@ -486,31 +487,34 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public Set getFileIDsWithCategory(Category category) throws TskCoreException { try { + final DrawableTagsManager tagsManager = controller.getTagsManager(); if (category == Category.ZERO) { + List< TagName> tns = Stream.of(Category.ONE, Category.TWO, Category.THREE, Category.FOUR, Category.FIVE) + .map(tagsManager::getTagName) + .collect(Collectors.toList()); Set files = new HashSet<>(); - TagName[] tns = {Category.FOUR.getTagName(), Category.THREE.getTagName(), Category.TWO.getTagName(), Category.ONE.getTagName(), Category.FIVE.getTagName()}; for (TagName tn : tns) { - List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tn); - for (ContentTag ct : contentTags) { - if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { - files.add(ct.getContent().getId()); - } + if (tn != null) { + List contentTags = tagsManager.getContentTagsByTagName(tn); + files.addAll(contentTags.stream() + .filter(ct -> ct.getContent() instanceof AbstractFile) + .filter(ct -> db.isInDB(ct.getContent().getId())) + .map(ct -> ct.getContent().getId()) + .collect(Collectors.toSet())); } } return db.findAllFileIdsWhere("obj_id NOT IN (" + StringUtils.join(files, ',') + ")"); } else { - Set files = new HashSet<>(); - List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(category.getTagName()); - for (ContentTag ct : contentTags) { - if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { - files.add(ct.getContent().getId()); - } - } + List contentTags = tagsManager.getContentTagsByTagName(tagsManager.getTagName(category)); + return contentTags.stream() + .filter(ct -> ct.getContent() instanceof AbstractFile) + .filter(ct -> db.isInDB(ct.getContent().getId())) + .map(ct -> ct.getContent().getId()) + .collect(Collectors.toSet()); - return files; } } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "TSK error getting files in Category:" + category.getDisplayName(), ex); @@ -688,7 +692,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { controller.getCategoryManager().fireChange(fileIDs); if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { - TagUtils.fireChange(fileIDs); + controller.getTagsManager().fireChange(fileIDs); } break; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java index 80f16a3d7a..75332ba158 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java @@ -32,7 +32,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableViewBase.globalSelectionModel; /** @@ -43,7 +42,7 @@ import static org.sleuthkit.autopsy.imagegallery.gui.DrawableViewBase.globalSele * * TODO: refactor this to extend from {@link Control}? -jm */ -public class DrawableTile extends DrawableViewBase implements TagUtils.TagListener { +public class DrawableTile extends DrawableViewBase { private static final DropShadow LAST_SELECTED_EFFECT = new DropShadow(10, Color.BLUE); @@ -73,8 +72,8 @@ public class DrawableTile extends DrawableViewBase implements TagUtils.TagListen setCacheHint(CacheHint.SPEED); nameLabel.prefWidthProperty().bind(imageView.fitWidthProperty()); - imageView.fitHeightProperty().bind(Toolbar.getDefault().sizeSliderValue()); - imageView.fitWidthProperty().bind(Toolbar.getDefault().sizeSliderValue()); + imageView.fitHeightProperty().bind(Toolbar.getDefault(getController()).sizeSliderValue()); + imageView.fitWidthProperty().bind(Toolbar.getDefault(getController()).sizeSliderValue()); globalSelectionModel.lastSelectedProperty().addListener((observable, oldValue, newValue) -> { try { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 8f91cdf932..ed0453ec0b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -1,7 +1,6 @@ package org.sleuthkit.autopsy.imagegallery.gui; import com.google.common.eventbus.Subscribe; -import java.util.Collection; import java.util.logging.Level; import javafx.application.Platform; import javafx.scene.layout.Border; @@ -13,7 +12,8 @@ import javafx.scene.layout.Region; import javafx.scene.paint.Color; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; @@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; * } to have there {@link DrawableView#handleCategoryChanged(org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent) * } method invoked */ -public interface DrawableView extends TagUtils.TagListener { +public interface DrawableView { //TODO: do this all in css? -jm static final int CAT_BORDER_WIDTH = 10; @@ -67,8 +67,10 @@ public interface DrawableView extends TagUtils.TagListener { @Subscribe void handleCategoryChanged(CategoryChangeEvent evt); - @Override - void handleTagsChanged(Collection ids); + @Subscribe + void handleTagsChanged(TagsChangeEvent evt); + + ImageGalleryController getController(); default boolean hasHashHit() { try { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index e866742505..7f29af775e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -64,10 +64,10 @@ import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; -import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; -import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTag; +import org.sleuthkit.autopsy.imagegallery.actions.DeleteTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -138,6 +138,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie */ final private GroupPane groupPane; private boolean registered = false; + private final ImageGalleryController controller; GroupPane getGroupPane() { return groupPane; @@ -145,6 +146,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie protected DrawableViewBase(GroupPane groupPane) { this.groupPane = groupPane; + this.controller = groupPane.getController(); globalSelectionModel.getSelected().addListener((Observable observable) -> { updateSelectionState(); }); @@ -194,9 +196,9 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie private ContextMenu buildContextMenu() { final ArrayList menuItems = new ArrayList<>(); - menuItems.add(CategorizeAction.getPopupMenu()); + menuItems.add(new CategorizeAction(controller).getPopupMenu()); - menuItems.add(AddDrawableTagAction.getInstance().getPopupMenu()); + menuItems.add(new AddDrawableTagAction(controller).getPopupMenu()); final MenuItem extractMenuItem = new MenuItem("Extract File(s)"); extractMenuItem.setOnAction((ActionEvent t) -> { @@ -260,43 +262,16 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie if (followUpToggle.isSelected() == true) { globalSelectionModel.clearAndSelect(fileID); try { - AddDrawableTagAction.getInstance().addTag(TagUtils.getFollowUpTagName(), ""); + new AddDrawableTagAction(controller).addTag(ImageGalleryController.getDefault().getTagsManager().getFollowUpTagName(), ""); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to add follow up tag. Could not load TagName.", ex); } } else { - new DeleteFollowUpTag(file).handle(t); -// deleteFollowupTag(fileID); + new DeleteTagAction(controller, file).handle(t); } }); } -// /** -// * -// * @param fileID1 the value of fileID1 -// * -// * @throws IllegalStateException -// */ -// private void deleteFollowupTag(final Long fileID1) throws IllegalStateException { -// //TODO: convert this to an action! -// final ImageGalleryController controller = ImageGalleryController.getDefault(); -// try { -// // remove file from old category group -// controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID1); -// -// List contentTagsByContent = controller.getSleuthKitCase().getContentTagsByContent(file); -// for (ContentTag ct : contentTagsByContent) { -// if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { -// controller.getSleuthKitCase().deleteContentTag(ct); -// } -// } -// IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS -// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID1), DrawableAttribute.TAGS)); -// } catch (TskCoreException ex) { -// LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); -// } -// } - @Override public DrawableFile getFile() { if (fileID != null) { @@ -315,7 +290,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie } protected boolean hasFollowUp() throws TskCoreException { - String followUpTagName = TagUtils.getFollowUpTagName().getDisplayName(); + String followUpTagName = ImageGalleryController.getDefault().getTagsManager().getFollowUpTagName().getDisplayName(); Collection tagNames = DrawableAttribute.TAGS.getValue(getFile()); return tagNames.stream().anyMatch((tn) -> tn.getDisplayName().equals(followUpTagName)); } @@ -326,8 +301,8 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie } @Override - synchronized public void handleTagsChanged(Collection ids) { - if (fileID != null && ids.contains(fileID)) { + synchronized public void handleTagsChanged(TagsChangeEvent evnt) { + if (fileID != null && evnt.getFileIDs().contains(fileID)) { updateFollowUpIcon(); } } @@ -354,8 +329,8 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie if (this.fileID == null || Case.isCaseOpen() == false) { if (registered == true) { - ImageGalleryController.getDefault().getCategoryManager().unregisterListener(this); - TagUtils.unregisterListener(this); + getController().getCategoryManager().unregisterListener(this); + getController().getTagsManager().unregisterListener(this); registered = false; } file = null; @@ -364,8 +339,8 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie }); } else { if (registered == false) { - ImageGalleryController.getDefault().getCategoryManager().registerListener(this); - TagUtils.registerListener(this); + getController().getCategoryManager().registerListener(this); + getController().getTagsManager().registerListener(this); registered = true; } file = null; @@ -411,8 +386,13 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { - if (evt.getIds().contains(getFileID())) { + if (evt.getFileIDs().contains(getFileID())) { updateCategoryBorder(); } } + + @Override + public ImageGalleryController getController() { + return controller; + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java index 30dcf743fb..09042abaf4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java @@ -100,11 +100,11 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.Back; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; @@ -277,7 +277,7 @@ public class GroupPane extends BorderPane implements GroupView { @Override public void handle(ActionEvent t) { Set fileIdSet = new HashSet<>(getGrouping().fileIds()); - new CategorizeAction().addTagsToFiles(cat.getTagName(), "", fileIdSet); + new CategorizeAction(controller).addTagsToFiles(controller.getTagsManager().getTagName(cat), "", fileIdSet); grpCatSplitMenu.setText(cat.getDisplayName()); grpCatSplitMenu.setOnAction(this); @@ -292,7 +292,7 @@ public class GroupPane extends BorderPane implements GroupView { @Override public void handle(ActionEvent t) { Set fileIdSet = new HashSet<>(getGrouping().fileIds()); - AddDrawableTagAction.getInstance().addTagsToFiles(tn, "", fileIdSet); + new AddDrawableTagAction(controller).addTagsToFiles(tn, "", fileIdSet); grpTagSplitMenu.setText(tn.getDisplayName()); grpTagSplitMenu.setOnAction(this); @@ -340,8 +340,8 @@ public class GroupPane extends BorderPane implements GroupView { flashAnimation.setAutoReverse(true); //configure gridView cell properties - gridView.cellHeightProperty().bind(Toolbar.getDefault().sizeSliderValue().add(75)); - gridView.cellWidthProperty().bind(Toolbar.getDefault().sizeSliderValue().add(75)); + gridView.cellHeightProperty().bind(Toolbar.getDefault(controller).sizeSliderValue().add(75)); + gridView.cellWidthProperty().bind(Toolbar.getDefault(controller).sizeSliderValue().add(75)); gridView.setCellFactory((GridView param) -> new DrawableCell()); //configure toolbar properties @@ -349,8 +349,8 @@ public class GroupPane extends BorderPane implements GroupView { spacer.setMinWidth(Region.USE_PREF_SIZE); try { - grpTagSplitMenu.setText(TagUtils.getFollowUpTagName().getDisplayName()); - grpTagSplitMenu.setOnAction(createGrpTagMenuItem(TagUtils.getFollowUpTagName()).getOnAction()); + grpTagSplitMenu.setText(getController().getTagsManager().getFollowUpTagName().getDisplayName()); + grpTagSplitMenu.setOnAction(createGrpTagMenuItem(getController().getTagsManager().getFollowUpTagName()).getOnAction()); } catch (TskCoreException tskCoreException) { LOGGER.log(Level.WARNING, "failed to load FollowUpTagName", tskCoreException); } @@ -358,8 +358,8 @@ public class GroupPane extends BorderPane implements GroupView { grpTagSplitMenu.showingProperty().addListener((ObservableValue ov, Boolean t, Boolean t1) -> { if (t1) { ArrayList selTagMenues = new ArrayList<>(); - for (final TagName tn : TagUtils.getNonCategoryTagNames()) { - MenuItem menuItem = TagUtils.createSelTagMenuItem(tn, grpTagSplitMenu); + for (final TagName tn : getController().getTagsManager().getNonCategoryTagNames()) { + MenuItem menuItem = GuiUtils.createSelTagMenuItem(tn, grpTagSplitMenu, controller); selTagMenues.add(menuItem); } grpTagSplitMenu.getItems().setAll(selTagMenues); @@ -419,9 +419,8 @@ public class GroupPane extends BorderPane implements GroupView { private ContextMenu buildContextMenu() { ArrayList menuItems = new ArrayList<>(); - menuItems.add(CategorizeAction.getPopupMenu()); - - menuItems.add(AddDrawableTagAction.getInstance().getPopupMenu()); + menuItems.add(new CategorizeAction(controller).getPopupMenu()); + menuItems.add(new AddDrawableTagAction(controller).getPopupMenu()); Collection menuProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class); @@ -653,6 +652,10 @@ public class GroupPane extends BorderPane implements GroupView { } } + ImageGalleryController getController() { + return controller; + } + private class DrawableCell extends GridCell { private final DrawableTile tile = new DrawableTile(GroupPane.this); @@ -751,27 +754,27 @@ public class GroupPane extends BorderPane implements GroupView { switch (t.getCode()) { case NUMPAD0: case DIGIT0: - new CategorizeAction().addTag(Category.ZERO.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.ZERO), ""); break; case NUMPAD1: case DIGIT1: - new CategorizeAction().addTag(Category.ONE.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.ONE), ""); break; case NUMPAD2: case DIGIT2: - new CategorizeAction().addTag(Category.TWO.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.TWO), ""); break; case NUMPAD3: case DIGIT3: - new CategorizeAction().addTag(Category.THREE.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.THREE), ""); break; case NUMPAD4: case DIGIT4: - new CategorizeAction().addTag(Category.FOUR.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.FOUR), ""); break; case NUMPAD5: case DIGIT5: - new CategorizeAction().addTag(Category.FIVE.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(Category.FIVE), ""); break; } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java new file mode 100644 index 0000000000..4a2a84fd46 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GuiUtils.java @@ -0,0 +1,62 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery.gui; + +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.scene.control.MenuItem; +import javafx.scene.control.SplitMenuButton; +import javafx.scene.image.ImageView; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.datamodel.TagName; + +/** + * Static utility methods for working with GUI components + */ +public class GuiUtils { + + /** + * make a new menu item that when clicked, tags the selected files with the + * given tagname + * + * @param tagName + * @param tagSelectedMenuButton + * @param controller + * + * @return + */ + public static MenuItem createSelTagMenuItem(final TagName tagName, final SplitMenuButton tagSelectedMenuButton, ImageGalleryController controller) { + final MenuItem menuItem = new MenuItem(tagName.getDisplayName(), new ImageView(DrawableAttribute.TAGS.getIcon())); + menuItem.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent t) { + new AddDrawableTagAction(controller).addTag(tagName, ""); + tagSelectedMenuButton.setText(tagName.getDisplayName()); + tagSelectedMenuButton.setOnAction(this); + } + }); + return menuItem; + } + + private GuiUtils() { + } + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index b4319ac815..f9f6115d67 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -45,7 +45,7 @@ import javafx.util.Pair; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -56,12 +56,17 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Shows details of the selected file. */ -public class MetaDataPane extends AnchorPane implements TagUtils.TagListener, DrawableView { +public class MetaDataPane extends AnchorPane implements DrawableView { private static final Logger LOGGER = Logger.getLogger(MetaDataPane.class.getName()); private final ImageGalleryController controller; + @Override + public ImageGalleryController getController() { + return controller; + } + private Long fileID; @FXML @@ -92,8 +97,8 @@ public class MetaDataPane extends AnchorPane implements TagUtils.TagListener, Dr assert imageView != null : "fx:id=\"imageView\" was not injected: check your FXML file 'MetaDataPane.fxml'."; assert tableView != null : "fx:id=\"tableView\" was not injected: check your FXML file 'MetaDataPane.fxml'."; assert valueColumn != null : "fx:id=\"valueColumn\" was not injected: check your FXML file 'MetaDataPane.fxml'."; - TagUtils.registerListener(this); - ImageGalleryController.getDefault().getCategoryManager().registerListener(this); + getController().getTagsManager().registerListener(this); + getController().getCategoryManager().registerListener(this); tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); tableView.setPlaceholder(new Label("Select a file to show its details here.")); @@ -224,14 +229,15 @@ public class MetaDataPane extends AnchorPane implements TagUtils.TagListener, Dr @Subscribe @Override public void handleCategoryChanged(CategoryChangeEvent evt) { - if (getFile() != null && evt.getIds().contains(getFileID())) { + if (getFile() != null && evt.getFileIDs().contains(getFileID())) { updateUI(); } } @Override - public void handleTagsChanged(Collection ids) { - if (getFile() != null && ids.contains(getFileID())) { + @Subscribe + public void handleTagsChanged(TagsChangeEvent evt) { + if (getFile() != null && evt.getFileIDs().contains(getFileID())) { updateUI(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index 88467e1973..7977eb0219 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -48,9 +48,9 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -66,7 +66,7 @@ import org.sleuthkit.datamodel.TskCoreException; * GroupPane. TODO: Extract a subclass for video files in slideshow mode-jm * TODO: reduce coupling to GroupPane */ -public class SlideShowView extends DrawableViewBase implements TagUtils.TagListener { +public class SlideShowView extends DrawableViewBase { private static final Logger LOGGER = Logger.getLogger(SlideShowView.class.getName()); @@ -127,7 +127,7 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe tagSplitButton.setOnAction((ActionEvent t) -> { try { - TagUtils.createSelTagMenuItem(TagUtils.getFollowUpTagName(), tagSplitButton).getOnAction().handle(t); + GuiUtils.createSelTagMenuItem(getController().getTagsManager().getFollowUpTagName(), tagSplitButton, getController()).getOnAction().handle(t); } catch (TskCoreException ex) { Exceptions.printStackTrace(ex); } @@ -137,8 +137,8 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe tagSplitButton.showingProperty().addListener((ObservableValue ov, Boolean t, Boolean t1) -> { if (t1) { ArrayList selTagMenues = new ArrayList<>(); - for (final TagName tn : TagUtils.getNonCategoryTagNames()) { - MenuItem menuItem = TagUtils.createSelTagMenuItem(tn, tagSplitButton); + for (final TagName tn : getController().getTagsManager().getNonCategoryTagNames()) { + MenuItem menuItem = GuiUtils.createSelTagMenuItem(tn, tagSplitButton, getController()); selTagMenues.add(menuItem); } tagSplitButton.getItems().setAll(selTagMenues); @@ -347,7 +347,7 @@ public class SlideShowView extends DrawableViewBase implements TagUtils.TagListe public void changed(ObservableValue ov, Boolean t, Boolean t1) { if (t1) { FileIDSelectionModel.getInstance().clearAndSelect(getFileID()); - new CategorizeAction().addTag(cat.getTagName(), ""); + new CategorizeAction(getController()).addTag(getController().getTagsManager().getTagName(cat), ""); } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index bf62f89084..2131ff73fc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -41,10 +41,10 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javax.swing.SortOrder; import org.openide.util.Exceptions; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.ThumbnailCache; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; @@ -105,6 +105,7 @@ public class Toolbar extends ToolBar { ImageGalleryController.getDefault().getGroupManager().regroup(groupByBox.getSelectionModel().getSelectedItem(), sortByBox.getSelectionModel().getSelectedItem(), getSortOrder(), false); }; + private ImageGalleryController controller; synchronized public SortOrder getSortOrder() { return orderProperty.get(); @@ -117,9 +118,9 @@ public class Toolbar extends ToolBar { return sizeSlider.valueProperty(); } - static synchronized public Toolbar getDefault() { + static synchronized public Toolbar getDefault(ImageGalleryController controller) { if (instance == null) { - instance = new Toolbar(); + instance = new Toolbar(controller); } return instance; } @@ -151,7 +152,7 @@ public class Toolbar extends ToolBar { tagSelectedMenuButton.setOnAction((ActionEvent t) -> { try { - TagUtils.createSelTagMenuItem(TagUtils.getFollowUpTagName(), tagSelectedMenuButton).getOnAction().handle(t); + GuiUtils.createSelTagMenuItem(getController().getTagsManager().getFollowUpTagName(), tagSelectedMenuButton, getController()).getOnAction().handle(t); } catch (TskCoreException ex) { Exceptions.printStackTrace(ex); } @@ -161,22 +162,22 @@ public class Toolbar extends ToolBar { tagSelectedMenuButton.showingProperty().addListener((ObservableValue ov, Boolean t, Boolean t1) -> { if (t1) { ArrayList selTagMenues = new ArrayList<>(); - for (final TagName tn : TagUtils.getNonCategoryTagNames()) { - MenuItem menuItem = TagUtils.createSelTagMenuItem(tn, tagSelectedMenuButton); + for (final TagName tn : getController().getTagsManager().getNonCategoryTagNames()) { + MenuItem menuItem = GuiUtils.createSelTagMenuItem(tn, tagSelectedMenuButton, getController()); selTagMenues.add(menuItem); } tagSelectedMenuButton.getItems().setAll(selTagMenues); } }); - catSelectedMenuButton.setOnAction(createSelCatMenuItem(Category.FIVE, catSelectedMenuButton).getOnAction()); + catSelectedMenuButton.setOnAction(createSelCatMenuItem(Category.FIVE, catSelectedMenuButton, getController()).getOnAction()); catSelectedMenuButton.setText(Category.FIVE.getDisplayName()); catSelectedMenuButton.setGraphic(new ImageView(DrawableAttribute.CATEGORY.getIcon())); catSelectedMenuButton.showingProperty().addListener((ObservableValue ov, Boolean t, Boolean t1) -> { if (t1) { ArrayList categoryMenues = new ArrayList<>(); for (final Category cat : Category.values()) { - MenuItem menuItem = createSelCatMenuItem(cat, catSelectedMenuButton); + MenuItem menuItem = createSelCatMenuItem(cat, catSelectedMenuButton, getController()); categoryMenues.add(menuItem); } catSelectedMenuButton.getItems().setAll(categoryMenues); @@ -221,20 +222,25 @@ public class Toolbar extends ToolBar { }); } - private Toolbar() { + private Toolbar(ImageGalleryController controller) { + this.controller = controller; FXMLConstructor.construct(this, "Toolbar.fxml"); } - private static MenuItem createSelCatMenuItem(Category cat, final SplitMenuButton catSelectedMenuButton) { + private static MenuItem createSelCatMenuItem(Category cat, final SplitMenuButton catSelectedMenuButton, ImageGalleryController controller) { final MenuItem menuItem = new MenuItem(cat.getDisplayName(), new ImageView(DrawableAttribute.CATEGORY.getIcon())); menuItem.setOnAction(new EventHandler() { @Override public void handle(ActionEvent t) { - new CategorizeAction().addTag(cat.getTagName(), ""); + new CategorizeAction(controller).addTag(controller.getTagsManager().getTagName(cat), ""); catSelectedMenuButton.setText(cat.getDisplayName()); catSelectedMenuButton.setOnAction(this); } }); return menuItem; } + + private ImageGalleryController getController() { + return controller; + } } From 16fe7db1e77baf08aeb53295400361fd56688519 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 17 Jun 2015 15:51:15 -0400 Subject: [PATCH 133/198] make sure all code is using the correct TagsManager (DrawableTagsManager) from controller; more cleanup --- .../imagegallery/DrawableTagsManager.java | 49 +++++++++++++++++-- .../imagegallery/ImageGalleryController.java | 39 ++++++++------- .../actions/AddDrawableTagAction.java | 3 +- .../imagegallery/actions/AddTagAction.java | 23 ++------- .../actions/CategorizeAction.java | 3 +- ...tion.java => DeleteFollowUpTagAction.java} | 43 ++++++++-------- .../imagegallery/datamodel/DrawableDB.java | 4 +- .../imagegallery/datamodel/DrawableFile.java | 10 ++-- .../imagegallery/grouping/GroupManager.java | 33 ++++++++++--- .../imagegallery/gui/DrawableViewBase.java | 16 +++--- 10 files changed, 134 insertions(+), 89 deletions(-) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/{DeleteTagAction.java => DeleteFollowUpTagAction.java} (69%) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 3c1dd42de3..7ba9ceb842 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -28,6 +28,10 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.ingest.IngestServices; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -45,7 +49,7 @@ public class DrawableTagsManager { /** Used to distribute {@link TagsChangeEvent}s */ private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); - /** The tag name corresponging to the "built-in" tag "Follow Up" */ + /** The tag name corresponding to the "built-in" tag "Follow Up" */ private TagName followUpTagName; public DrawableTagsManager(TagsManager autopsyTagsManager) { @@ -113,7 +117,7 @@ public class DrawableTagsManager { return followUpTagName; } - public Collection getNonCategoryTagNames() { + synchronized public Collection getNonCategoryTagNames() { try { return autopsyTagsManager.getAllTagNames().stream() .filter(Category::isCategoryTagName) @@ -124,6 +128,20 @@ public class DrawableTagsManager { return Collections.emptySet(); } + /** + * Gets content tags count by content. + * + * @param The content of interest. + * + * @return A list, possibly empty, of the tags that have been applied to the + * artifact. + * + * @throws TskCoreException + */ + public synchronized List getContentTagsByContent(Content content) throws TskCoreException { + return autopsyTagsManager.getContentTagsByContent(content); + } + public synchronized TagName getTagName(String displayName) throws TskCoreException { try { for (TagName tn : autopsyTagsManager.getAllTagNames()) { @@ -150,12 +168,35 @@ public class DrawableTagsManager { } } - public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { + synchronized public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { autopsyTagsManager.addContentTag(file, tagName, comment); } - public List getContentTagsByTagName(TagName t) throws TskCoreException { + synchronized public List getContentTagsByTagName(TagName t) throws TskCoreException { return autopsyTagsManager.getContentTagsByTagName(t); } + /** + * Fire the ModuleDataEvent that we use as a place holder for a real Tag + * Event. This is used to refresh the autopsy tag tree and the ui in + * ImageGallery + * + * + * Note: this is a hack. In an ideal world, TagsManager would fire + * events so that the directory tree would refresh. But, we haven't + * had a chance to add that so, we fire these events and the tree + * refreshes based on them. + */ + static public void fireTagsChangedEvent() { + + IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + } + + public synchronized List getAllTagNames() throws TskCoreException { + return autopsyTagsManager.getAllTagNames(); + } + + public synchronized List getTagNamesInUse() throws TskCoreException { + return autopsyTagsManager.getTagNamesInUse(); + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index ae7a169e96..4bed46a023 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.imagegallery; import java.beans.PropertyChangeEvent; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; @@ -134,6 +135,7 @@ public final class ImageGalleryController { private StackPane centralStackPane; private Node infoOverlay; + private SleuthkitCase sleuthKitCase; public ReadOnlyBooleanProperty getMetaDataCollapsed() { return metaDataCollapsed.getReadOnlyProperty(); @@ -345,20 +347,25 @@ public final class ImageGalleryController { * @param theNewCase the case to configure the controller for */ public synchronized void setCase(Case theNewCase) { - this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); + if (Objects.nonNull(theNewCase)) { + this.sleuthKitCase = theNewCase.getSleuthkitCase(); + this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); - setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); - setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); + setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); + setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); - // if we add this line icons are made as files are analyzed rather than on demand. - // db.addUpdatedFileListener(IconCache.getDefault()); - restartWorker(); - historyManager.clear(); - groupManager.setDB(db); - hashSetManager.setDb(db); - categoryManager.setDb(db); - tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); - SummaryTablePane.getDefault().refresh(); + // if we add this line icons are made as files are analyzed rather than on demand. + // db.addUpdatedFileListener(IconCache.getDefault()); + restartWorker(); + historyManager.clear(); + groupManager.setDB(db); + hashSetManager.setDb(db); + categoryManager.setDb(db); + tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); + SummaryTablePane.getDefault().refresh(); + } else { + reset(); + } } /** @@ -558,12 +565,8 @@ public final class ImageGalleryController { } } - public SleuthkitCase getSleuthKitCase() throws IllegalStateException { - if (Case.isCaseOpen()) { - return Case.getCurrentCase().getSleuthkitCase(); - } else { - throw new IllegalStateException("No Case is open!"); - } + public synchronized SleuthkitCase getSleuthKitCase() { + return sleuthKitCase; } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index 394f348466..9d5c5f277b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -28,6 +28,7 @@ import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.openide.util.Utilities; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -89,7 +90,7 @@ public class AddDrawableTagAction extends AddTagAction { //make sure rest of ui hears category change. controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } - refreshDirectoryTree(); + DrawableTagsManager.fireTagsChangedEvent(); return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 94fd9f070a..11fac7a403 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -27,14 +27,11 @@ import javafx.scene.control.MenuItem; import javax.swing.SwingUtilities; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -48,16 +45,6 @@ import org.sleuthkit.datamodel.TskCoreException; */ abstract class AddTagAction { - @SuppressWarnings("deprecation") - protected void refreshDirectoryTree() { - - /* Note: this is a hack. In an ideal world, TagsManager would fire - * events so that the directory tree would refresh. But, we haven't - * had a chance to add that so, we fire these events and the tree - * refreshes based on them. - */ - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - } protected static final String NO_COMMENT = ""; /** @@ -91,7 +78,7 @@ abstract class AddTagAction { super(getActionDisplayName()); // Get the current set of tag names. - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + DrawableTagsManager tagsManager = controller.getTagsManager(); List tagNames = null; try { tagNames = tagsManager.getAllTagNames(); @@ -112,7 +99,7 @@ abstract class AddTagAction { MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); tagNameItem.setOnAction((ActionEvent t) -> { addTag(tagName, NO_COMMENT); - refreshDirectoryTree(); + DrawableTagsManager.fireTagsChangedEvent(); }); quickTagMenu.getItems().add(tagNameItem); } @@ -133,7 +120,7 @@ abstract class AddTagAction { TagName tagName = GetTagNameDialog.doDialog(); if (tagName != null) { addTag(tagName, NO_COMMENT); - refreshDirectoryTree(); + } }); }); @@ -152,7 +139,7 @@ abstract class AddTagAction { } else { new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } - refreshDirectoryTree(); + } }); }); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 358516694e..b3bb065644 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -30,6 +30,7 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -159,7 +160,7 @@ public class CategorizeAction extends AddTagAction { JOptionPane.showMessageDialog(null, "Unable to categorize " + fileID + ".", "Categorizing Error", JOptionPane.ERROR_MESSAGE); } - refreshDirectoryTree(); + DrawableTagsManager.fireTagsChangedEvent(); } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java similarity index 69% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 38a8e40256..6a1a54c30d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -19,19 +19,18 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.Collections; +import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; @@ -39,23 +38,19 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Action to delete the follow up tag a - * - * */ -public class DeleteTagAction extends Action { +public class DeleteFollowUpTagAction extends Action { - private static final Logger LOGGER = Logger.getLogger(DeleteTagAction.class.getName()); + private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTagAction.class.getName()); private final long fileID; private final DrawableFile file; private final ImageGalleryController controller; - private final ContentTag tag; - public DeleteTagAction(ImageGalleryController controller, DrawableFile file, ContentTag tag) { + public DeleteFollowUpTagAction(ImageGalleryController controller, DrawableFile file) { super("Delete Follow Up Tag"); this.controller = controller; this.file = file; this.fileID = file.getId(); - this.tag = tag; setEventHandler((ActionEvent t) -> { deleteTag(); }); @@ -63,27 +58,28 @@ public class DeleteTagAction extends Action { /** * - * @param fileID1 the value of fileID1 * - * @throws IllegalStateException + * */ - private void deleteTag() throws IllegalStateException { + private void deleteTag() { final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); final GroupManager groupManager = controller.getGroupManager(); + final DrawableTagsManager tagsManager = controller.getTagsManager(); try { + final TagName followUpTagName = tagsManager.getFollowUpTagName(); // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, tag.getName()), fileID); - sleuthKitCase.deleteContentTag(tag); -// -// List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); -// for (ContentTag ct : contentTagsByContent) { -// if (ct.getName().getDisplayName().equals(tagsManager.getFollowUpTagName().getDisplayName())) { -// sleuthKitCase.deleteContentTag(ct); -// } -// } - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); + + List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); + for (ContentTag ct : contentTagsByContent) { + if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { + sleuthKitCase.deleteContentTag(ct); + } + } + + DrawableTagsManager.fireTagsChangedEvent(); //make sure rest of ui hears category change. groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); @@ -91,4 +87,5 @@ public class DeleteTagAction extends Action { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index b043bf126d..49b0818e3b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -1058,7 +1058,7 @@ public final class DrawableDB { public List> getFilesWithCategory(Category cat) throws TskCoreException, IllegalArgumentException { try { List> files = new ArrayList<>(); - List contentTags = tskCase.getContentTagsByTagName(controller.getTagsManager().getTagName(cat)); + List contentTags = controller.getTagsManager().getContentTagsByTagName(controller.getTagsManager().getTagName(cat)); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile) { files.add(DrawableFile.create((AbstractFile) ct.getContent(), isFileAnalyzed(ct.getContent().getId()), @@ -1145,7 +1145,7 @@ public final class DrawableDB { * in. * * - * //TODO: why does this go to the SKC? don't we already have this in =fo + * //TODO: why does this go to the SKC? don't we already have this info * in the drawable db? */ @Nonnull diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 78bb8c6401..bd4c84dd5e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -170,19 +170,16 @@ public abstract class DrawableFile extends AbstractFile public Set getTagNames() { try { - List contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(this); - return contentTagsByContent.stream() + return getSleuthkitCase().getContentTagsByContent(this).stream() .map(Tag::getName) .collect(Collectors.toSet()); - } catch (TskCoreException ex) { Logger.getAnonymousLogger().log(Level.WARNING, "problem looking up " + DrawableAttribute.TAGS.getDisplayName() + " for " + file.getName(), ex); - return Collections.emptySet(); } catch (IllegalStateException ex) { Logger.getAnonymousLogger().log(Level.WARNING, "there is no case open; failed to look up " + DrawableAttribute.TAGS.getDisplayName() + " for " + file.getName()); - return Collections.emptySet(); } + return Collections.emptySet(); } @Deprecated @@ -275,7 +272,8 @@ public abstract class DrawableFile extends AbstractFile public void updateCategory() { try { - List contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(this); + + List contentTagsByContent = getSleuthkitCase().getContentTagsByContent(this); Category cat = null; for (ContentTag ct : contentTagsByContent) { if (ct.getName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index dab1f9743f..221c7ef4d1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -40,6 +40,9 @@ import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; import javax.swing.SortOrder; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -80,11 +83,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { private DrawableDB db; private final ImageGalleryController controller; + /** * map from {@link GroupKey}s to {@link DrawableGroup}s. All groups (even - * not - * fully analyzed or not visible groups could be in this map + * not fully analyzed or not visible groups could be in this map */ + @GuardedBy("this") private final Map, DrawableGroup> groupMap = new HashMap<>(); /** @@ -153,7 +157,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { Set> resultSet = new HashSet<>(); for (Comparable val : groupBy.getValue(file)) { if (groupBy == DrawableAttribute.TAGS) { - if (((TagName) val).getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) { + if (Category.isCategoryTagName((TagName) val) == false) { resultSet.add(new GroupKey(groupBy, val)); } } else { @@ -189,9 +193,24 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * or * null if no group exists for that key. */ - public DrawableGroup getGroupForKey(GroupKey groupKey) { + @Nullable + public DrawableGroup getGroupForKey(@Nonnull GroupKey groupKey) { synchronized (groupMap) { + if (groupKey.getAttribute() == DrawableAttribute.TAGS) { + + System.out.println(groupKey); +// @SuppressWarnings("unchecked") +// GroupKey tagKey = (GroupKey) groupKey; +// +// return groupMap.keySet().stream() +// .filter((GroupKey t) -> t.getAttribute() == DrawableAttribute.TAGS) +// .map((GroupKey t) -> (GroupKey) t) +// .filter(t -> tagKey.getValue().getDisplayName().equals(t.getValue().getDisplayName())) +// .findFirst().map(groupMap::get).orElse(null); + + } //else { return groupMap.get(groupKey); +// } } } @@ -443,7 +462,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { values = (List) Arrays.asList(Category.values()); break; case TAGS: - values = (List) Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse().stream() + values = (List) controller.getTagsManager().getTagNamesInUse().stream() .filter(t -> t.getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) .collect(Collectors.toList()); break; @@ -525,14 +544,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public Set getFileIDsWithTag(TagName tagName) throws TskCoreException { try { Set files = new HashSet<>(); - List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName); + List contentTags = controller.getTagsManager().getContentTagsByTagName(tagName); for (ContentTag ct : contentTags) { if (ct.getContent() instanceof AbstractFile && db.isInDB(ct.getContent().getId())) { - files.add(ct.getContent().getId()); } } - return files; } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "TSK error getting files with Tag:" + tagName.getDisplayName(), ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 7f29af775e..52ac70def0 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -67,7 +67,7 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; -import org.sleuthkit.autopsy.imagegallery.actions.DeleteTagAction; +import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -257,17 +257,17 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @SuppressWarnings("deprecation") protected void initialize() { - followUpToggle.setOnAction((ActionEvent t) -> { - + followUpToggle.setOnAction((ActionEvent event) -> { if (followUpToggle.isSelected() == true) { - globalSelectionModel.clearAndSelect(fileID); try { - new AddDrawableTagAction(controller).addTag(ImageGalleryController.getDefault().getTagsManager().getFollowUpTagName(), ""); + final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); + globalSelectionModel.clearAndSelect(fileID); + new AddDrawableTagAction(controller).addTag(followUpTagName, ""); } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to add follow up tag. Could not load TagName.", ex); + LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); } } else { - new DeleteTagAction(controller, file).handle(t); + new DeleteFollowUpTagAction(controller, file).handle(event); } }); } @@ -290,7 +290,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie } protected boolean hasFollowUp() throws TskCoreException { - String followUpTagName = ImageGalleryController.getDefault().getTagsManager().getFollowUpTagName().getDisplayName(); + String followUpTagName = getController().getTagsManager().getFollowUpTagName().getDisplayName(); Collection tagNames = DrawableAttribute.TAGS.getValue(getFile()); return tagNames.stream().anyMatch((tn) -> tn.getDisplayName().equals(followUpTagName)); } From 255219689199ede0ee5e8e98eea3ae0ab5d1ce65 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 17 Jun 2015 15:54:34 -0400 Subject: [PATCH 134/198] more cleanup of Categories/Tags and listening to autopsy generated "Tag Events" -remove unused code from Category.java -use Category.isCategoryTagName instead of .getDisplayName().startsWith(Category.CATEGORY_PREFIX) -regroup when notified of Tag Change from autopsy --- .../imagegallery/DrawableTagsManager.java | 3 +- .../imagegallery/ImageGalleryController.java | 229 +++++++++--------- .../imagegallery/actions/AddTagAction.java | 4 +- .../actions/CategorizeAction.java | 4 +- .../imagegallery/datamodel/Category.java | 29 +-- .../datamodel/CategoryManager.java | 1 - .../imagegallery/datamodel/DrawableFile.java | 22 +- .../imagegallery/grouping/GroupManager.java | 17 +- .../imagegallery/gui/DrawableView.java | 32 +-- .../imagegallery/gui/MetaDataPane.java | 18 +- 10 files changed, 181 insertions(+), 178 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 7ba9ceb842..2639de7617 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -22,6 +22,7 @@ import com.google.common.eventbus.EventBus; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.logging.Level; import java.util.stream.Collectors; import org.sleuthkit.autopsy.casemodule.services.TagsManager; @@ -111,7 +112,7 @@ public class DrawableTagsManager { * @throws TskCoreException */ synchronized public TagName getFollowUpTagName() throws TskCoreException { - if (followUpTagName == null) { + if (Objects.isNull(followUpTagName)) { followUpTagName = getTagName(FOLLOW_UP); } return followUpTagName; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 4bed46a023..11fd505ba6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.imagegallery; import java.beans.PropertyChangeEvent; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.BlockingQueue; @@ -57,7 +58,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.History; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -68,6 +68,7 @@ import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; import org.sleuthkit.autopsy.imagegallery.gui.SummaryTablePane; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -83,25 +84,25 @@ import org.sleuthkit.datamodel.TskData; * control. */ public final class ImageGalleryController { - + private static final Logger LOGGER = Logger.getLogger(ImageGalleryController.class.getName()); - + private final Region infoOverLayBackground = new Region() { { setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY))); setOpacity(.4); } }; - + private static ImageGalleryController instance; - + public static synchronized ImageGalleryController getDefault() { if (instance == null) { instance = new ImageGalleryController(); } return instance; } - + private final History historyManager = new History<>(); /** @@ -109,75 +110,75 @@ public final class ImageGalleryController { * not listen to speed up ingest */ private final SimpleBooleanProperty listeningEnabled = new SimpleBooleanProperty(false); - + private final ReadOnlyIntegerWrapper queueSizeProperty = new ReadOnlyIntegerWrapper(0); - + private final ReadOnlyBooleanWrapper regroupDisabled = new ReadOnlyBooleanWrapper(false); - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private final ReadOnlyBooleanWrapper stale = new ReadOnlyBooleanWrapper(false); - + private final ReadOnlyBooleanWrapper metaDataCollapsed = new ReadOnlyBooleanWrapper(false); - + private final FileIDSelectionModel selectionModel = FileIDSelectionModel.getInstance(); - + private DBWorkerThread dbWorkerThread; - + private DrawableDB db; - + private final GroupManager groupManager = new GroupManager(this); private final HashSetManager hashSetManager = new HashSetManager(); private final CategoryManager categoryManager = new CategoryManager(this); private final DrawableTagsManager tagsManager = new DrawableTagsManager(null); - + private StackPane fullUIStackPane; - + private StackPane centralStackPane; - + private Node infoOverlay; private SleuthkitCase sleuthKitCase; - + public ReadOnlyBooleanProperty getMetaDataCollapsed() { return metaDataCollapsed.getReadOnlyProperty(); } - + public void setMetaDataCollapsed(Boolean metaDataCollapsed) { this.metaDataCollapsed.set(metaDataCollapsed); } - + private GroupViewState getViewState() { return historyManager.getCurrentState(); } - + public ReadOnlyBooleanProperty regroupDisabled() { return regroupDisabled.getReadOnlyProperty(); } - + public ReadOnlyObjectProperty viewState() { return historyManager.currentState(); } - + public synchronized FileIDSelectionModel getSelectionModel() { - + return selectionModel; } - + public GroupManager getGroupManager() { return groupManager; } - + public DrawableDB getDatabase() { return db; } - + synchronized public void setListeningEnabled(boolean enabled) { listeningEnabled.set(enabled); } - + synchronized boolean isListeningEnabled() { return listeningEnabled.get(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.ANY) void setStale(Boolean b) { Platform.runLater(() -> { @@ -187,18 +188,18 @@ public final class ImageGalleryController { new PerCaseProperties(Case.getCurrentCase()).setConfigSetting(ImageGalleryModule.getModuleName(), PerCaseProperties.STALE, b.toString()); } } - + public ReadOnlyBooleanProperty stale() { return stale.getReadOnlyProperty(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) boolean isStale() { return stale.get(); } - + private ImageGalleryController() { - + listeningEnabled.addListener((observable, oldValue, newValue) -> { //if we just turned on listening and a case is open and that case is not up to date if (newValue && !oldValue && Case.existsCurrentCase() && ImageGalleryModule.isDrawableDBStale(Case.getCurrentCase())) { @@ -206,28 +207,28 @@ public final class ImageGalleryController { queueDBWorkerTask(new CopyAnalyzedFiles()); } }); - + groupManager.getAnalyzedGroups().addListener((Observable o) -> { if (Case.isCaseOpen()) { checkForGroups(); } }); - + groupManager.getUnSeenGroups().addListener((Observable observable) -> { //if there are unseen groups and none being viewed if (groupManager.getUnSeenGroups().isEmpty() == false && (getViewState() == null || getViewState().getGroup() == null)) { advance(GroupViewState.tile(groupManager.getUnSeenGroups().get(0))); } }); - + viewState().addListener((Observable observable) -> { selectionModel.clearSelection(); }); - + regroupDisabled.addListener((Observable observable) -> { checkForGroups(); }); - + IngestManager.getInstance().addIngestModuleEventListener((PropertyChangeEvent evt) -> { Platform.runLater(this::updateRegroupDisabled); }); @@ -236,27 +237,27 @@ public final class ImageGalleryController { }); // metaDataCollapsed.bind(Toolbar.getDefault().showMetaDataProperty()); } - + public ReadOnlyBooleanProperty getCanAdvance() { return historyManager.getCanAdvance(); } - + public ReadOnlyBooleanProperty getCanRetreat() { return historyManager.getCanRetreat(); } - + public void advance(GroupViewState newState) { historyManager.advance(newState); } - + public GroupViewState advance() { return historyManager.advance(); } - + public GroupViewState retreat() { return historyManager.retreat(); } - + private void updateRegroupDisabled() { regroupDisabled.set(getFileUpdateQueueSizeProperty().get() > 0 || IngestManager.getInstance().isIngestRunning()); } @@ -278,7 +279,7 @@ public final class ImageGalleryController { new NoGroupsDialog("No groups are fully analyzed yet, but ingest is still ongoing. Please Wait.", new ProgressIndicator())); } - + } else if (getFileUpdateQueueSizeProperty().get() > 0) { replaceNotification(fullUIStackPane, new NoGroupsDialog("No groups are fully analyzed yet, but image / video data is still being populated. Please Wait.", @@ -292,19 +293,19 @@ public final class ImageGalleryController { replaceNotification(fullUIStackPane, new NoGroupsDialog("There are no images/videos in the added datasources.")); } - + } else if (!groupManager.isRegrouping()) { replaceNotification(centralStackPane, new NoGroupsDialog("There are no fully analyzed groups to display:" + " the current Group By setting resulted in no groups, " + "or no groups are fully analyzed but ingest is not running.")); } - + } else { clearNotification(); } } - + private void clearNotification() { //remove the ingest spinner if (fullUIStackPane != null) { @@ -315,27 +316,27 @@ public final class ImageGalleryController { centralStackPane.getChildren().remove(infoOverlay); } } - + private void replaceNotification(StackPane stackPane, Node newNode) { clearNotification(); - + infoOverlay = new StackPane(infoOverLayBackground, newNode); if (stackPane != null) { stackPane.getChildren().add(infoOverlay); } } - + private void restartWorker() { if (dbWorkerThread != null) { // Keep using the same worker thread if one exists return; } dbWorkerThread = new DBWorkerThread(); - + getFileUpdateQueueSizeProperty().addListener((Observable o) -> { Platform.runLater(this::updateRegroupDisabled); }); - + Thread th = new Thread(dbWorkerThread); th.setDaemon(false); // we want it to go away when it is done th.start(); @@ -350,7 +351,7 @@ public final class ImageGalleryController { if (Objects.nonNull(theNewCase)) { this.sleuthKitCase = theNewCase.getSleuthkitCase(); this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); - + setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); @@ -362,7 +363,9 @@ public final class ImageGalleryController { hashSetManager.setDb(db); categoryManager.setDb(db); tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); + tagsManager.registerListener(groupManager); SummaryTablePane.getDefault().refresh(); + } else { reset(); } @@ -379,9 +382,9 @@ public final class ImageGalleryController { Platform.runLater(() -> { historyManager.clear(); }); - Category.clearTagNames(); tagsManager.clearFollowUpTagName(); - + tagsManager.unregisterListener(groupManager); + Toolbar.getDefault(this).reset(); groupManager.clear(); if (db != null) { @@ -403,21 +406,21 @@ public final class ImageGalleryController { } dbWorkerThread.addTask(innerTask); } - + public DrawableFile getFileFromId(Long fileID) throws TskCoreException { return db.getFileFromID(fileID); } - + public void setStacks(StackPane fullUIStack, StackPane centralStack) { fullUIStackPane = fullUIStack; this.centralStackPane = centralStack; Platform.runLater(this::checkForGroups); } - + public ReadOnlyIntegerProperty getFileUpdateQueueSizeProperty() { return queueSizeProperty.getReadOnlyProperty(); } - + public ReadOnlyDoubleProperty regroupProgress() { return groupManager.regroupProgress(); } @@ -436,6 +439,10 @@ public final class ImageGalleryController { case CONTENT_CHANGED: //TODO: do we need to do anything here? -jm case DATA_ADDED: + ModuleDataEvent oldValue = (ModuleDataEvent) evt.getOldValue(); + if ("TagAction".equals(oldValue.getModuleName()) && oldValue.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { + getTagsManager().fireChange(Collections.singleton(-1L)); + } /* we could listen to DATA events and progressivly * update files, and get data from DataSource ingest * modules, but given that most modules don't post new @@ -489,15 +496,15 @@ public final class ImageGalleryController { } }); } - + public HashSetManager getHashSetManager() { return hashSetManager; } - + public CategoryManager getCategoryManager() { return categoryManager; } - + public DrawableTagsManager getTagsManager() { return tagsManager; } @@ -538,7 +545,7 @@ public final class ImageGalleryController { queueSizeProperty.set(workQueue.size()); }); } - + @Override public void run() { @@ -549,22 +556,22 @@ public final class ImageGalleryController { } try { InnerTask it = workQueue.take(); - + if (it.cancelled == false) { it.run(); } - + Platform.runLater(() -> { queueSizeProperty.set(workQueue.size()); }); - + } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); } } } } - + public synchronized SleuthkitCase getSleuthKitCase() { return sleuthKitCase; } @@ -573,55 +580,55 @@ public final class ImageGalleryController { * Abstract base class for task to be done on {@link DBWorkerThread} */ static public abstract class InnerTask implements Runnable { - + public double getProgress() { return progress.get(); } - + public final void updateProgress(Double workDone) { this.progress.set(workDone); } - + public String getMessage() { return message.get(); } - + public final void updateMessage(String Status) { this.message.set(Status); } SimpleObjectProperty state = new SimpleObjectProperty<>(Worker.State.READY); SimpleDoubleProperty progress = new SimpleDoubleProperty(this, "pregress"); SimpleStringProperty message = new SimpleStringProperty(this, "status"); - + public SimpleDoubleProperty progressProperty() { return progress; } - + public SimpleStringProperty messageProperty() { return message; } - + public Worker.State getState() { return state.get(); } - + protected void updateState(Worker.State newState) { state.set(newState); } - + public ReadOnlyObjectProperty stateProperty() { return new ReadOnlyObjectWrapper<>(state.get()); } - + protected InnerTask() { } - + protected volatile boolean cancelled = false; - + public void cancel() { updateState(Worker.State.CANCELLED); } - + protected boolean isCancelled() { return getState() == Worker.State.CANCELLED; } @@ -631,25 +638,25 @@ public final class ImageGalleryController { * Abstract base class for tasks associated with a file in the database */ static public abstract class FileTask extends InnerTask { - + private final AbstractFile file; - + public AbstractFile getFile() { return file; } - + public FileTask(AbstractFile f) { super(); this.file = f; } - + } /** * task that updates one file in database with results from ingest */ private class UpdateFileTask extends FileTask { - + public UpdateFileTask(AbstractFile f) { super(f); } @@ -676,7 +683,7 @@ public final class ImageGalleryController { * task that updates one file in database with results from ingest */ private class RemoveFileTask extends FileTask { - + public RemoveFileTask(AbstractFile f) { super(f); } @@ -695,7 +702,7 @@ public final class ImageGalleryController { Logger.getLogger(RemoveFileTask.class.getName()).log(Level.SEVERE, "Case was closed out from underneath RemoveFile task"); } } - + } } @@ -707,16 +714,16 @@ public final class ImageGalleryController { * adds them to the Drawable DB */ private class CopyAnalyzedFiles extends InnerTask { - + final private String DRAWABLE_QUERY = "name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "'"; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("populating analyzed image/video database"); - + @Override public void run() { progressHandle.start(); updateMessage("populating analyzed image/video database"); - + try { //grab all files with supported extension or detected mime types final List files = getSleuthKitCase().findAllFilesWhere(DRAWABLE_QUERY + " or tsk_files.obj_id in (select tsk_files.obj_id from tsk_files , blackboard_artifacts, blackboard_attributes" @@ -726,7 +733,7 @@ public final class ImageGalleryController { + " and blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID() + " and blackboard_attributes.value_text in ('" + StringUtils.join(ImageGalleryModule.getSupportedMimes(), "','") + "'))"); progressHandle.switchToDeterminate(files.size()); - + updateProgress(0.0); //do in transaction @@ -740,7 +747,7 @@ public final class ImageGalleryController { } final Boolean hasMimeType = ImageGalleryModule.hasSupportedMimeType(f); final boolean known = f.getKnown() == TskData.FileKnown.KNOWN; - + if (known) { db.removeFile(f.getId(), tr); //remove known files } else { @@ -760,38 +767,38 @@ public final class ImageGalleryController { } } } - + units++; final int prog = units; progressHandle.progress(f.getName(), units); updateProgress(prog - 1 / (double) files.size()); updateMessage(f.getName()); } - + progressHandle.finish(); - + progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); updateMessage("commiting image/video database"); updateProgress(1.0); - + progressHandle.start(); db.commitTransaction(tr, true); - + } catch (TskCoreException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.SEVERE, "Case was closed out from underneath CopyDataSource task", ex); } - + progressHandle.finish(); - + updateMessage( ""); updateProgress( -1.0); setStale(false); } - + } /** @@ -802,7 +809,7 @@ public final class ImageGalleryController { * netbeans and ImageGallery progress/status */ class PrePopulateDataSourceFiles extends InnerTask { - + private final Content dataSource; /** @@ -812,7 +819,7 @@ public final class ImageGalleryController { */ // (name like '.jpg' or name like '.png' ...) private final String DRAWABLE_QUERY = "(name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "') "; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("prepopulating image/video database"); /** @@ -838,7 +845,7 @@ public final class ImageGalleryController { final List files; try { List fsObjIds = new ArrayList<>(); - + String fsQuery; if (dataSource instanceof Image) { Image image = (Image) dataSource; @@ -852,7 +859,7 @@ public final class ImageGalleryController { else { fsQuery = "(fs_obj_id IS NULL) "; } - + files = getSleuthKitCase().findAllFilesWhere(fsQuery + " and " + DRAWABLE_QUERY); progressHandle.switchToDeterminate(files.size()); @@ -870,21 +877,21 @@ public final class ImageGalleryController { final int prog = units; progressHandle.progress(f.getName(), units); } - + progressHandle.finish(); progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); - + progressHandle.start(); db.commitTransaction(tr, false); - + } catch (TskCoreException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException | NullPointerException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "Case was closed out from underneath prepopulating database"); } - + progressHandle.finish(); } } - + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 11fac7a403..5284b7eb71 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -95,7 +95,7 @@ abstract class AddTagAction { // a tag with the associated tag name. if (null != tagNames && !tagNames.isEmpty()) { for (final TagName tagName : tagNames) { - if (tagName.getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) { + if (Category.isNotCategoryTagName(tagName)) { MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); tagNameItem.setOnAction((ActionEvent t) -> { addTag(tagName, NO_COMMENT); @@ -134,7 +134,7 @@ abstract class AddTagAction { SwingUtilities.invokeLater(() -> { GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); if (null != tagNameAndComment) { - if (tagNameAndComment.getTagName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { + if (Category.isCategoryTagName(tagNameAndComment.getTagName())) { new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } else { new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index b3bb065644..1b84b005bf 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -141,9 +141,7 @@ public class CategorizeAction extends AddTagAction { List allContentTags = sleuthKitCase.getContentTagsByContent(file); //tsk db for (ContentTag ct : allContentTags) { - //this is bad: treating tags as categories as long as their names start with prefix - //TODO: abandon using tags for categories and instead add a new column to DrawableDB - if (ct.getName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { + if (Category.isCategoryTagName(ct.getName())) { sleuthKitCase.deleteContentTag(ct); //tsk db categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 0ded98426f..ee6a46098e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -43,30 +43,25 @@ public enum Category implements Comparable { Category::getDisplayName, Function.identity())); - public static final String CATEGORY_PREFIX = "CAT-"; - public static Category fromDisplayName(String displayName) { return nameMap.get(displayName); } - /** - * Use when closing a case to make sure everything is re-initialized in the - * next case. - */ - public static void clearTagNames() { - Category.ZERO.tagName = null; - Category.ONE.tagName = null; - Category.TWO.tagName = null; - Category.THREE.tagName = null; - Category.FOUR.tagName = null; - Category.FIVE.tagName = null; - } - public static boolean isCategoryTagName(TagName tName) { - return nameMap.containsKey(tName.getDisplayName()); + return isCategoryName(tName.getDisplayName()); } - private TagName tagName; + public static boolean isNotCategoryTagName(TagName tName) { + return isNotCategoryName(tName.getDisplayName()); + } + + public static boolean isCategoryName(String tName) { + return nameMap.containsKey(tName); + } + + public static boolean isNotCategoryName(String tName) { + return nameMap.containsKey(tName) == false; + } private final Color color; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 08ba1b17a5..0197c3c847 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -92,7 +92,6 @@ public class CategoryManager { this.db = db; categoryCounts.invalidateAll(); catTagNameMap.invalidateAll(); - Category.clearTagNames(); } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index bd4c84dd5e..4d3de0d553 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -46,7 +46,6 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBU import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.LONG; import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.SleuthkitItemVisitor; import org.sleuthkit.datamodel.Tag; @@ -111,7 +110,6 @@ public abstract class DrawableFile extends AbstractFile super(file.getSleuthkitCase(), file.getId(), file.getAttrType(), file.getAttrId(), file.getName(), file.getType(), file.getMetaAddr(), (int) file.getMetaSeq(), file.getDirType(), file.getMetaType(), null, new Integer(0).shortValue(), file.getSize(), file.getCtime(), file.getCrtime(), file.getAtime(), file.getMtime(), new Integer(0).shortValue(), file.getUid(), file.getGid(), file.getMd5Hash(), file.getKnown(), file.getParentPath()); this.analyzed = new SimpleBooleanProperty(analyzed); this.file = file; - } public abstract boolean isVideo(); @@ -272,20 +270,14 @@ public abstract class DrawableFile extends AbstractFile public void updateCategory() { try { + category.set(getSleuthkitCase().getContentTagsByContent(this).stream() + .map(Tag::getName).filter(Category::isCategoryTagName) + .findFirst() + .map(TagName::getDisplayName) + .map(Category::fromDisplayName) + .orElse(Category.ZERO) + ); - List contentTagsByContent = getSleuthkitCase().getContentTagsByContent(this); - Category cat = null; - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().startsWith(Category.CATEGORY_PREFIX)) { - cat = Category.fromDisplayName(ct.getName().getDisplayName()); - break; - } - } - if (cat == null) { - category.set(Category.ZERO); - } else { - category.set(cat); - } } catch (TskCoreException ex) { Logger.getLogger(DrawableFile.class.getName()).log(Level.WARNING, "problem looking up category for file " + this.getName(), ex); } catch (IllegalStateException ex) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 221c7ef4d1..cd02ba9c0a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.grouping; +import com.google.common.eventbus.Subscribe; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; @@ -59,6 +60,7 @@ import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; +import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; @@ -157,7 +159,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { Set> resultSet = new HashSet<>(); for (Comparable val : groupBy.getValue(file)) { if (groupBy == DrawableAttribute.TAGS) { - if (Category.isCategoryTagName((TagName) val) == false) { + if (Category.isNotCategoryTagName((TagName) val)) { resultSet.add(new GroupKey(groupBy, val)); } } else { @@ -463,7 +465,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { break; case TAGS: values = (List) controller.getTagsManager().getTagNamesInUse().stream() - .filter(t -> t.getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) + .filter(Category::isNotCategoryTagName) .collect(Collectors.toList()); break; case ANALYZED: @@ -590,7 +592,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @param sortOrder * @param force true to force a full db query regroup */ - public > void regroup(final DrawableAttribute groupBy, final GroupSortBy sortBy, final SortOrder sortOrder, Boolean force) { + public synchronized > void regroup(final DrawableAttribute groupBy, final GroupSortBy sortBy, final SortOrder sortOrder, Boolean force) { if (!Case.isCaseOpen()) { return; @@ -633,6 +635,15 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { return regroupProgress.getReadOnlyProperty(); } + @Subscribe + public void handleAutopsyTagChange(TagsChangeEvent evt) { + if (groupBy == DrawableAttribute.TAGS + && evt.getFileIDs().size() == 1 + && evt.getFileIDs().contains(-1L)) { + regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); + } + } + /** * handle {@link FileUpdateEvent} sent from Db when files are * inserted/updated diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index ed0453ec0b..93dbae801e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -84,21 +84,25 @@ public interface DrawableView { } static Border getCategoryBorder(Category category) { - switch (category) { - case ONE: - return CAT1_BORDER; - case TWO: - return CAT2_BORDER; - case THREE: - return CAT3_BORDER; - case FOUR: - return CAT4_BORDER; - case FIVE: - return CAT5_BORDER; - case ZERO: - default: - return CAT0_BORDER; + if (category != null) { + switch (category) { + case ONE: + return CAT1_BORDER; + case TWO: + return CAT2_BORDER; + case THREE: + return CAT3_BORDER; + case FOUR: + return CAT4_BORDER; + case FIVE: + return CAT5_BORDER; + case ZERO: + default: + return CAT0_BORDER; + } + } else { + return CAT0_BORDER; } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index f9f6115d67..4ab6fff208 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -92,6 +92,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { } @FXML + @SuppressWarnings("unchecked") void initialize() { assert attributeColumn != null : "fx:id=\"attributeColumn\" was not injected: check your FXML file 'MetaDataPane.fxml'."; assert imageView != null : "fx:id=\"imageView\" was not injected: check your FXML file 'MetaDataPane.fxml'."; @@ -121,14 +122,12 @@ public class MetaDataPane extends AnchorPane implements DrawableView { attributeColumn.setPrefWidth(USE_COMPUTED_SIZE); valueColumn.setCellValueFactory((p) -> { - if (p.getValue().getKey() == DrawableAttribute.TAGS) { - return new SimpleStringProperty(((Collection) p.getValue().getValue()).stream() - .map(TagName::getDisplayName) - .filter((String t) -> t.startsWith(Category.CATEGORY_PREFIX) == false) - .collect(Collectors.joining(" ; ", "", ""))); - } else { - return new SimpleStringProperty(StringUtils.join((Iterable) p.getValue().getValue(), " ; ")); - } + return (p.getValue().getKey() == DrawableAttribute.TAGS) + ? new SimpleStringProperty(((Collection) p.getValue().getValue()).stream() + .map(TagName::getDisplayName) + .filter(Category::isNotCategoryName) + .collect(Collectors.joining(" ; "))) + : new SimpleStringProperty(StringUtils.join((Iterable) p.getValue().getValue(), " ; ")); }); valueColumn.setPrefWidth(USE_COMPUTED_SIZE); valueColumn.setCellFactory((p) -> new TableCell, ? extends Object>, String>() { @@ -150,9 +149,6 @@ public class MetaDataPane extends AnchorPane implements DrawableView { controller.getSelectionModel().lastSelectedProperty().addListener((observable, oldFileID, newFileID) -> { setFile(newFileID); }); - -// MetaDataPane.this.visibleProperty().bind(controller.getMetaDataCollapsed().not()); -// MetaDataPane.this.managedProperty().bind(controller.getMetaDataCollapsed().not()); } @Override From 6353d3cc0f809b69f8cbe46b022430565e6391d6 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 17 Jun 2015 17:42:00 -0400 Subject: [PATCH 135/198] more work to keep autopsy and ImageGallery tags in sync add setFiles method to DrawableGroup; don't clear groups from GroupMap except for CaseChange; reuse groups via setFiles method when regrouping reselect group in navpanel after regroup --- .../imagegallery/DrawableTagsManager.java | 2 +- .../imagegallery/grouping/DrawableGroup.java | 25 +++++++-- .../imagegallery/grouping/GroupManager.java | 56 ++++++++----------- .../imagegallery/gui/navpanel/NavPanel.java | 6 ++ 4 files changed, 50 insertions(+), 39 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 2639de7617..149c7fd888 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index b59a1b8edd..386ae51d65 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -134,7 +134,7 @@ public class DrawableGroup implements Comparable { ((DrawableGroup) obj).groupKey); } - synchronized public void addFile(Long f) { + synchronized void addFile(Long f) { invalidateHashSetHitsCount(); if (fileIDs.contains(f) == false) { fileIDs.add(f); @@ -142,7 +142,21 @@ public class DrawableGroup implements Comparable { } } - synchronized public void removeFile(Long f) { + synchronized void setFiles(Set newFileIds) { + invalidateHashSetHitsCount(); + boolean filesRemoved = fileIDs.removeIf((Long t) -> newFileIds.contains(t) == false); + if (filesRemoved) { + seen.set(false); + } + for (Long f : newFileIds) { + if (fileIDs.contains(f) == false) { + fileIDs.add(f); + seen.set(false); + } + } + } + + synchronized void removeFile(Long f) { invalidateHashSetHitsCount(); if (fileIDs.removeAll(f)) { seen.set(false); @@ -151,11 +165,13 @@ public class DrawableGroup implements Comparable { // By default, sort by group key name @Override - public int compareTo(DrawableGroup other) { + public int compareTo(DrawableGroup other + ) { return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName()); } - void setSeen(boolean isSeen) { + void setSeen(boolean isSeen + ) { this.seen.set(isSeen); } @@ -166,4 +182,5 @@ public class DrawableGroup implements Comparable { public boolean isSeen() { return seen.get(); } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index cd02ba9c0a..a79b8e3b48 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -198,21 +198,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Nullable public DrawableGroup getGroupForKey(@Nonnull GroupKey groupKey) { synchronized (groupMap) { - if (groupKey.getAttribute() == DrawableAttribute.TAGS) { - - System.out.println(groupKey); -// @SuppressWarnings("unchecked") -// GroupKey tagKey = (GroupKey) groupKey; -// -// return groupMap.keySet().stream() -// .filter((GroupKey t) -> t.getAttribute() == DrawableAttribute.TAGS) -// .map((GroupKey t) -> (GroupKey) t) -// .filter(t -> tagKey.getValue().getDisplayName().equals(t.getValue().getDisplayName())) -// .findFirst().map(groupMap::get).orElse(null); - - } //else { return groupMap.get(groupKey); -// } } } @@ -255,7 +241,8 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { /** * make and return a new group with the given key and files. If a group - * already existed for that key, it will be replaced. + * already existed for that key, it will be updated to contain the given + * files. * * NOTE: this is the only API for making a new group. * @@ -265,28 +252,33 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @return the new DrawableGroup for the given key */ public DrawableGroup makeGroup(GroupKey groupKey, Set files) { - - Set newFiles = ObjectUtils.defaultIfNull(files, new HashSet()); - final boolean groupSeen = db.isGroupSeen(groupKey); - DrawableGroup g = new DrawableGroup(groupKey, newFiles, groupSeen); - - g.seenProperty().addListener((observable, oldSeen, newSeen) -> { - markGroupSeen(g, newSeen); - }); synchronized (groupMap) { - groupMap.put(groupKey, g); + if (groupMap.containsKey(groupKey)) { + DrawableGroup group = groupMap.get(groupKey); + group.setFiles(ObjectUtils.defaultIfNull(files, Collections.emptySet())); + return group; + } else { + final boolean groupSeen = db.isGroupSeen(groupKey); + DrawableGroup group = new DrawableGroup(groupKey, files, groupSeen); + group.seenProperty().addListener((observable, oldSeen, newSeen) -> { + markGroupSeen(group, newSeen); + }); + groupMap.put(groupKey, group); + return group; + } } - return g; } /** - * 'mark' the given group as seen. This removes it from the queue of groups + * 'mark' the given group as seen. This removes it from the queue of + * groups * to review, and is persisted in the drawable db. * * @param group the {@link DrawableGroup} to mark as seen */ @ThreadConfined(type = ThreadType.JFX) - public void markGroupSeen(DrawableGroup group, boolean seen) { + public void markGroupSeen(DrawableGroup group, boolean seen + ) { db.markGroupSeen(group.getGroupKey(), seen); group.setSeen(seen); if (seen) { @@ -314,9 +306,6 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { // If we're grouping by category, we don't want to remove empty groups. if (groupKey.getAttribute() != DrawableAttribute.CATEGORY) { if (group.fileIds().isEmpty()) { - synchronized (groupMap) { - groupMap.remove(groupKey, group); - } Platform.runLater(() -> { analyzedGroups.remove(group); unSeenGroups.remove(group); @@ -624,6 +613,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder)); }); } + } /** @@ -723,6 +713,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { controller.getTagsManager().fireChange(fileIDs); } break; + } } @@ -768,14 +759,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { unSeenGroups.clear(); } }); - synchronized (groupMap) { - groupMap.clear(); - } // Get the list of group keys final List vals = findValuesForAttribute(groupBy); - // Make a list of each group + // Make a list of each group final List groups = new ArrayList<>(); groupProgress.start(vals.size()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java index 09b025d75e..482ff66f7c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java @@ -155,6 +155,7 @@ public class NavPanel extends TabPane { initNavTree(); controller.getGroupManager().getAnalyzedGroups().addListener((ListChangeListener.Change change) -> { + TreeItem selectedItem = activeTreeProperty.get().getSelectionModel().getSelectedItem(); boolean wasPermuted = false; while (change.next()) { for (DrawableGroup g : change.getAddedSubList()) { @@ -175,6 +176,11 @@ public class NavPanel extends TabPane { if (wasPermuted) { rebuildTrees(); + } + if (selectedItem != null) { + Platform.runLater(() -> { + setFocusedGroup(selectedItem.getValue().getGroup()); + }); } }); From 34eb72655167cdd16b24fe4e5b05106f1131652a Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 11:39:16 -0400 Subject: [PATCH 136/198] refactor in GroupManager, to make logic and flow cleaner split FileUpdateEvent handlers to seperate update and removed methods name DbWorkerThread, Thread --- .../autopsy/imagegallery/FileUpdateEvent.java | 5 +- .../imagegallery/ImageGalleryController.java | 222 ++++++------ .../imagegallery/actions/NextUnseenGroup.java | 1 + .../imagegallery/datamodel/DrawableDB.java | 2 +- .../imagegallery/grouping/DrawableGroup.java | 6 +- .../imagegallery/grouping/GroupManager.java | 323 +++++++----------- .../imagegallery/gui/navpanel/NavPanel.java | 4 +- 7 files changed, 238 insertions(+), 325 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java index 038ac4bafb..c2803a5090 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.imagegallery; import java.util.Collection; +import java.util.Collections; import java.util.EventListener; import java.util.HashSet; import java.util.Set; @@ -43,7 +44,7 @@ public class FileUpdateEvent { } public Collection getFileIDs() { - return fileIDs; + return Collections.unmodifiableCollection(fileIDs); } public DrawableAttribute getChangedAttribute() { @@ -86,5 +87,7 @@ public class FileUpdateEvent { public static interface FileUpdateListener extends EventListener { public void handleFileUpdate(FileUpdateEvent evt); + + public void handleFileRemoved(FileUpdateEvent evt); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 11fd505ba6..e649afbc39 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -84,25 +84,25 @@ import org.sleuthkit.datamodel.TskData; * control. */ public final class ImageGalleryController { - + private static final Logger LOGGER = Logger.getLogger(ImageGalleryController.class.getName()); - + private final Region infoOverLayBackground = new Region() { { setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY))); setOpacity(.4); } }; - + private static ImageGalleryController instance; - + public static synchronized ImageGalleryController getDefault() { if (instance == null) { instance = new ImageGalleryController(); } return instance; } - + private final History historyManager = new History<>(); /** @@ -110,75 +110,75 @@ public final class ImageGalleryController { * not listen to speed up ingest */ private final SimpleBooleanProperty listeningEnabled = new SimpleBooleanProperty(false); - + private final ReadOnlyIntegerWrapper queueSizeProperty = new ReadOnlyIntegerWrapper(0); - + private final ReadOnlyBooleanWrapper regroupDisabled = new ReadOnlyBooleanWrapper(false); - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private final ReadOnlyBooleanWrapper stale = new ReadOnlyBooleanWrapper(false); - + private final ReadOnlyBooleanWrapper metaDataCollapsed = new ReadOnlyBooleanWrapper(false); - + private final FileIDSelectionModel selectionModel = FileIDSelectionModel.getInstance(); - + private DBWorkerThread dbWorkerThread; - + private DrawableDB db; - + private final GroupManager groupManager = new GroupManager(this); private final HashSetManager hashSetManager = new HashSetManager(); private final CategoryManager categoryManager = new CategoryManager(this); private final DrawableTagsManager tagsManager = new DrawableTagsManager(null); - + private StackPane fullUIStackPane; - + private StackPane centralStackPane; - + private Node infoOverlay; private SleuthkitCase sleuthKitCase; - + public ReadOnlyBooleanProperty getMetaDataCollapsed() { return metaDataCollapsed.getReadOnlyProperty(); } - + public void setMetaDataCollapsed(Boolean metaDataCollapsed) { this.metaDataCollapsed.set(metaDataCollapsed); } - + private GroupViewState getViewState() { return historyManager.getCurrentState(); } - + public ReadOnlyBooleanProperty regroupDisabled() { return regroupDisabled.getReadOnlyProperty(); } - + public ReadOnlyObjectProperty viewState() { return historyManager.currentState(); } - + public synchronized FileIDSelectionModel getSelectionModel() { - + return selectionModel; } - + public GroupManager getGroupManager() { return groupManager; } - + public DrawableDB getDatabase() { return db; } - + synchronized public void setListeningEnabled(boolean enabled) { listeningEnabled.set(enabled); } - + synchronized boolean isListeningEnabled() { return listeningEnabled.get(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.ANY) void setStale(Boolean b) { Platform.runLater(() -> { @@ -188,18 +188,18 @@ public final class ImageGalleryController { new PerCaseProperties(Case.getCurrentCase()).setConfigSetting(ImageGalleryModule.getModuleName(), PerCaseProperties.STALE, b.toString()); } } - + public ReadOnlyBooleanProperty stale() { return stale.getReadOnlyProperty(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) boolean isStale() { return stale.get(); } - + private ImageGalleryController() { - + listeningEnabled.addListener((observable, oldValue, newValue) -> { //if we just turned on listening and a case is open and that case is not up to date if (newValue && !oldValue && Case.existsCurrentCase() && ImageGalleryModule.isDrawableDBStale(Case.getCurrentCase())) { @@ -207,28 +207,28 @@ public final class ImageGalleryController { queueDBWorkerTask(new CopyAnalyzedFiles()); } }); - + groupManager.getAnalyzedGroups().addListener((Observable o) -> { if (Case.isCaseOpen()) { checkForGroups(); } }); - + groupManager.getUnSeenGroups().addListener((Observable observable) -> { //if there are unseen groups and none being viewed if (groupManager.getUnSeenGroups().isEmpty() == false && (getViewState() == null || getViewState().getGroup() == null)) { advance(GroupViewState.tile(groupManager.getUnSeenGroups().get(0))); } }); - + viewState().addListener((Observable observable) -> { selectionModel.clearSelection(); }); - + regroupDisabled.addListener((Observable observable) -> { checkForGroups(); }); - + IngestManager.getInstance().addIngestModuleEventListener((PropertyChangeEvent evt) -> { Platform.runLater(this::updateRegroupDisabled); }); @@ -237,27 +237,27 @@ public final class ImageGalleryController { }); // metaDataCollapsed.bind(Toolbar.getDefault().showMetaDataProperty()); } - + public ReadOnlyBooleanProperty getCanAdvance() { return historyManager.getCanAdvance(); } - + public ReadOnlyBooleanProperty getCanRetreat() { return historyManager.getCanRetreat(); } - + public void advance(GroupViewState newState) { historyManager.advance(newState); } - + public GroupViewState advance() { return historyManager.advance(); } - + public GroupViewState retreat() { return historyManager.retreat(); } - + private void updateRegroupDisabled() { regroupDisabled.set(getFileUpdateQueueSizeProperty().get() > 0 || IngestManager.getInstance().isIngestRunning()); } @@ -279,7 +279,7 @@ public final class ImageGalleryController { new NoGroupsDialog("No groups are fully analyzed yet, but ingest is still ongoing. Please Wait.", new ProgressIndicator())); } - + } else if (getFileUpdateQueueSizeProperty().get() > 0) { replaceNotification(fullUIStackPane, new NoGroupsDialog("No groups are fully analyzed yet, but image / video data is still being populated. Please Wait.", @@ -293,19 +293,19 @@ public final class ImageGalleryController { replaceNotification(fullUIStackPane, new NoGroupsDialog("There are no images/videos in the added datasources.")); } - + } else if (!groupManager.isRegrouping()) { replaceNotification(centralStackPane, new NoGroupsDialog("There are no fully analyzed groups to display:" + " the current Group By setting resulted in no groups, " + "or no groups are fully analyzed but ingest is not running.")); } - + } else { clearNotification(); } } - + private void clearNotification() { //remove the ingest spinner if (fullUIStackPane != null) { @@ -316,28 +316,28 @@ public final class ImageGalleryController { centralStackPane.getChildren().remove(infoOverlay); } } - + private void replaceNotification(StackPane stackPane, Node newNode) { clearNotification(); - + infoOverlay = new StackPane(infoOverLayBackground, newNode); if (stackPane != null) { stackPane.getChildren().add(infoOverlay); } } - + private void restartWorker() { if (dbWorkerThread != null) { // Keep using the same worker thread if one exists return; } dbWorkerThread = new DBWorkerThread(); - + getFileUpdateQueueSizeProperty().addListener((Observable o) -> { Platform.runLater(this::updateRegroupDisabled); }); - - Thread th = new Thread(dbWorkerThread); + + Thread th = new Thread(dbWorkerThread, "DB-Worker-Thread"); th.setDaemon(false); // we want it to go away when it is done th.start(); } @@ -351,7 +351,7 @@ public final class ImageGalleryController { if (Objects.nonNull(theNewCase)) { this.sleuthKitCase = theNewCase.getSleuthkitCase(); this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); - + setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); @@ -365,7 +365,7 @@ public final class ImageGalleryController { tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); tagsManager.registerListener(groupManager); SummaryTablePane.getDefault().refresh(); - + } else { reset(); } @@ -384,7 +384,7 @@ public final class ImageGalleryController { }); tagsManager.clearFollowUpTagName(); tagsManager.unregisterListener(groupManager); - + Toolbar.getDefault(this).reset(); groupManager.clear(); if (db != null) { @@ -406,21 +406,21 @@ public final class ImageGalleryController { } dbWorkerThread.addTask(innerTask); } - + public DrawableFile getFileFromId(Long fileID) throws TskCoreException { return db.getFileFromID(fileID); } - + public void setStacks(StackPane fullUIStack, StackPane centralStack) { fullUIStackPane = fullUIStack; this.centralStackPane = centralStack; Platform.runLater(this::checkForGroups); } - + public ReadOnlyIntegerProperty getFileUpdateQueueSizeProperty() { return queueSizeProperty.getReadOnlyProperty(); } - + public ReadOnlyDoubleProperty regroupProgress() { return groupManager.regroupProgress(); } @@ -496,15 +496,15 @@ public final class ImageGalleryController { } }); } - + public HashSetManager getHashSetManager() { return hashSetManager; } - + public CategoryManager getCategoryManager() { return categoryManager; } - + public DrawableTagsManager getTagsManager() { return tagsManager; } @@ -545,7 +545,7 @@ public final class ImageGalleryController { queueSizeProperty.set(workQueue.size()); }); } - + @Override public void run() { @@ -556,22 +556,22 @@ public final class ImageGalleryController { } try { InnerTask it = workQueue.take(); - + if (it.cancelled == false) { it.run(); } - + Platform.runLater(() -> { queueSizeProperty.set(workQueue.size()); }); - + } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); } } } } - + public synchronized SleuthkitCase getSleuthKitCase() { return sleuthKitCase; } @@ -580,55 +580,55 @@ public final class ImageGalleryController { * Abstract base class for task to be done on {@link DBWorkerThread} */ static public abstract class InnerTask implements Runnable { - + public double getProgress() { return progress.get(); } - + public final void updateProgress(Double workDone) { this.progress.set(workDone); } - + public String getMessage() { return message.get(); } - + public final void updateMessage(String Status) { this.message.set(Status); } SimpleObjectProperty state = new SimpleObjectProperty<>(Worker.State.READY); SimpleDoubleProperty progress = new SimpleDoubleProperty(this, "pregress"); SimpleStringProperty message = new SimpleStringProperty(this, "status"); - + public SimpleDoubleProperty progressProperty() { return progress; } - + public SimpleStringProperty messageProperty() { return message; } - + public Worker.State getState() { return state.get(); } - + protected void updateState(Worker.State newState) { state.set(newState); } - + public ReadOnlyObjectProperty stateProperty() { return new ReadOnlyObjectWrapper<>(state.get()); } - + protected InnerTask() { } - + protected volatile boolean cancelled = false; - + public void cancel() { updateState(Worker.State.CANCELLED); } - + protected boolean isCancelled() { return getState() == Worker.State.CANCELLED; } @@ -638,25 +638,25 @@ public final class ImageGalleryController { * Abstract base class for tasks associated with a file in the database */ static public abstract class FileTask extends InnerTask { - + private final AbstractFile file; - + public AbstractFile getFile() { return file; } - + public FileTask(AbstractFile f) { super(); this.file = f; } - + } /** * task that updates one file in database with results from ingest */ private class UpdateFileTask extends FileTask { - + public UpdateFileTask(AbstractFile f) { super(f); } @@ -683,7 +683,7 @@ public final class ImageGalleryController { * task that updates one file in database with results from ingest */ private class RemoveFileTask extends FileTask { - + public RemoveFileTask(AbstractFile f) { super(f); } @@ -702,7 +702,7 @@ public final class ImageGalleryController { Logger.getLogger(RemoveFileTask.class.getName()).log(Level.SEVERE, "Case was closed out from underneath RemoveFile task"); } } - + } } @@ -714,16 +714,16 @@ public final class ImageGalleryController { * adds them to the Drawable DB */ private class CopyAnalyzedFiles extends InnerTask { - + final private String DRAWABLE_QUERY = "name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "'"; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("populating analyzed image/video database"); - + @Override public void run() { progressHandle.start(); updateMessage("populating analyzed image/video database"); - + try { //grab all files with supported extension or detected mime types final List files = getSleuthKitCase().findAllFilesWhere(DRAWABLE_QUERY + " or tsk_files.obj_id in (select tsk_files.obj_id from tsk_files , blackboard_artifacts, blackboard_attributes" @@ -733,7 +733,7 @@ public final class ImageGalleryController { + " and blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID() + " and blackboard_attributes.value_text in ('" + StringUtils.join(ImageGalleryModule.getSupportedMimes(), "','") + "'))"); progressHandle.switchToDeterminate(files.size()); - + updateProgress(0.0); //do in transaction @@ -747,7 +747,7 @@ public final class ImageGalleryController { } final Boolean hasMimeType = ImageGalleryModule.hasSupportedMimeType(f); final boolean known = f.getKnown() == TskData.FileKnown.KNOWN; - + if (known) { db.removeFile(f.getId(), tr); //remove known files } else { @@ -767,38 +767,38 @@ public final class ImageGalleryController { } } } - + units++; final int prog = units; progressHandle.progress(f.getName(), units); updateProgress(prog - 1 / (double) files.size()); updateMessage(f.getName()); } - + progressHandle.finish(); - + progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); updateMessage("commiting image/video database"); updateProgress(1.0); - + progressHandle.start(); db.commitTransaction(tr, true); - + } catch (TskCoreException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.SEVERE, "Case was closed out from underneath CopyDataSource task", ex); } - + progressHandle.finish(); - + updateMessage( ""); updateProgress( -1.0); setStale(false); } - + } /** @@ -809,7 +809,7 @@ public final class ImageGalleryController { * netbeans and ImageGallery progress/status */ class PrePopulateDataSourceFiles extends InnerTask { - + private final Content dataSource; /** @@ -819,7 +819,7 @@ public final class ImageGalleryController { */ // (name like '.jpg' or name like '.png' ...) private final String DRAWABLE_QUERY = "(name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "') "; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("prepopulating image/video database"); /** @@ -845,7 +845,7 @@ public final class ImageGalleryController { final List files; try { List fsObjIds = new ArrayList<>(); - + String fsQuery; if (dataSource instanceof Image) { Image image = (Image) dataSource; @@ -859,7 +859,7 @@ public final class ImageGalleryController { else { fsQuery = "(fs_obj_id IS NULL) "; } - + files = getSleuthKitCase().findAllFilesWhere(fsQuery + " and " + DRAWABLE_QUERY); progressHandle.switchToDeterminate(files.size()); @@ -877,21 +877,21 @@ public final class ImageGalleryController { final int prog = units; progressHandle.progress(f.getName(), units); } - + progressHandle.finish(); progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); - + progressHandle.start(); db.commitTransaction(tr, false); - + } catch (TskCoreException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException | NullPointerException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "Case was closed out from underneath prepopulating database"); } - + progressHandle.finish(); } } - + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java index ab8ef06401..550581d8b2 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java @@ -51,6 +51,7 @@ public class NextUnseenGroup extends Action { this.controller = controller; setGraphic(new ImageView(ADVANCE)); + //TODO: do we need both these listeners? controller.getGroupManager().getAnalyzedGroups().addListener((Observable observable) -> { Platform.runLater(this::updateButton); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 49b0818e3b..9dfbbdc239 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -656,7 +656,7 @@ public final class DrawableDB { private void fireRemovedFiles(Collection fileIDs) { for (FileUpdateEvent.FileUpdateListener listener : updateListeners) { - listener.handleFileUpdate(FileUpdateEvent.newRemovedEvent(fileIDs)); + listener.handleFileRemoved(FileUpdateEvent.newRemovedEvent(fileIDs)); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java index 386ae51d65..0ad8b2640e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java @@ -165,13 +165,11 @@ public class DrawableGroup implements Comparable { // By default, sort by group key name @Override - public int compareTo(DrawableGroup other - ) { + public int compareTo(DrawableGroup other) { return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName()); } - void setSeen(boolean isSeen - ) { + void setSeen(boolean isSeen) { this.seen.set(isSeen); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index a79b8e3b48..2027dae724 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-4 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,10 +25,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ExecutorService; @@ -41,12 +43,14 @@ import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.collections.FXCollections; import javafx.collections.ObservableList; +import javafx.collections.transformation.SortedList; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; import javax.swing.SortOrder; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; @@ -98,16 +102,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { */ @ThreadConfined(type = ThreadType.JFX) private final ObservableList analyzedGroups = FXCollections.observableArrayList(); + private final SortedList unmodifiableAnalyzedGroups = new SortedList<>(analyzedGroups); - private final ObservableList publicAnalyzedGroupsWrapper = FXCollections.unmodifiableObservableList(analyzedGroups); - /** - * list of unseen groups - */ + /** list of unseen groups */ @ThreadConfined(type = ThreadType.JFX) private final ObservableList unSeenGroups = FXCollections.observableArrayList(); - -// private final SortedList sortedUnSeenGroups = new SortedList<>(unSeenGroups); - private final ObservableList publicSortedUnseenGroupsWrapper = FXCollections.unmodifiableObservableList(unSeenGroups); + private final SortedList unmodifiableUnSeenGroups = new SortedList<>(unSeenGroups); private ReGroupTask groupByTask; @@ -117,7 +117,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { private volatile DrawableAttribute groupBy = DrawableAttribute.PATH; private volatile SortOrder sortOrder = SortOrder.ASCENDING; - private ReadOnlyDoubleWrapper regroupProgress = new ReadOnlyDoubleWrapper(); + private final ReadOnlyDoubleWrapper regroupProgress = new ReadOnlyDoubleWrapper(); public void setDB(DrawableDB db) { this.db = db; @@ -125,13 +125,15 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); } + @SuppressWarnings("ReturnOfCollectionOrArrayField") public ObservableList getAnalyzedGroups() { - return publicAnalyzedGroupsWrapper; + return unmodifiableAnalyzedGroups; } @ThreadConfined(type = ThreadType.JFX) + @SuppressWarnings("ReturnOfCollectionOrArrayField") public ObservableList getUnSeenGroups() { - return publicSortedUnseenGroupsWrapper; + return unmodifiableUnSeenGroups; } /** @@ -239,36 +241,6 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } - /** - * make and return a new group with the given key and files. If a group - * already existed for that key, it will be updated to contain the given - * files. - * - * NOTE: this is the only API for making a new group. - * - * @param groupKey the groupKey that uniquely identifies this group - * @param files a list of fileids that are members of this group - * - * @return the new DrawableGroup for the given key - */ - public DrawableGroup makeGroup(GroupKey groupKey, Set files) { - synchronized (groupMap) { - if (groupMap.containsKey(groupKey)) { - DrawableGroup group = groupMap.get(groupKey); - group.setFiles(ObjectUtils.defaultIfNull(files, Collections.emptySet())); - return group; - } else { - final boolean groupSeen = db.isGroupSeen(groupKey); - DrawableGroup group = new DrawableGroup(groupKey, files, groupSeen); - group.seenProperty().addListener((observable, oldSeen, newSeen) -> { - markGroupSeen(group, newSeen); - }); - groupMap.put(groupKey, group); - return group; - } - } - } - /** * 'mark' the given group as seen. This removes it from the queue of * groups @@ -277,15 +249,13 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @param group the {@link DrawableGroup} to mark as seen */ @ThreadConfined(type = ThreadType.JFX) - public void markGroupSeen(DrawableGroup group, boolean seen - ) { + public void markGroupSeen(DrawableGroup group, boolean seen) { db.markGroupSeen(group.getGroupKey(), seen); group.setSeen(seen); if (seen) { unSeenGroups.removeAll(group); } else if (unSeenGroups.contains(group) == false) { unSeenGroups.add(group); - FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); } } @@ -297,7 +267,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * @param groupKey the value of groupKey * @param fileID the value of file */ - public synchronized void removeFromGroup(GroupKey groupKey, final Long fileID) { + public synchronized DrawableGroup removeFromGroup(GroupKey groupKey, final Long fileID) { //get grouping this file would be in final DrawableGroup group = getGroupForKey(groupKey); if (group != null) { @@ -311,74 +281,10 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { unSeenGroups.remove(group); }); } - } else { } } - } - public synchronized void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup) { - populateAnalyzedGroup(groupKey, filesInGroup, null); - } - - /** - * create a group with the given GroupKey and file ids and add it to the - * analyzed group list. - * - * @param groupKey - * @param filesInGroup - */ - private synchronized > void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup, ReGroupTask task) { - - /* if this is not part of a regroup task or it is but the task is not - * cancelled... - * - * this allows us to stop if a regroup task has been cancelled (e.g. the - * user picked a different group by attribute, while the current task - * was still running) */ - if (task == null || (task.isCancelled() == false)) { - DrawableGroup g = makeGroup(groupKey, filesInGroup); - populateAnalyzedGroup(g, task); - } - } - - private synchronized void populateAnalyzedGroup(final DrawableGroup g, ReGroupTask task) { - - if (task == null || (task.isCancelled() == false)) { - final boolean groupSeen = db.isGroupSeen(g.getGroupKey()); - - Platform.runLater(() -> { - if (analyzedGroups.contains(g) == false) { - analyzedGroups.add(g); - } - markGroupSeen(g, groupSeen); - - }); - } - } - - /** - * check if the group for the given groupkey is analyzed - * - * @param groupKey - * - * @return null if this group is not analyzed or a list of file ids in - * this - * group if they are all analyzed - */ - public Set checkAnalyzed(final GroupKey groupKey) { - try { - /* for attributes other than path we can't be sure a group is fully - * analyzed because we don't know all the files that will be a part - * of that group */ - if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { - return getFileIDsInGroup(groupKey); - } else { - return null; - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); - return null; - } + return group; } /** @@ -595,9 +501,6 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { if (groupByTask != null) { groupByTask.cancel(true); } - Platform.runLater(() -> { - FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); - }); groupByTask = new ReGroupTask(groupBy, sortBy, sortOrder); Platform.runLater(() -> { @@ -605,15 +508,14 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { }); regroupExecutor.submit(groupByTask); } else { - // just resort the list of groups + // resort the list of groups setSortBy(sortBy); setSortOrder(sortOrder); Platform.runLater(() -> { - FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); - FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder)); + unmodifiableAnalyzedGroups.setComparator(sortBy.getGrpComparator(sortOrder)); + unmodifiableUnSeenGroups.setComparator(sortBy.getGrpComparator(sortOrder)); }); } - } /** @@ -634,86 +536,114 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } } + @Override + synchronized public void handleFileRemoved(FileUpdateEvent evt) { + Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.REMOVE); + + for (final long fileId : evt.getFileIDs()) { + //get grouping(s) this file would be in + Set> groupsForFile = getGroupKeysForFileID(fileId); + + for (GroupKey gk : groupsForFile) { + DrawableGroup g = removeFromGroup(gk, fileId); + + if (g == null) { + // It may be that this was the last unanalyzed file in the group, so test + // whether the group is now fully analyzed. + popuplateIfAnalyzed(gk, null); + } + } + } + } + /** * handle {@link FileUpdateEvent} sent from Db when files are * inserted/updated * - * TODO: why isn't this just two methods! - * * @param evt */ @Override synchronized public void handleFileUpdate(FileUpdateEvent evt) { - final Collection fileIDs = evt.getFileIDs(); - switch (evt.getUpdateType()) { - case REMOVE: - for (final long fileId : fileIDs) { - //get grouping(s) this file would be in - Set> groupsForFile = getGroupKeysForFileID(fileId); + Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.UPDATE); + Collection fileIDs = evt.getFileIDs(); + /** + * TODO: is there a way to optimize this to avoid quering to db + * so much. the problem is that as a new files are analyzed they + * might be in new groups( if we are grouping by say make or + * model) -jm + */ + for (long fileId : fileIDs) { - for (GroupKey gk : groupsForFile) { - removeFromGroup(gk, fileId); + controller.getHashSetManager().invalidateHashSetsForFile(fileId); - DrawableGroup g = getGroupForKey(gk); + //get grouping(s) this file would be in + Set> groupsForFile = getGroupKeysForFileID(fileId); - if (g == null) { - // It may be that this was the last unanalyzed file in the group, so test - // whether the group is now fully analyzed. - //TODO: use method in groupmanager ? - Set checkAnalyzed = checkAnalyzed(gk); - if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui - populateAnalyzedGroup(gk, checkAnalyzed); + for (GroupKey gk : groupsForFile) { + DrawableGroup g = getGroupForKey(gk); + + if (g == null) { + //if there wasn't already a group check if there should be one now + popuplateIfAnalyzed(gk, null); + } else { + //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. + g.addFile(fileId); + } + } + } + + //we fire this event for all files so that the category counts get updated during initial db population + controller.getCategoryManager().fireChange(fileIDs); + + if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { + controller.getTagsManager().fireChange(fileIDs); + } + } + + private void popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { + + if (Objects.nonNull(task) && (task.isCancelled())) { + /* if this method call is part of a ReGroupTask and that task is + * cancelled, no-op + * + * this allows us to stop if a regroup task has been cancelled (e.g. + * the user picked a different group by attribute, while the + * current task was still running) */ + } else { // no task or un-cancelled task + if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { + /* for attributes other than path we can't be sure a group is + * fully analyzed because we don't know all the files that + * will be a part of that group */ + + try { + Set fileIDs = getFileIDsInGroup(groupKey); + if (Objects.nonNull(fileIDs)) { + DrawableGroup group; + final boolean groupSeen = db.isGroupSeen(groupKey); + synchronized (groupMap) { + if (groupMap.containsKey(groupKey)) { + group = groupMap.get(groupKey); + group.setFiles(ObjectUtils.defaultIfNull(fileIDs, Collections.emptySet())); + } else { + + group = new DrawableGroup(groupKey, fileIDs, groupSeen); + group.seenProperty().addListener((observable, oldSeen, newSeen) -> { + markGroupSeen(group, newSeen); + }); + groupMap.put(groupKey, group); } } - } - } - - break; - case UPDATE: - - /** - * TODO: is there a way to optimize this to avoid quering to db - * so much. the problem is that as a new files are analyzed they - * might be in new groups( if we are grouping by say make or - * model) - * - * TODO: Should this be a InnerTask so it can be done by the - * WorkerThread? Is it already done by worker thread because - * handlefileUpdate is invoked through call on db in UpdateTask - * innertask? -jm - */ - for (final long fileId : fileIDs) { - - controller.getHashSetManager().invalidateHashSetsForFile(fileId); - - //get grouping(s) this file would be in - Set> groupsForFile = getGroupKeysForFileID(fileId); - - for (GroupKey gk : groupsForFile) { - DrawableGroup g = getGroupForKey(gk); - - if (g != null) { - //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. - g.addFile(fileId); - } else { - //if there wasn't already a group check if there should be one now - //TODO: use method in groupmanager ? - Set checkAnalyzed = checkAnalyzed(gk); - if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui - populateAnalyzedGroup(gk, checkAnalyzed); + Platform.runLater(() -> { + if (analyzedGroups.contains(group) == false) { + analyzedGroups.add(group); } - } + markGroupSeen(group, groupSeen); + }); } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); } - - //we fire this event for all files so that the category counts get updated during initial db population - controller.getCategoryManager().fireChange(fileIDs); - - if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { - controller.getTagsManager().fireChange(fileIDs); - } - break; - + } } } @@ -755,17 +685,16 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { groupProgress = ProgressHandleFactory.createHandle("regrouping files by " + groupBy.attrName.toString() + " sorted by " + sortBy.name() + " in " + sortOrder.toString() + " order", this); Platform.runLater(() -> { analyzedGroups.clear(); - synchronized (unSeenGroups) { - unSeenGroups.clear(); - } + unSeenGroups.clear(); + + final Comparator grpComparator = sortBy.getGrpComparator(sortOrder); + unmodifiableAnalyzedGroups.setComparator(grpComparator); + unmodifiableUnSeenGroups.setComparator(grpComparator); }); // Get the list of group keys final List vals = findValuesForAttribute(groupBy); - // Make a list of each group - final List groups = new ArrayList<>(); - groupProgress.start(vals.size()); int p = 0; @@ -778,25 +707,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { updateMessage("regrouping files by " + groupBy.attrName.toString() + " : " + val); updateProgress(p, vals.size()); groupProgress.progress("regrouping files by " + groupBy.attrName.toString() + " : " + val, p); - //check if this group is analyzed - final GroupKey groupKey = new GroupKey<>(groupBy, val); - - Set checkAnalyzed = checkAnalyzed(groupKey); - if (checkAnalyzed != null) { // != null => the group is analyzed, so add it to the ui - - // makeGroup will create the group and add it to the map groupMap, but does not - // update anything else - DrawableGroup g = makeGroup(groupKey, checkAnalyzed); - groups.add(g); - } - } - - // Sort the group list - Collections.sort(groups, sortBy.getGrpComparator(sortOrder)); - - // Officially add all groups in order - for (DrawableGroup g : groups) { - populateAnalyzedGroup(g, ReGroupTask.this); + popuplateIfAnalyzed(new GroupKey(groupBy, val), this); } updateProgress(1, 1); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java index 482ff66f7c..efc855e8ca 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java @@ -171,13 +171,14 @@ public class NavPanel extends TabPane { if (change.wasPermutated()) { // Handle this afterward wasPermuted = true; + break; } } if (wasPermuted) { rebuildTrees(); } - if (selectedItem != null) { + if (selectedItem != null && selectedItem.getValue().getGroup() != null) { Platform.runLater(() -> { setFocusedGroup(selectedItem.getValue().getGroup()); }); @@ -268,7 +269,6 @@ public class NavPanel extends TabPane { } private static List groupingToPath(DrawableGroup g) { - if (g.groupKey.getAttribute() == DrawableAttribute.PATH) { String path = g.groupKey.getValueDisplayName(); From aec6c222e8b083917cecc11184a814231f878917 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 13:51:37 -0400 Subject: [PATCH 137/198] rename method; add synchronization; remove singletonness from SummaryTablePane --- .../imagegallery/DrawableTagsManager.java | 4 ++-- .../imagegallery/ImageGalleryController.java | 4 +--- .../ImageGalleryTopComponent.java | 2 +- .../actions/AddDrawableTagAction.java | 2 +- .../imagegallery/actions/AddTagAction.java | 2 +- .../actions/CategorizeAction.java | 2 +- .../actions/DeleteFollowUpTagAction.java | 2 +- .../datamodel/CategoryManager.java | 21 +++++++++++++------ .../imagegallery/gui/SummaryTablePane.java | 18 ++++++---------- 9 files changed, 29 insertions(+), 28 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 149c7fd888..7e0303fe4d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -78,7 +78,7 @@ public class DrawableTagsManager { } /** - * fire a CategoryChangeEvent with the given fileIDs + * fire a TagsChangeEvent with the given fileIDs * * @param fileIDs */ @@ -188,7 +188,7 @@ public class DrawableTagsManager { * had a chance to add that so, we fire these events and the tree * refreshes based on them. */ - static public void fireTagsChangedEvent() { + static public void refreshTagsInAutopsy() { IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index e649afbc39..6c54db8185 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -65,7 +65,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; -import org.sleuthkit.autopsy.imagegallery.gui.SummaryTablePane; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -364,8 +363,6 @@ public final class ImageGalleryController { categoryManager.setDb(db); tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); tagsManager.registerListener(groupManager); - SummaryTablePane.getDefault().refresh(); - } else { reset(); } @@ -442,6 +439,7 @@ public final class ImageGalleryController { ModuleDataEvent oldValue = (ModuleDataEvent) evt.getOldValue(); if ("TagAction".equals(oldValue.getModuleName()) && oldValue.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { getTagsManager().fireChange(Collections.singleton(-1L)); + getCategoryManager().invalidateCaches(); } /* we could listen to DATA events and progressivly * update files, and get data from DataSource ingest diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java index e5c2bb3bd6..850230cb88 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java @@ -150,7 +150,7 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl metaDataTable = new MetaDataPane(controller); navPanel = new NavPanel(controller); - leftPane = new VBox(navPanel, SummaryTablePane.getDefault()); + leftPane = new VBox(navPanel, new SummaryTablePane(controller)); SplitPane.setResizableWithParent(leftPane, Boolean.FALSE); SplitPane.setResizableWithParent(groupPane, Boolean.TRUE); SplitPane.setResizableWithParent(metaDataTable, Boolean.FALSE); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index 9d5c5f277b..e88c51f12b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -90,7 +90,7 @@ public class AddDrawableTagAction extends AddTagAction { //make sure rest of ui hears category change. controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 5284b7eb71..abc441fb61 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -99,7 +99,7 @@ abstract class AddTagAction { MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); tagNameItem.setOnAction((ActionEvent t) -> { addTag(tagName, NO_COMMENT); - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); }); quickTagMenu.getItems().add(tagNameItem); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 1b84b005bf..27f599cafe 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -158,7 +158,7 @@ public class CategorizeAction extends AddTagAction { JOptionPane.showMessageDialog(null, "Unable to categorize " + fileID + ".", "Categorizing Error", JOptionPane.ERROR_MESSAGE); } - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 6a1a54c30d..bba6d5e4dc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -79,7 +79,7 @@ public class DeleteFollowUpTagAction extends Action { } } - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); //make sure rest of ui hears category change. groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 0197c3c847..f8b0e6beb1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -23,6 +23,7 @@ import com.google.common.cache.LoadingCache; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import java.util.Collection; +import java.util.Collections; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; @@ -44,6 +45,7 @@ import org.sleuthkit.datamodel.TagName; public class CategoryManager { private static final java.util.logging.Logger LOGGER = Logger.getLogger(CategoryManager.class.getName()); + private final ImageGalleryController controller; /** @@ -88,10 +90,17 @@ public class CategoryManager { * * @param db */ - public void setDb(DrawableDB db) { + synchronized public void setDb(DrawableDB db) { this.db = db; categoryCounts.invalidateAll(); catTagNameMap.invalidateAll(); + fireChange(Collections.singleton(-1L)); + } + + synchronized public void invalidateCaches() { + categoryCounts.invalidateAll(); + catTagNameMap.invalidateAll(); + fireChange(Collections.singleton(-1L)); } /** @@ -101,7 +110,7 @@ public class CategoryManager { * * @return the long the number of files with the given Category */ - public long getCategoryCount(Category cat) { + synchronized public long getCategoryCount(Category cat) { if (cat == Category.ZERO) { // Keeping track of the uncategorized files is a bit tricky while ingest // is going on, so always use the list of file IDs we already have along with the @@ -119,7 +128,7 @@ public class CategoryManager { * * @param cat the Category to increment */ - public void incrementCategoryCount(Category cat) { + synchronized public void incrementCategoryCount(Category cat) { if (cat != Category.ZERO) { categoryCounts.getUnchecked(cat).increment(); } @@ -131,7 +140,7 @@ public class CategoryManager { * * @param cat the Category to decrement */ - public void decrementCategoryCount(Category cat) { + synchronized public void decrementCategoryCount(Category cat) { if (cat != Category.ZERO) { categoryCounts.getUnchecked(cat).decrement(); } @@ -147,7 +156,7 @@ public class CategoryManager { * @return a LongAdder whose value is set to the number of file with the * given Category */ - private LongAdder getCategoryCountHelper(Category cat) { + synchronized private LongAdder getCategoryCountHelper(Category cat) { LongAdder longAdder = new LongAdder(); longAdder.decrement(); try { @@ -191,7 +200,7 @@ public class CategoryManager { * * @return the TagName used for this Category */ - public TagName getTagName(Category cat) { + synchronized public TagName getTagName(Category cat) { return catTagNameMap.getUnchecked(cat); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java index 6692bf873f..2710020c45 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java @@ -43,8 +43,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; */ public class SummaryTablePane extends AnchorPane { - private static SummaryTablePane instance; - @FXML private TableColumn, String> catColumn; @@ -53,6 +51,7 @@ public class SummaryTablePane extends AnchorPane { @FXML private TableView> tableView; + private final ImageGalleryController controller; @FXML void initialize() { @@ -74,19 +73,14 @@ public class SummaryTablePane extends AnchorPane { tableView.getColumns().setAll(Arrays.asList(catColumn, countColumn)); -// //register for category events - ImageGalleryController.getDefault().getCategoryManager().registerListener(this); + //register for category events + controller.getCategoryManager().registerListener(this); } - private SummaryTablePane() { + public SummaryTablePane(ImageGalleryController controller) { + this.controller = controller; FXMLConstructor.construct(this, "SummaryTablePane.fxml"); - } - public static synchronized SummaryTablePane getDefault() { - if (instance == null) { - instance = new SummaryTablePane(); - } - return instance; } /** @@ -101,7 +95,7 @@ public class SummaryTablePane extends AnchorPane { final ObservableList> data = FXCollections.observableArrayList(); if (Case.isCaseOpen()) { for (Category cat : Category.values()) { - data.add(new Pair<>(cat, ImageGalleryController.getDefault().getCategoryManager().getCategoryCount(cat))); + data.add(new Pair<>(cat, controller.getCategoryManager().getCategoryCount(cat))); } } Platform.runLater(() -> { From 9bdaab4f031e6b67982c762f0752d115ada74227 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 15:20:02 -0400 Subject: [PATCH 138/198] more tag/category autopsy integeration update CategoryCounts, FollowUp and Category border on general Tag Event use most severe category if multiple categories are present for a file enforce category ordering via enum declaration order --- .../imagegallery/datamodel/Category.java | 9 +++++--- .../imagegallery/datamodel/DrawableFile.java | 7 +++--- .../imagegallery/gui/DrawableView.java | 22 +++++++++++-------- .../imagegallery/gui/DrawableViewBase.java | 6 ++--- .../imagegallery/gui/MetaDataPane.java | 4 ++-- .../imagegallery/gui/SummaryTablePane.java | 5 +---- 6 files changed, 28 insertions(+), 25 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index ee6a46098e..aed95afec6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -28,14 +28,17 @@ import org.sleuthkit.datamodel.TagName; /** * Enum to represent the six categories in the DHs image categorization scheme. */ -public enum Category implements Comparable { +public enum Category { - ZERO(Color.LIGHTGREY, 0, "CAT-0: Uncategorized"), + /* This order of declaration is required so that Enum's compareTo method + * preserves the fact that lower category numbers are first/most sever, + * except 0 which is last */ ONE(Color.RED, 1, "CAT-1: Child Exploitation (Illegal)"), TWO(Color.ORANGE, 2, "CAT-2: Child Exploitation (Non-Illegal/Age Difficult)"), THREE(Color.YELLOW, 3, "CAT-3: CGI/Animation (Child Exploitive)"), FOUR(Color.BISQUE, 4, "CAT-4: Exemplar/Comparison (Internal Use Only)"), - FIVE(Color.GREEN, 5, "CAT-5: Non-pertinent"); + FIVE(Color.GREEN, 5, "CAT-5: Non-pertinent"), + ZERO(Color.LIGHTGREY, 0, "CAT-0: Uncategorized"); /** map from displayName to enum value */ private static final Map nameMap diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 4d3de0d553..3890ca577a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -268,22 +268,21 @@ public abstract class DrawableFile extends AbstractFile return category; } - public void updateCategory() { + /** set the category property to the most severe one found */ + private void updateCategory() { try { category.set(getSleuthkitCase().getContentTagsByContent(this).stream() .map(Tag::getName).filter(Category::isCategoryTagName) - .findFirst() .map(TagName::getDisplayName) .map(Category::fromDisplayName) + .sorted().findFirst() //sort by severity and take the first .orElse(Category.ZERO) ); - } catch (TskCoreException ex) { Logger.getLogger(DrawableFile.class.getName()).log(Level.WARNING, "problem looking up category for file " + this.getName(), ex); } catch (IllegalStateException ex) { // We get here many times if the case is closed during ingest, so don't print out a ton of warnings. } - } public abstract Image getThumbnail(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 93dbae801e..99d8671a63 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -108,15 +108,19 @@ public interface DrawableView { @ThreadConfined(type = ThreadConfined.ThreadType.ANY) default Category updateCategoryBorder() { - final Category category = getFile().getCategory(); - final Border border = hasHashHit() && (category == Category.ZERO) - ? HASH_BORDER - : getCategoryBorder(category); + if (getFile() != null) { + final Category category = getFile().getCategory(); + final Border border = hasHashHit() && (category == Category.ZERO) + ? HASH_BORDER + : getCategoryBorder(category); - Platform.runLater(() -> { - getCategoryBorderRegion().setBorder(border); - getCategoryBorderRegion().requestLayout(); - }); - return category; + Platform.runLater(() -> { + getCategoryBorderRegion().setBorder(border); + getCategoryBorderRegion().requestLayout(); + }); + return category; + } else { + return Category.ZERO; + } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 52ac70def0..38c48c2951 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -2,7 +2,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-14 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -302,7 +302,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Override synchronized public void handleTagsChanged(TagsChangeEvent evnt) { - if (fileID != null && evnt.getFileIDs().contains(fileID)) { + if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { updateFollowUpIcon(); } } @@ -386,7 +386,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { - if (evt.getFileIDs().contains(getFileID())) { + if (evt.getFileIDs().contains(getFileID()) || evt.getFileIDs().contains(-1L)) { updateCategoryBorder(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index 4ab6fff208..4f4cace550 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -225,7 +225,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @Subscribe @Override public void handleCategoryChanged(CategoryChangeEvent evt) { - if (getFile() != null && evt.getFileIDs().contains(getFileID())) { + if (getFile() != null && (evt.getFileIDs().contains(-1L) || evt.getFileIDs().contains(getFileID()))) { updateUI(); } } @@ -233,7 +233,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @Override @Subscribe public void handleTagsChanged(TagsChangeEvent evt) { - if (getFile() != null && evt.getFileIDs().contains(getFileID())) { + if (getFile() != null && (evt.getFileIDs().contains(-1L) || evt.getFileIDs().contains(getFileID()))) { updateUI(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java index 2710020c45..955cf0760f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java @@ -75,6 +75,7 @@ public class SummaryTablePane extends AnchorPane { //register for category events controller.getCategoryManager().registerListener(this); + handleCategoryChanged(null); } public SummaryTablePane(ImageGalleryController controller) { @@ -88,10 +89,6 @@ public class SummaryTablePane extends AnchorPane { */ @Subscribe public void handleCategoryChanged(CategoryChangeEvent evt) { - refresh(); - } - - public void refresh() { final ObservableList> data = FXCollections.observableArrayList(); if (Case.isCaseOpen()) { for (Category cat : Category.values()) { From 762037c649593efc4b90345f564037311446dc54 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 16:57:28 -0400 Subject: [PATCH 139/198] new Tag event system --- .../imagegallery/DrawableTagsManager.java | 148 +++++++++++------- .../imagegallery/ImageGalleryController.java | 30 +++- .../actions/CategorizeAction.java | 1 + .../actions/DeleteFollowUpTagAction.java | 70 ++++----- .../imagegallery/datamodel/Category.java | 3 + .../imagegallery/grouping/GroupManager.java | 6 +- .../imagegallery/gui/DrawableViewBase.java | 15 +- 7 files changed, 163 insertions(+), 110 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 7e0303fe4d..add7065742 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -45,6 +45,7 @@ public class DrawableTagsManager { private static final String FOLLOW_UP = "Follow Up"; + private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; /** Used to distribute {@link TagsChangeEvent}s */ @@ -64,26 +65,21 @@ public class DrawableTagsManager { * * @param autopsyTagsManager */ - public synchronized void setAutopsyTagsManager(TagsManager autopsyTagsManager) { - this.autopsyTagsManager = autopsyTagsManager; - clearFollowUpTagName(); + public void setAutopsyTagsManager(TagsManager autopsyTagsManager) { + synchronized (autopsyTagsManager) { + this.autopsyTagsManager = autopsyTagsManager; + clearFollowUpTagName(); + } } /** * Use when closing a case to make sure everything is re-initialized in the * next case. */ - public synchronized void clearFollowUpTagName() { - followUpTagName = null; - } - - /** - * fire a TagsChangeEvent with the given fileIDs - * - * @param fileIDs - */ - public final void fireChange(Collection fileIDs) { - tagsEventBus.post(new TagsChangeEvent(fileIDs)); + public void clearFollowUpTagName() { + synchronized (autopsyTagsManager) { + followUpTagName = null; + } } /** @@ -111,22 +107,26 @@ public class DrawableTagsManager { * * @throws TskCoreException */ - synchronized public TagName getFollowUpTagName() throws TskCoreException { - if (Objects.isNull(followUpTagName)) { - followUpTagName = getTagName(FOLLOW_UP); + public TagName getFollowUpTagName() throws TskCoreException { + synchronized (autopsyTagsManager) { + if (Objects.isNull(followUpTagName)) { + followUpTagName = getTagName(FOLLOW_UP); + } + return followUpTagName; } - return followUpTagName; } - synchronized public Collection getNonCategoryTagNames() { - try { - return autopsyTagsManager.getAllTagNames().stream() - .filter(Category::isCategoryTagName) - .collect(Collectors.toSet()); - } catch (TskCoreException | IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + public Collection getNonCategoryTagNames() { + synchronized (autopsyTagsManager) { + try { + return autopsyTagsManager.getAllTagNames().stream() + .filter(Category::isCategoryTagName) + .collect(Collectors.toSet()); + } catch (TskCoreException | IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + } + return Collections.emptySet(); } - return Collections.emptySet(); } /** @@ -139,29 +139,33 @@ public class DrawableTagsManager { * * @throws TskCoreException */ - public synchronized List getContentTagsByContent(Content content) throws TskCoreException { - return autopsyTagsManager.getContentTagsByContent(content); - } - - public synchronized TagName getTagName(String displayName) throws TskCoreException { - try { - for (TagName tn : autopsyTagsManager.getAllTagNames()) { - if (displayName.equals(tn.getDisplayName())) { - return tn; - } - } - try { - return autopsyTagsManager.addTagName(displayName); - } catch (TagsManager.TagNameAlreadyExistsException ex) { - throw new TskCoreException("tagame exists but wasn't found", ex); - } - } catch (IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); - throw new TskCoreException("Case was closed out from underneath", ex); + public List getContentTagsByContent(Content content) throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getContentTagsByContent(content); } } - public synchronized TagName getTagName(Category cat) { + public TagName getTagName(String displayName) throws TskCoreException { + synchronized (autopsyTagsManager) { + try { + for (TagName tn : autopsyTagsManager.getAllTagNames()) { + if (displayName.equals(tn.getDisplayName())) { + return tn; + } + } + try { + return autopsyTagsManager.addTagName(displayName); + } catch (TagsManager.TagNameAlreadyExistsException ex) { + throw new TskCoreException("tagame exists but wasn't found", ex); + } + } catch (IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); + throw new TskCoreException("Case was closed out from underneath", ex); + } + } + } + + public TagName getTagName(Category cat) { try { return getTagName(cat.getDisplayName()); } catch (TskCoreException ex) { @@ -169,12 +173,18 @@ public class DrawableTagsManager { } } - synchronized public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { - autopsyTagsManager.addContentTag(file, tagName, comment); + public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { + ContentTag addContentTag; + synchronized (autopsyTagsManager) { + addContentTag = autopsyTagsManager.addContentTag(file, tagName, comment); + } + fireTagAdded(addContentTag); } - synchronized public List getContentTagsByTagName(TagName t) throws TskCoreException { - return autopsyTagsManager.getContentTagsByTagName(t); + public List getContentTagsByTagName(TagName t) throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getContentTagsByTagName(t); + } } /** @@ -189,15 +199,43 @@ public class DrawableTagsManager { * refreshes based on them. */ static public void refreshTagsInAutopsy() { - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS } - public synchronized List getAllTagNames() throws TskCoreException { - return autopsyTagsManager.getAllTagNames(); + public List getAllTagNames() throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getAllTagNames(); + } } - public synchronized List getTagNamesInUse() throws TskCoreException { - return autopsyTagsManager.getTagNamesInUse(); + public List getTagNamesInUse() throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getTagNamesInUse(); + } } + + public void fireTagAdded(ContentTag newTag) { + tagsEventBus.post(new TagsChangeEvent(Collections.singleton(newTag.getContent().getId()))); + } + + public void fireTagDeleted(ContentTag oldTag) { + tagsEventBus.post(new TagsChangeEvent(Collections.singleton(oldTag.getContent().getId()))); + } +// +// /** +// * fire a TagsChangeEvent with the given fileIDs +// * +// * @param fileIDs +// */ +// public final void fireChange(Collection fileIDs) { +// tagsEventBus.post(new TagsChangeEvent(fileIDs)); +// } + + public void deleteContentTag(ContentTag ct) throws TskCoreException { + synchronized (autopsyTagsManager) { + autopsyTagsManager.deleteContentTag(ct); + } + fireTagDeleted(ct); + } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 6c54db8185..046c88bc7a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -58,7 +58,10 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.History; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; +import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; @@ -67,11 +70,11 @@ import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase; @@ -436,11 +439,6 @@ public final class ImageGalleryController { case CONTENT_CHANGED: //TODO: do we need to do anything here? -jm case DATA_ADDED: - ModuleDataEvent oldValue = (ModuleDataEvent) evt.getOldValue(); - if ("TagAction".equals(oldValue.getModuleName()) && oldValue.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { - getTagsManager().fireChange(Collections.singleton(-1L)); - getCategoryManager().invalidateCaches(); - } /* we could listen to DATA events and progressivly * update files, and get data from DataSource ingest * modules, but given that most modules don't post new @@ -491,6 +489,26 @@ public final class ImageGalleryController { setStale(true); } break; + case CONTENT_TAG_ADDED: + ContentTag newTag = (ContentTag) evt.getNewValue(); + if (Category.isCategoryTagName(newTag.getName())) { + new CategorizeAction(ImageGalleryController.this).addTag(newTag.getName(), ""); + } else { + getTagsManager().fireTagAdded(newTag); + } + break; + case CONTENT_TAG_DELETED: + ContentTag oldTag = (ContentTag) evt.getOldValue(); + final long fileID = oldTag.getContent().getId(); + if (getDatabase().isInDB(fileID)) { + if (Category.isCategoryTagName(oldTag.getName())) { + getCategoryManager().decrementCategoryCount(Category.fromTagName(oldTag.getName())); + getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); + } else { + getTagsManager().fireTagDeleted(oldTag); + } + } + break; } }); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 27f599cafe..8918934a6e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -161,4 +161,5 @@ public class CategorizeAction extends AddTagAction { DrawableTagsManager.refreshTagsInAutopsy(); } } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index bba6d5e4dc..98fdc316ad 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; +import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; @@ -43,49 +44,40 @@ public class DeleteFollowUpTagAction extends Action { private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTagAction.class.getName()); private final long fileID; - private final DrawableFile file; - private final ImageGalleryController controller; - public DeleteFollowUpTagAction(ImageGalleryController controller, DrawableFile file) { + public DeleteFollowUpTagAction(final ImageGalleryController controller, final DrawableFile file) { super("Delete Follow Up Tag"); - this.controller = controller; - this.file = file; this.fileID = file.getId(); setEventHandler((ActionEvent t) -> { - deleteTag(); + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + final GroupManager groupManager = controller.getGroupManager(); + final DrawableTagsManager tagsManager = controller.getTagsManager(); + + try { + final TagName followUpTagName = tagsManager.getFollowUpTagName(); + // remove file from old category group + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); + + List contentTagsByContent = tagsManager.getContentTagsByContent(file); + for (ContentTag ct : contentTagsByContent) { + if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { + tagsManager.deleteContentTag(ct); + } + } + + DrawableTagsManager.refreshTagsInAutopsy(); + //make sure rest of ui hears category change. + groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); + } + return null; + } + }.execute(); }); } - - /** - * - * - * - */ - private void deleteTag() { - - final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); - final GroupManager groupManager = controller.getGroupManager(); - final DrawableTagsManager tagsManager = controller.getTagsManager(); - - try { - final TagName followUpTagName = tagsManager.getFollowUpTagName(); - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); - - List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { - sleuthKitCase.deleteContentTag(ct); - } - } - - DrawableTagsManager.refreshTagsInAutopsy(); - - //make sure rest of ui hears category change. - groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); - } - } - } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index aed95afec6..00750c4ba9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -49,6 +49,9 @@ public enum Category { public static Category fromDisplayName(String displayName) { return nameMap.get(displayName); } + public static Category fromTagName(TagName tagName) { + return nameMap.get(tagName.getDisplayName()); + } public static boolean isCategoryTagName(TagName tName) { return isCategoryName(tName.getDisplayName()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 2027dae724..51a99bd5f7 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -595,9 +595,9 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { //we fire this event for all files so that the category counts get updated during initial db population controller.getCategoryManager().fireChange(fileIDs); - if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { - controller.getTagsManager().fireChange(fileIDs); - } +// if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { +// controller.getTagsManager().fireChange(fileIDs); +// } } private void popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 38c48c2951..93026d688d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -300,13 +300,6 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie return fileID; } - @Override - synchronized public void handleTagsChanged(TagsChangeEvent evnt) { - if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { - updateFollowUpIcon(); - } - } - synchronized protected void updateFollowUpIcon() { if (file != null) { try { @@ -383,6 +376,14 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie return imageBorder; } + @Subscribe + @Override + synchronized public void handleTagsChanged(TagsChangeEvent evnt) { + if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { + updateFollowUpIcon(); + } + } + @Subscribe @Override synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { From 78bab47b34c444b7d033c33eeddcc214ae58114e Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 17:00:05 -0400 Subject: [PATCH 140/198] more granular synchronization in DrawableTagsManager --- .../casemodule/services/TagsManager.java | 1 + .../imagegallery/DrawableTagsManager.java | 34 +++++++------------ 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 01daae9fba..f94976b572 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -404,6 +404,7 @@ public class TagsManager implements Closeable { getExistingTagNames(); } + Case.getPropertyChangeSupport().firePropertyChange(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString(), tag, null); tskCase.deleteBlackboardArtifactTag(tag); try { Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index add7065742..13455d2fb1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -45,7 +45,7 @@ public class DrawableTagsManager { private static final String FOLLOW_UP = "Follow Up"; - private Object autopsyTagsManagerLock = new Object(); + final private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; /** Used to distribute {@link TagsChangeEvent}s */ @@ -66,7 +66,7 @@ public class DrawableTagsManager { * @param autopsyTagsManager */ public void setAutopsyTagsManager(TagsManager autopsyTagsManager) { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { this.autopsyTagsManager = autopsyTagsManager; clearFollowUpTagName(); } @@ -77,7 +77,7 @@ public class DrawableTagsManager { * next case. */ public void clearFollowUpTagName() { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { followUpTagName = null; } } @@ -108,7 +108,7 @@ public class DrawableTagsManager { * @throws TskCoreException */ public TagName getFollowUpTagName() throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { if (Objects.isNull(followUpTagName)) { followUpTagName = getTagName(FOLLOW_UP); } @@ -117,7 +117,7 @@ public class DrawableTagsManager { } public Collection getNonCategoryTagNames() { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { try { return autopsyTagsManager.getAllTagNames().stream() .filter(Category::isCategoryTagName) @@ -140,13 +140,13 @@ public class DrawableTagsManager { * @throws TskCoreException */ public List getContentTagsByContent(Content content) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getContentTagsByContent(content); } } public TagName getTagName(String displayName) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { try { for (TagName tn : autopsyTagsManager.getAllTagNames()) { if (displayName.equals(tn.getDisplayName())) { @@ -175,14 +175,14 @@ public class DrawableTagsManager { public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { ContentTag addContentTag; - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { addContentTag = autopsyTagsManager.addContentTag(file, tagName, comment); } fireTagAdded(addContentTag); } public List getContentTagsByTagName(TagName t) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getContentTagsByTagName(t); } } @@ -203,13 +203,13 @@ public class DrawableTagsManager { } public List getAllTagNames() throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getAllTagNames(); } } public List getTagNamesInUse() throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getTagNamesInUse(); } } @@ -221,21 +221,11 @@ public class DrawableTagsManager { public void fireTagDeleted(ContentTag oldTag) { tagsEventBus.post(new TagsChangeEvent(Collections.singleton(oldTag.getContent().getId()))); } -// -// /** -// * fire a TagsChangeEvent with the given fileIDs -// * -// * @param fileIDs -// */ -// public final void fireChange(Collection fileIDs) { -// tagsEventBus.post(new TagsChangeEvent(fileIDs)); -// } public void deleteContentTag(ContentTag ct) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { autopsyTagsManager.deleteContentTag(ct); } fireTagDeleted(ct); } - } From 929f8c9c9c018979d4d6bde6d7d4c30d12f5fc2a Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 10:22:18 -0400 Subject: [PATCH 141/198] Tag Events - created new Case.Event enum values for BlackBoard/Content tags added/deleted - created new PropertyChangeEvent subclasses for BlackBoard/Content tags added/deleted - replaced ModuleDataEvent hack with new Tag Events - removed [in] from javadocs, other minor cleanup --- .../sleuthkit/autopsy/casemodule/Case.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index b4c61305b2..30216d3140 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -547,6 +547,59 @@ public class Case implements SleuthkitCase.ErrorObserver { } } + /** + * Notifies the UI that a new ContentTag has been added. + * + * @param newTag new ContentTag added + */ + public void notifyContentTagAdded(ContentTag newTag) { + notify(new ContentTagAddedEvent(newTag)); + } + + /** + * Notifies the UI that a ContentTag has been deleted. + * + * @param deletedTag ContentTag deleted + */ + public void notifyContentTagDeleted(ContentTag deletedTag) { + notify(new ContentTagDeletedEvent(deletedTag)); + } + + /** + * Notifies the UI that a new BlackboardArtifactTag has been added. + * + * @param newTag new BlackboardArtifactTag added + */ + public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) { + notify(new BlackBoardArtifactTagAddedEvent(newTag)); + } + + /** + * Notifies the UI that a BlackboardArtifactTag has been. + * + * @param deletedTag BlackboardArtifactTag deleted + */ + public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { + notify(new BlackBoardArtifactTagDeletedEvent(deletedTag)); + } + + /** + * Notifies the UI about a Case level event. + * + * @param propertyChangeEvent the event to distribute + */ + private void notify(final PropertyChangeEvent propertyChangeEvent) { + try { + pcs.firePropertyChange(propertyChangeEvent); + } catch (Exception e) { + logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS + MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), + NbBundle.getMessage(this.getClass(), + "Case.changeCase.errListenToCaseUpdates.msg"), + MessageNotifyUtil.MessageType.ERROR); + } + } + /** * @return The Services object for this case. */ From 22868333a0491fb55d83499cc3f0b889b8b99c9f Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 13:53:53 -0400 Subject: [PATCH 142/198] use new Autopsy Tag events, don't fire extra events from ig, but listen to events from autopsy --- .../imagegallery/DrawableTagsManager.java | 82 ++++++++----------- .../imagegallery/ImageGalleryController.java | 30 +++---- .../autopsy/imagegallery/TagsChangeEvent.java | 41 ---------- .../actions/AddDrawableTagAction.java | 9 +- .../imagegallery/actions/AddTagAction.java | 7 +- .../actions/CategorizeAction.java | 27 +++--- .../actions/DeleteFollowUpTagAction.java | 7 +- .../imagegallery/datamodel/Category.java | 12 --- .../datamodel/CategoryChangeEvent.java | 14 +++- .../datamodel/CategoryManager.java | 69 +++++++++++++++- .../imagegallery/datamodel/DrawableFile.java | 2 +- .../imagegallery/grouping/GroupManager.java | 64 +++++++++------ .../imagegallery/gui/DrawableView.java | 8 +- .../imagegallery/gui/DrawableViewBase.java | 18 ++-- .../imagegallery/gui/MetaDataPane.java | 18 ++-- 15 files changed, 208 insertions(+), 200 deletions(-) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 13455d2fb1..0bbc4b9d5a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -27,11 +27,11 @@ import java.util.logging.Level; import java.util.stream.Collectors; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -59,6 +59,32 @@ public class DrawableTagsManager { } + /** + * register an object to receive CategoryChangeEvents + * + * @param listner + */ + public void registerListener(Object listner) { + tagsEventBus.register(listner); + } + + /** + * unregister an object from receiving CategoryChangeEvents + * + * @param listener + */ + public void unregisterListener(Object listener) { + tagsEventBus.unregister(listener); + } + + public void fireTagAddedEvent(ContentTagAddedEvent event) { + tagsEventBus.post(event); + } + + public void fireTagDeletedEvent(ContentTagDeletedEvent event) { + tagsEventBus.post(event); + } + /** * assign a new TagsManager to back this one, ie when the current case * changes @@ -82,24 +108,6 @@ public class DrawableTagsManager { } } - /** - * register an object to receive CategoryChangeEvents - * - * @param listner - */ - public void registerListener(Object listner) { - tagsEventBus.register(listner); - } - - /** - * unregister an object from receiving CategoryChangeEvents - * - * @param listener - */ - public void unregisterListener(Object listener) { - tagsEventBus.unregister(listener); - } - /** * get the (cached) follow up TagName * @@ -120,7 +128,7 @@ public class DrawableTagsManager { synchronized (autopsyTagsManagerLock) { try { return autopsyTagsManager.getAllTagNames().stream() - .filter(Category::isCategoryTagName) + .filter(CategoryManager::isCategoryTagName) .collect(Collectors.toSet()); } catch (TskCoreException | IllegalStateException ex) { Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); @@ -173,12 +181,10 @@ public class DrawableTagsManager { } } - public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { - ContentTag addContentTag; + public ContentTag addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { synchronized (autopsyTagsManagerLock) { - addContentTag = autopsyTagsManager.addContentTag(file, tagName, comment); + return autopsyTagsManager.addContentTag(file, tagName, comment); } - fireTagAdded(addContentTag); } public List getContentTagsByTagName(TagName t) throws TskCoreException { @@ -187,21 +193,6 @@ public class DrawableTagsManager { } } - /** - * Fire the ModuleDataEvent that we use as a place holder for a real Tag - * Event. This is used to refresh the autopsy tag tree and the ui in - * ImageGallery - * - * - * Note: this is a hack. In an ideal world, TagsManager would fire - * events so that the directory tree would refresh. But, we haven't - * had a chance to add that so, we fire these events and the tree - * refreshes based on them. - */ - static public void refreshTagsInAutopsy() { - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - } - public List getAllTagNames() throws TskCoreException { synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getAllTagNames(); @@ -214,18 +205,9 @@ public class DrawableTagsManager { } } - public void fireTagAdded(ContentTag newTag) { - tagsEventBus.post(new TagsChangeEvent(Collections.singleton(newTag.getContent().getId()))); - } - - public void fireTagDeleted(ContentTag oldTag) { - tagsEventBus.post(new TagsChangeEvent(Collections.singleton(oldTag.getContent().getId()))); - } - public void deleteContentTag(ContentTag ct) throws TskCoreException { synchronized (autopsyTagsManagerLock) { autopsyTagsManager.deleteContentTag(ct); } - fireTagDeleted(ct); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 046c88bc7a..6c6bd7c789 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.imagegallery; import java.beans.PropertyChangeEvent; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.BlockingQueue; @@ -58,10 +57,9 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.History; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; @@ -74,7 +72,6 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase; @@ -366,6 +363,8 @@ public final class ImageGalleryController { categoryManager.setDb(db); tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); tagsManager.registerListener(groupManager); + tagsManager.registerListener(categoryManager); + } else { reset(); } @@ -384,6 +383,7 @@ public final class ImageGalleryController { }); tagsManager.clearFollowUpTagName(); tagsManager.unregisterListener(groupManager); + tagsManager.unregisterListener(categoryManager); Toolbar.getDefault(this).reset(); groupManager.clear(); @@ -490,23 +490,15 @@ public final class ImageGalleryController { } break; case CONTENT_TAG_ADDED: - ContentTag newTag = (ContentTag) evt.getNewValue(); - if (Category.isCategoryTagName(newTag.getName())) { - new CategorizeAction(ImageGalleryController.this).addTag(newTag.getName(), ""); - } else { - getTagsManager().fireTagAdded(newTag); + final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt; + if (getDatabase().isInDB((tagAddedEvent).getAddedTag().getContent().getId())) { + getTagsManager().fireTagAddedEvent(tagAddedEvent); } break; case CONTENT_TAG_DELETED: - ContentTag oldTag = (ContentTag) evt.getOldValue(); - final long fileID = oldTag.getContent().getId(); - if (getDatabase().isInDB(fileID)) { - if (Category.isCategoryTagName(oldTag.getName())) { - getCategoryManager().decrementCategoryCount(Category.fromTagName(oldTag.getName())); - getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); - } else { - getTagsManager().fireTagDeleted(oldTag); - } + final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) evt; + if (getDatabase().isInDB((tagDeletedEvent).getDeletedTag().getContent().getId())) { + getTagsManager().fireTagDeletedEvent(tagDeletedEvent); } break; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java deleted file mode 100644 index 0647a18456..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery; - -import java.util.Collection; -import java.util.Collections; -import javax.annotation.concurrent.Immutable; - -/** - * - */ -@Immutable -public class TagsChangeEvent { - - private final Collection fileIDs; - - public Collection getFileIDs() { - return Collections.unmodifiableCollection(fileIDs); - } - - public TagsChangeEvent(Collection fileIDs) { - this.fileIDs = fileIDs; - } - -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index e88c51f12b..be9343f4de 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -28,11 +27,8 @@ import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.openide.util.Utilities; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TagName; @@ -87,10 +83,9 @@ public class AddDrawableTagAction extends AddTagAction { JOptionPane.showMessageDialog(null, "Unable to tag " + fileID + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); } - //make sure rest of ui hears category change. - controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); +// //make sure rest of ui hears category change. +// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } - DrawableTagsManager.refreshTagsInAutopsy(); return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index abc441fb61..615b9b7f7d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -31,7 +31,7 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -95,11 +95,10 @@ abstract class AddTagAction { // a tag with the associated tag name. if (null != tagNames && !tagNames.isEmpty()) { for (final TagName tagName : tagNames) { - if (Category.isNotCategoryTagName(tagName)) { + if (CategoryManager.isNotCategoryTagName(tagName)) { MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); tagNameItem.setOnAction((ActionEvent t) -> { addTag(tagName, NO_COMMENT); - DrawableTagsManager.refreshTagsInAutopsy(); }); quickTagMenu.getItems().add(tagNameItem); } @@ -134,7 +133,7 @@ abstract class AddTagAction { SwingUtilities.invokeLater(() -> { GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); if (null != tagNameAndComment) { - if (Category.isCategoryTagName(tagNameAndComment.getTagName())) { + if (CategoryManager.isCategoryTagName(tagNameAndComment.getTagName())) { new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } else { new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 8918934a6e..067a5cf967 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -32,7 +31,6 @@ import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; @@ -41,7 +39,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -87,6 +84,10 @@ public class CategorizeAction extends AddTagAction { } } + public void enforceOneCat(TagName name, String string) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + /** * Instances of this class implement a context menu user interface for * selecting a category @@ -127,8 +128,8 @@ public class CategorizeAction extends AddTagAction { @Override public void run() { final GroupManager groupManager = controller.getGroupManager(); - final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); final CategoryManager categoryManager = controller.getCategoryManager(); + final DrawableTagsManager tagsManager = controller.getTagsManager(); try { DrawableFile file = controller.getFileFromId(fileID); //drawable db @@ -138,27 +139,27 @@ public class CategorizeAction extends AddTagAction { groupManager.removeFromGroup(new GroupKey(DrawableAttribute.CATEGORY, oldCat), fileID); //memory //remove old category tag if necessary - List allContentTags = sleuthKitCase.getContentTagsByContent(file); //tsk db + List allContentTags = tagsManager.getContentTagsByContent(file); //tsk db + //JMTODO: move this to CategoryManager for (ContentTag ct : allContentTags) { - if (Category.isCategoryTagName(ct.getName())) { - sleuthKitCase.deleteContentTag(ct); //tsk db - categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db + if (CategoryManager.isCategoryTagName(ct.getName())) { + tagsManager.deleteContentTag(ct); //tsk db +// categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db } } - categoryManager.incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db +// categoryManager.incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db if (tagName != categoryManager.getTagName(Category.ZERO)) { // no tags for cat-0 - controller.getTagsManager().addContentTag(file, tagName, comment); //tsk db + tagsManager.addContentTag(file, tagName, comment); //tsk db } - //make sure rest of ui hears category change. - groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui +// //make sure rest of ui hears category change. +// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error categorizing result", ex); JOptionPane.showMessageDialog(null, "Unable to categorize " + fileID + ".", "Categorizing Error", JOptionPane.ERROR_MESSAGE); } - DrawableTagsManager.refreshTagsInAutopsy(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 98fdc316ad..aab8a9c827 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.util.Collections; import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; @@ -26,14 +25,12 @@ import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -53,7 +50,6 @@ public class DeleteFollowUpTagAction extends Action { @Override protected Void doInBackground() throws Exception { - final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); final GroupManager groupManager = controller.getGroupManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); @@ -69,9 +65,8 @@ public class DeleteFollowUpTagAction extends Action { } } - DrawableTagsManager.refreshTagsInAutopsy(); //make sure rest of ui hears category change. - groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); +// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 00750c4ba9..8999fff2f1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -23,7 +23,6 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import javafx.scene.paint.Color; -import org.sleuthkit.datamodel.TagName; /** * Enum to represent the six categories in the DHs image categorization scheme. @@ -49,17 +48,6 @@ public enum Category { public static Category fromDisplayName(String displayName) { return nameMap.get(displayName); } - public static Category fromTagName(TagName tagName) { - return nameMap.get(tagName.getDisplayName()); - } - - public static boolean isCategoryTagName(TagName tName) { - return isCategoryName(tName.getDisplayName()); - } - - public static boolean isNotCategoryTagName(TagName tName) { - return isNotCategoryName(tName.getDisplayName()); - } public static boolean isCategoryName(String tName) { return nameMap.containsKey(tName); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java index 9896325e09..3868864737 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java @@ -30,6 +30,16 @@ import javax.annotation.concurrent.Immutable; public class CategoryChangeEvent { private final Collection fileIDs; + private final Category newCategory; + + public CategoryChangeEvent(Collection fileIDs, Category newCategory) { + this.fileIDs = fileIDs; + this.newCategory = newCategory; + } + + public Category getNewCategory() { + return newCategory; + } /** * @return the fileIDs of the files whose categories have changed @@ -37,8 +47,4 @@ public class CategoryChangeEvent { public Collection getFileIDs() { return Collections.unmodifiableCollection(fileIDs); } - - public CategoryChangeEvent(Collection fileIDs) { - this.fileIDs = fileIDs; - } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index f8b0e6beb1..b6a11d2b25 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -24,11 +24,17 @@ import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; /** * Provides a cached view of the number of files per category, and fires @@ -94,13 +100,13 @@ public class CategoryManager { this.db = db; categoryCounts.invalidateAll(); catTagNameMap.invalidateAll(); - fireChange(Collections.singleton(-1L)); + fireChange(Collections.emptyList(), null); } synchronized public void invalidateCaches() { categoryCounts.invalidateAll(); catTagNameMap.invalidateAll(); - fireChange(Collections.singleton(-1L)); + fireChange(Collections.emptyList(), null); } /** @@ -173,8 +179,8 @@ public class CategoryManager { * * @param fileIDs */ - public void fireChange(Collection fileIDs) { - categoryEventBus.post(new CategoryChangeEvent(fileIDs)); + public void fireChange(Collection fileIDs, Category newCategory) { + categoryEventBus.post(new CategoryChangeEvent(fileIDs, newCategory)); } /** @@ -204,4 +210,59 @@ public class CategoryManager { return catTagNameMap.getUnchecked(cat); } + + public static Category fromTagName(TagName tagName) { + return Category.fromDisplayName(tagName.getDisplayName()); + } + + public static boolean isCategoryTagName(TagName tName) { + return Category.isCategoryName(tName.getDisplayName()); + } + + public static boolean isNotCategoryTagName(TagName tName) { + return Category.isNotCategoryName(tName.getDisplayName()); + + } + + public void handleTagAdded(ContentTagAddedEvent event) { + ContentTag addedTag = event.getAddedTag(); + if (isCategoryTagName(addedTag.getName())) { + final DrawableTagsManager tagsManager = controller.getTagsManager(); + try { + //remove old category tag(s) if necessary + List allContentTags = tagsManager.getContentTagsByContent(addedTag.getContent()); + + for (ContentTag ct : allContentTags) { + if (ct.getId() != addedTag.getId() + && CategoryManager.isCategoryTagName(ct.getName())) { + try { + tagsManager.deleteContentTag(ct); + } catch (TskCoreException tskException) { + LOGGER.log(Level.SEVERE, "Failed to delete content tag. Unable to maintain categories in a consistent state.", tskException); + } + } + } + } catch (TskCoreException tskException) { + LOGGER.log(Level.SEVERE, "Failed to get content tags for content. Unable to maintain category in a consistent state.", tskException); + } + Category newCat = CategoryManager.fromTagName(addedTag.getName()); + if (newCat != Category.ZERO) { + incrementCategoryCount(newCat); + } + + fireChange(Collections.singleton(addedTag.getId()), newCat); + } + } + + public void handleTagDeleted(ContentTagDeletedEvent event) { + ContentTag deleted = event.getDeletedTag(); + if (isCategoryTagName(deleted.getName())) { + + Category deletedCat = CategoryManager.fromTagName(deleted.getName()); + if (deletedCat != Category.ZERO) { + decrementCategoryCount(deletedCat); + } + fireChange(Collections.singleton(deleted.getId()), null); + } + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 3890ca577a..79ea49f879 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -272,7 +272,7 @@ public abstract class DrawableFile extends AbstractFile private void updateCategory() { try { category.set(getSleuthkitCase().getContentTagsByContent(this).stream() - .map(Tag::getName).filter(Category::isCategoryTagName) + .map(Tag::getName).filter(CategoryManager::isCategoryTagName) .map(TagName::getDisplayName) .map(Category::fromDisplayName) .sorted().findFirst() //sort by severity and take the first diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 51a99bd5f7..733baf2813 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -60,12 +60,14 @@ import org.sleuthkit.autopsy.coreutils.LoggedTask; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; -import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -161,7 +163,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { Set> resultSet = new HashSet<>(); for (Comparable val : groupBy.getValue(file)) { if (groupBy == DrawableAttribute.TAGS) { - if (Category.isNotCategoryTagName((TagName) val)) { + if (CategoryManager.isNotCategoryTagName((TagName) val)) { resultSet.add(new GroupKey(groupBy, val)); } } else { @@ -282,6 +284,10 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { }); } } + } else { //group == null + // It may be that this was the last unanalyzed file in the group, so test + // whether the group is now fully analyzed. + popuplateIfAnalyzed(groupKey, null); } return group; @@ -360,7 +366,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { break; case TAGS: values = (List) controller.getTagsManager().getTagNamesInUse().stream() - .filter(Category::isNotCategoryTagName) + .filter(CategoryManager::isNotCategoryTagName) .collect(Collectors.toList()); break; case ANALYZED: @@ -528,14 +534,31 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } @Subscribe - public void handleAutopsyTagChange(TagsChangeEvent evt) { - if (groupBy == DrawableAttribute.TAGS - && evt.getFileIDs().size() == 1 - && evt.getFileIDs().contains(-1L)) { - regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); + public void handleTagAdded(ContentTagAddedEvent evt) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + final long fileID = evt.getAddedTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); + + } + + private void addFileToGroup(DrawableGroup g, final GroupKey groupKey, final long fileID) { + if (g == null) { + //if there wasn't already a group check if there should be one now + popuplateIfAnalyzed(groupKey, null); + } else { + //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. + g.addFile(fileID); } } + @Subscribe + public void handleTagDeleted(ContentTagDeletedEvent evt) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); + final long fileID = evt.getDeletedTag().getContent().getId(); + DrawableGroup g = removeFromGroup(groupKey, fileID); + } + @Override synchronized public void handleFileRemoved(FileUpdateEvent evt) { Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.REMOVE); @@ -545,13 +568,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { Set> groupsForFile = getGroupKeysForFileID(fileId); for (GroupKey gk : groupsForFile) { - DrawableGroup g = removeFromGroup(gk, fileId); - - if (g == null) { - // It may be that this was the last unanalyzed file in the group, so test - // whether the group is now fully analyzed. - popuplateIfAnalyzed(gk, null); - } + removeFromGroup(gk, fileId); } } } @@ -578,29 +595,21 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { //get grouping(s) this file would be in Set> groupsForFile = getGroupKeysForFileID(fileId); - for (GroupKey gk : groupsForFile) { DrawableGroup g = getGroupForKey(gk); - - if (g == null) { - //if there wasn't already a group check if there should be one now - popuplateIfAnalyzed(gk, null); - } else { - //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. - g.addFile(fileId); - } + addFileToGroup(g, gk, fileId); } } //we fire this event for all files so that the category counts get updated during initial db population - controller.getCategoryManager().fireChange(fileIDs); + controller.getCategoryManager().fireChange(fileIDs, null); // if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { // controller.getTagsManager().fireChange(fileIDs); // } } - private void popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { + private DrawableGroup popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { if (Objects.nonNull(task) && (task.isCancelled())) { /* if this method call is part of a ReGroupTask and that task is @@ -609,6 +618,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * this allows us to stop if a regroup task has been cancelled (e.g. * the user picked a different group by attribute, while the * current task was still running) */ + } else { // no task or un-cancelled task if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { /* for attributes other than path we can't be sure a group is @@ -639,12 +649,14 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } markGroupSeen(group, groupSeen); }); + return group; } } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); } } } + return null; } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 99d8671a63..9b442273d1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -12,8 +12,9 @@ import javafx.scene.layout.Region; import javafx.scene.paint.Color; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; @@ -68,7 +69,10 @@ public interface DrawableView { void handleCategoryChanged(CategoryChangeEvent evt); @Subscribe - void handleTagsChanged(TagsChangeEvent evt); + void handleTagAdded(ContentTagAddedEvent evt); + + @Subscribe + void handleTagDeleted(ContentTagDeletedEvent evt); ImageGalleryController getController(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index 93026d688d..ea88d2dfbb 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -61,10 +61,11 @@ import org.sleuthkit.autopsy.datamodel.FileNode; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; -import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; @@ -378,16 +379,21 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override - synchronized public void handleTagsChanged(TagsChangeEvent evnt) { - if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { - updateFollowUpIcon(); - } + public void handleTagAdded(ContentTagAddedEvent evt) { + + updateFollowUpIcon(); + } + + @Subscribe + @Override + public void handleTagDeleted(ContentTagDeletedEvent evt) { + updateFollowUpIcon(); } @Subscribe @Override synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { - if (evt.getFileIDs().contains(getFileID()) || evt.getFileIDs().contains(-1L)) { + if (fileID != null && evt.getFileIDs().contains(getFileID())) { updateCategoryBorder(); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index 4f4cace550..0681d29eb9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -44,8 +44,9 @@ import javafx.scene.text.Text; import javafx.util.Pair; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -225,16 +226,23 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @Subscribe @Override public void handleCategoryChanged(CategoryChangeEvent evt) { - if (getFile() != null && (evt.getFileIDs().contains(-1L) || evt.getFileIDs().contains(getFileID()))) { + if (getFile() != null && evt.getFileIDs().contains(getFileID())) { updateUI(); } } @Override - @Subscribe - public void handleTagsChanged(TagsChangeEvent evt) { - if (getFile() != null && (evt.getFileIDs().contains(-1L) || evt.getFileIDs().contains(getFileID()))) { + public void handleTagAdded(ContentTagAddedEvent evt) { + if (getFile() != null && evt.getAddedTag().getContent().getId() == getFileID()) { updateUI(); } } + + @Override + public void handleTagDeleted(ContentTagDeletedEvent evt) { + if (getFile() != null && evt.getDeletedTag().getContent().getId() == getFileID()) { + updateUI(); + } + } + } From 13ad8aaaeb07bcdb55cf209f55e0d0ffd2d6829d Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 17:20:35 -0400 Subject: [PATCH 143/198] remove uneeded notification code; let event handlers do it all. optionalize DrawableView --- Core/nbproject/project.xml | 1 + .../actions/AddDrawableTagAction.java | 3 - .../actions/CategorizeAction.java | 33 +- .../actions/DeleteFollowUpTagAction.java | 11 +- .../datamodel/CategoryManager.java | 3 +- .../imagegallery/grouping/GroupManager.java | 26 +- .../imagegallery/gui/DrawableTile.java | 16 +- .../imagegallery/gui/DrawableView.java | 13 +- .../imagegallery/gui/DrawableViewBase.java | 301 ++++++++++-------- .../imagegallery/gui/MetaDataPane.java | 114 ++++--- .../imagegallery/gui/SlideShowView.java | 81 +++-- 11 files changed, 341 insertions(+), 261 deletions(-) diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index ac5f32a1ac..463e1c1903 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -192,6 +192,7 @@ org.sleuthkit.autopsy.coreutils org.sleuthkit.autopsy.datamodel org.sleuthkit.autopsy.directorytree + org.sleuthkit.autopsy.events org.sleuthkit.autopsy.externalresults org.sleuthkit.autopsy.filesearch org.sleuthkit.autopsy.ingest diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index be9343f4de..3c115d9134 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -82,9 +82,6 @@ public class AddDrawableTagAction extends AddTagAction { LOGGER.log(Level.SEVERE, "Error tagging result", ex); JOptionPane.showMessageDialog(null, "Unable to tag " + fileID + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); } - -// //make sure rest of ui hears category change. -// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 067a5cf967..afe2b3bb5d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.logging.Level; import javafx.event.ActionEvent; @@ -34,11 +33,7 @@ import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -127,33 +122,25 @@ public class CategorizeAction extends AddTagAction { @Override public void run() { - final GroupManager groupManager = controller.getGroupManager(); final CategoryManager categoryManager = controller.getCategoryManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); try { DrawableFile file = controller.getFileFromId(fileID); //drawable db - Category oldCat = file.getCategory(); - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.CATEGORY, oldCat), fileID); //memory - - //remove old category tag if necessary - List allContentTags = tagsManager.getContentTagsByContent(file); //tsk db - - //JMTODO: move this to CategoryManager - for (ContentTag ct : allContentTags) { - if (CategoryManager.isCategoryTagName(ct.getName())) { - tagsManager.deleteContentTag(ct); //tsk db -// categoryManager.decrementCategoryCount(Category.fromDisplayName(ct.getName().getDisplayName())); //memory/drawable db - } - } -// categoryManager.incrementCategoryCount(Category.fromDisplayName(tagName.getDisplayName())); //memory/drawable db if (tagName != categoryManager.getTagName(Category.ZERO)) { // no tags for cat-0 tagsManager.addContentTag(file, tagName, comment); //tsk db + } else { + tagsManager.getContentTagsByContent(file).stream() + .filter(tag -> CategoryManager.isCategoryTagName(tag.getName())) + .forEach((ct) -> { + try { + tagsManager.deleteContentTag(ct); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error removing old categories result", ex); + } + }); } -// //make sure rest of ui hears category change. -// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); //memory/ui } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error categorizing result", ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index aab8a9c827..74082fcd1c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -26,10 +26,7 @@ import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -50,23 +47,17 @@ public class DeleteFollowUpTagAction extends Action { @Override protected Void doInBackground() throws Exception { - final GroupManager groupManager = controller.getGroupManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); try { final TagName followUpTagName = tagsManager.getFollowUpTagName(); - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); - + List contentTagsByContent = tagsManager.getContentTagsByContent(file); for (ContentTag ct : contentTagsByContent) { if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { tagsManager.deleteContentTag(ct); } } - - //make sure rest of ui hears category change. -// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index b6a11d2b25..466278f588 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -224,6 +224,7 @@ public class CategoryManager { } + @Subscribe public void handleTagAdded(ContentTagAddedEvent event) { ContentTag addedTag = event.getAddedTag(); if (isCategoryTagName(addedTag.getName())) { @@ -253,7 +254,7 @@ public class CategoryManager { fireChange(Collections.singleton(addedTag.getId()), newCat); } } - + @Subscribe public void handleTagDeleted(ContentTagDeletedEvent event) { ContentTag deleted = event.getDeletedTag(); if (isCategoryTagName(deleted.getName())) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 733baf2813..9ac899742c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -279,8 +279,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { if (groupKey.getAttribute() != DrawableAttribute.CATEGORY) { if (group.fileIds().isEmpty()) { Platform.runLater(() -> { - analyzedGroups.remove(group); - unSeenGroups.remove(group); + if (analyzedGroups.contains(group)) { + analyzedGroups.remove(group); + } + if (unSeenGroups.contains(group)) { + unSeenGroups.remove(group); + } }); } } @@ -535,10 +539,12 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); - final long fileID = evt.getAddedTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); + if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + final long fileID = evt.getAddedTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); + } } @@ -554,9 +560,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagDeleted(ContentTagDeletedEvent evt) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); - final long fileID = evt.getDeletedTag().getContent().getId(); - DrawableGroup g = removeFromGroup(groupKey, fileID); + if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); + final long fileID = evt.getDeletedTag().getContent().getId(); + DrawableGroup g = removeFromGroup(groupKey, fileID); + } } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java index 75332ba158..96f05dd9c1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java @@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableViewBase.globalSelectionModel; +import org.sleuthkit.datamodel.AbstractContent; /** * GUI component that represents a single image as a tile with an icon, a label, @@ -109,15 +110,20 @@ public class DrawableTile extends DrawableViewBase { @Override protected Runnable getContentUpdateRunnable() { - Image image = getFile().getThumbnail(); + if (getFile().isPresent()) { + Image image = getFile().get().getThumbnail(); - return () -> { - imageView.setImage(image); - }; + return () -> { + imageView.setImage(image); + }; + } else { + return () -> { //no-op + }; + } } @Override protected String getTextForLabel() { - return getFile().getName(); + return getFile().map(AbstractContent::getName).orElse(""); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index 9b442273d1..e4e6faf1de 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -1,6 +1,8 @@ package org.sleuthkit.autopsy.imagegallery.gui; import com.google.common.eventbus.Subscribe; +import java.util.Collection; +import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; import javafx.scene.layout.Border; @@ -51,11 +53,11 @@ public interface DrawableView { Region getCategoryBorderRegion(); - DrawableFile getFile(); + Optional> getFile(); void setFile(final Long fileID); - Long getFileID(); + Optional getFileID(); /** * update the visual representation of the category of the assigned file. @@ -78,7 +80,10 @@ public interface DrawableView { default boolean hasHashHit() { try { - return getFile().getHashHitSetNames().isEmpty() == false; + return getFile().map(DrawableFile::getHashHitSetNames) + .map((Collection t) -> t.isEmpty() == false) + .orElse(false); + } catch (NullPointerException ex) { // I think this happens when we're in the process of removing images from the view while // also trying to update it? @@ -113,7 +118,7 @@ public interface DrawableView { @ThreadConfined(type = ThreadConfined.ThreadType.ANY) default Category updateCategoryBorder() { if (getFile() != null) { - final Category category = getFile().getCategory(); + final Category category = getFile().map(DrawableFile::getCategory).orElse(Category.ZERO); final Border border = hasHashHit() && (category == Category.ZERO) ? HASH_BORDER : getCategoryBorder(category); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java index ea88d2dfbb..a1ee32a108 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java @@ -23,6 +23,8 @@ import com.google.common.eventbus.Subscribe; import java.util.ArrayList; import java.util.Collection; import java.util.Objects; +import static java.util.Objects.nonNull; +import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; import javafx.beans.Observable; @@ -130,9 +132,33 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie static private ContextMenu contextMenu; - private DrawableFile file; + volatile private Optional> fileOpt = Optional.empty(); - private Long fileID; + volatile private Optional fileIDOpt = Optional.empty(); + + @Override + public Optional getFileID() { + return fileIDOpt; + } + + @Override + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + try { + fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); + } catch (TskCoreException ex) { + Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); + fileOpt = Optional.empty(); + } + return fileOpt; + } + } else { + return Optional.empty(); + } + } /** * the groupPane this {@link DrawableViewBase} is embedded in @@ -158,43 +184,44 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Override public void handle(MouseEvent t) { + getFile().ifPresent(file -> { + final long fileID = file.getId(); + switch (t.getButton()) { + case PRIMARY: + if (t.getClickCount() == 1) { + if (t.isControlDown()) { - switch (t.getButton()) { - case PRIMARY: - if (t.getClickCount() == 1) { - if (t.isControlDown()) { - globalSelectionModel.toggleSelection(fileID); - } else { - groupPane.makeSelection(t.isShiftDown(), fileID); + globalSelectionModel.toggleSelection(fileID); + } else { + groupPane.makeSelection(t.isShiftDown(), fileID); + } + } else if (t.getClickCount() > 1) { + groupPane.activateSlideShowViewer(fileID); } - } else if (t.getClickCount() > 1) { - groupPane.activateSlideShowViewer(fileID); - } - break; - case SECONDARY: - - if (t.getClickCount() == 1) { - if (globalSelectionModel.isSelected(fileID) == false) { - groupPane.makeSelection(false, fileID); + break; + case SECONDARY: + if (t.getClickCount() == 1) { + if (globalSelectionModel.isSelected(fileID) == false) { + groupPane.makeSelection(false, fileID); + } } - } + if (contextMenu != null) { + contextMenu.hide(); + } + final ContextMenu groupContextMenu = groupPane.getContextMenu(); + if (groupContextMenu != null) { + groupContextMenu.hide(); + } + contextMenu = buildContextMenu(file); + contextMenu.show(DrawableViewBase.this, t.getScreenX(), t.getScreenY()); + break; + } + }); - if (contextMenu != null) { - contextMenu.hide(); - } - final ContextMenu groupContextMenu = groupPane.getContextMenu(); - if (groupContextMenu != null) { - groupContextMenu.hide(); - } - contextMenu = buildContextMenu(); - contextMenu.show(DrawableViewBase.this, t.getScreenX(), t.getScreenY()); - - break; - } t.consume(); } - private ContextMenu buildContextMenu() { + private ContextMenu buildContextMenu(DrawableFile file) { final ArrayList menuItems = new ArrayList<>(); menuItems.add(new CategorizeAction(controller).getPopupMenu()); @@ -213,13 +240,13 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie MenuItem contentViewer = new MenuItem("Show Content Viewer"); contentViewer.setOnAction((ActionEvent t) -> { SwingUtilities.invokeLater(() -> { - new NewWindowViewAction("Show Content Viewer", new FileNode(getFile().getAbstractFile())).actionPerformed(null); + new NewWindowViewAction("Show Content Viewer", new FileNode(file.getAbstractFile())).actionPerformed(null); }); }); menuItems.add(contentViewer); MenuItem externalViewer = new MenuItem("Open in External Viewer"); - final ExternalViewerAction externalViewerAction = new ExternalViewerAction("Open in External Viewer", new FileNode(getFile().getAbstractFile())); + final ExternalViewerAction externalViewerAction = new ExternalViewerAction("Open in External Viewer", new FileNode(file.getAbstractFile())); externalViewer.setDisable(externalViewerAction.isEnabled() == false); externalViewer.setOnAction((ActionEvent t) -> { @@ -259,116 +286,106 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @SuppressWarnings("deprecation") protected void initialize() { followUpToggle.setOnAction((ActionEvent event) -> { - if (followUpToggle.isSelected() == true) { - try { - final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); - globalSelectionModel.clearAndSelect(fileID); - new AddDrawableTagAction(controller).addTag(followUpTagName, ""); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); + getFile().ifPresent(file -> { + if (followUpToggle.isSelected() == true) { + try { + final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); + globalSelectionModel.clearAndSelect(file.getId()); + new AddDrawableTagAction(controller).addTag(followUpTagName, ""); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); + } + } else { + new DeleteFollowUpTagAction(controller, file).handle(event); } - } else { - new DeleteFollowUpTagAction(controller, file).handle(event); - } + }); }); } - @Override - public DrawableFile getFile() { - if (fileID != null) { - if (file == null || file.getId() != fileID) { - try { - file = ImageGalleryController.getDefault().getFileFromId(fileID); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileID, ex); - file = null; - } - } - return file; - } else { - return null; - } - } - - protected boolean hasFollowUp() throws TskCoreException { - String followUpTagName = getController().getTagsManager().getFollowUpTagName().getDisplayName(); - Collection tagNames = DrawableAttribute.TAGS.getValue(getFile()); - return tagNames.stream().anyMatch((tn) -> tn.getDisplayName().equals(followUpTagName)); - } - - @Override - synchronized public Long getFileID() { - return fileID; - } - - synchronized protected void updateFollowUpIcon() { - if (file != null) { + protected boolean hasFollowUp() { + if (getFile().isPresent()) { try { - boolean hasFollowUp = hasFollowUp(); - Platform.runLater(() -> { - followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray); - followUpToggle.setSelected(hasFollowUp); - }); + TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); + Collection tagNames = DrawableAttribute.TAGS.getValue(getFile().get()); + return tagNames.stream().anyMatch((tn) -> tn.equals(followUpTagName)); } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + LOGGER.log(Level.WARNING, "failed to get follow up tag name ", ex); + return true; } + } else { + return false; } } @Override - synchronized public void setFile(final Long fileID) { - if (Objects.equals(fileID, this.fileID) == false) { - this.fileID = fileID; - disposeContent(); - - if (this.fileID == null || Case.isCaseOpen() == false) { - if (registered == true) { - getController().getCategoryManager().unregisterListener(this); - getController().getTagsManager().unregisterListener(this); - registered = false; - } - file = null; - Platform.runLater(() -> { - clearContent(); - }); - } else { - if (registered == false) { - getController().getCategoryManager().registerListener(this); - getController().getTagsManager().registerListener(this); - registered = true; - } - file = null; - getFile(); - updateSelectionState(); - updateCategoryBorder(); - updateFollowUpIcon(); - updateUI(); - Platform.runLater(getContentUpdateRunnable()); + public void setFile(final Long newFileID) { + if (fileIDOpt.isPresent()) { + if (Objects.equals(newFileID, fileIDOpt.get()) == false) { + setFileHelper(newFileID); } + } else { + if (nonNull(newFileID)) { + setFileHelper(newFileID); + } + } + } + + private void setFileHelper(final Long newFileID) { + fileIDOpt = Optional.ofNullable(newFileID); + disposeContent(); + + if (fileIDOpt.isPresent() == false || Case.isCaseOpen() == false) { + if (registered == true) { + getController().getCategoryManager().unregisterListener(this); + getController().getTagsManager().unregisterListener(this); + registered = false; + } + fileOpt = Optional.empty(); + Platform.runLater(() -> { + clearContent(); + }); + } else { + if (registered == false) { + getController().getCategoryManager().registerListener(this); + getController().getTagsManager().registerListener(this); + registered = true; + } + fileOpt = Optional.empty(); + + updateSelectionState(); + updateCategoryBorder(); + updateFollowUpIcon(); + updateUI(); + Platform.runLater(getContentUpdateRunnable()); } } private void updateUI() { - final boolean isVideo = getFile().isVideo(); - final boolean hasHashSetHits = hasHashHit(); - final String text = getTextForLabel(); + getFile().ifPresent(file -> { + final boolean isVideo = file.isVideo(); + final boolean hasHashSetHits = hasHashHit(); + final String text = getTextForLabel(); - Platform.runLater(() -> { - fileTypeImageView.setImage(isVideo ? videoIcon : null); - hashHitImageView.setImage(hasHashSetHits ? hashHitIcon : null); - nameLabel.setText(text); - nameLabel.setTooltip(new Tooltip(text)); + Platform.runLater(() -> { + fileTypeImageView.setImage(isVideo ? videoIcon : null); + hashHitImageView.setImage(hasHashSetHits ? hashHitIcon : null); + nameLabel.setText(text); + nameLabel.setTooltip(new Tooltip(text)); + }); }); + } /** * update the visual representation of the selection state of this * DrawableView */ - synchronized protected void updateSelectionState() { - final boolean selected = globalSelectionModel.isSelected(getFileID()); - Platform.runLater(() -> { - setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER); + protected void updateSelectionState() { + getFile().ifPresent(file -> { + final boolean selected = globalSelectionModel.isSelected(file.getId()); + Platform.runLater(() -> { + setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER); + }); }); } @@ -380,22 +397,54 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { + fileIDOpt.ifPresent(fileID -> { + try { + if (fileID == evt.getAddedTag().getContent().getId() + && evt.getAddedTag().getName() == getController().getTagsManager().getFollowUpTagName()) { - updateFollowUpIcon(); + Platform.runLater(() -> { + followUpImageView.setImage(followUpIcon); + followUpToggle.setSelected(true); + }); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + } + }); } @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - updateFollowUpIcon(); + + fileIDOpt.ifPresent(fileID -> { + try { + if (fileID == evt.getDeletedTag().getContent().getId() + && evt.getDeletedTag().getName() == controller.getTagsManager().getFollowUpTagName()) { + updateFollowUpIcon(); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + } + }); + } + + private void updateFollowUpIcon() { + boolean hasFollowUp = hasFollowUp(); + Platform.runLater(() -> { + followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray); + followUpToggle.setSelected(hasFollowUp); + }); } @Subscribe @Override - synchronized public void handleCategoryChanged(CategoryChangeEvent evt) { - if (fileID != null && evt.getFileIDs().contains(getFileID())) { - updateCategoryBorder(); - } + public void handleCategoryChanged(CategoryChangeEvent evt) { + fileIDOpt.ifPresent(fileID -> { + if (evt.getFileIDs().contains(fileID)) { + updateCategoryBorder(); + } + }); } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index 0681d29eb9..87bd64491f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -22,6 +22,9 @@ import com.google.common.eventbus.Subscribe; import java.io.IOException; import java.util.Arrays; import java.util.Collection; +import java.util.Objects; +import static java.util.Objects.nonNull; +import java.util.Optional; import java.util.logging.Level; import java.util.stream.Collectors; import javafx.application.Platform; @@ -68,8 +71,6 @@ public class MetaDataPane extends AnchorPane implements DrawableView { return controller; } - private Long fileID; - @FXML private ImageView imageView; @@ -85,13 +86,6 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @FXML private BorderPane imageBorder; - private DrawableFile file; - - @Override - public Long getFileID() { - return fileID; - } - @FXML @SuppressWarnings("unchecked") void initialize() { @@ -152,29 +146,52 @@ public class MetaDataPane extends AnchorPane implements DrawableView { }); } + volatile private Optional> fileOpt = Optional.empty(); + + volatile private Optional fileIDOpt = Optional.empty(); + @Override - public DrawableFile getFile() { - if (fileID != null) { - if (file == null || file.getId() != fileID) { - try { - file = controller.getFileFromId(fileID); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileID, ex); - return null; - } - } - } else { - return null; - } - return file; + public Optional getFileID() { + return fileIDOpt; } @Override - public void setFile(Long fileID) { - this.fileID = fileID; + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + try { + fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); + } catch (TskCoreException ex) { + Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); + fileOpt = Optional.empty(); + } + return fileOpt; + } + } else { + return Optional.empty(); + } + } - if (fileID == null) { + @Override + public void setFile(Long newFileID) { + if (fileIDOpt.isPresent()) { + if (Objects.equals(newFileID, fileIDOpt.get()) == false) { + setFileHelper(newFileID); + } + } else { + if (nonNull(newFileID)) { + setFileHelper(newFileID); + } + } + setFileHelper(newFileID); + } + + private void setFileHelper(Long newFileID) { + fileIDOpt = Optional.of(newFileID); + if (newFileID == null) { Platform.runLater(() -> { imageView.setImage(null); tableView.getItems().clear(); @@ -182,12 +199,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { }); } else { - try { - file = controller.getFileFromId(fileID); - updateUI(); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Failed to get drawable file from ID", ex); - } + updateUI(); } } @@ -206,15 +218,18 @@ public class MetaDataPane extends AnchorPane implements DrawableView { } public void updateUI() { - final Image icon = getFile().getThumbnail(); - final ObservableList, ? extends Object>> attributesList = getFile().getAttributesList(); + getFile().ifPresent(file -> { + final Image icon = file.getThumbnail(); + final ObservableList, ? extends Object>> attributesList = file.getAttributesList(); - Platform.runLater(() -> { - imageView.setImage(icon); - tableView.getItems().setAll(attributesList); + Platform.runLater(() -> { + imageView.setImage(icon); + tableView.getItems().setAll(attributesList); + }); + + updateCategoryBorder(); }); - updateCategoryBorder(); } @Override @@ -226,23 +241,28 @@ public class MetaDataPane extends AnchorPane implements DrawableView { @Subscribe @Override public void handleCategoryChanged(CategoryChangeEvent evt) { - if (getFile() != null && evt.getFileIDs().contains(getFileID())) { - updateUI(); - } + getFileID().ifPresent(fileID -> { + if (evt.getFileIDs().contains(fileID)) { + updateUI(); + } + }); } @Override public void handleTagAdded(ContentTagAddedEvent evt) { - if (getFile() != null && evt.getAddedTag().getContent().getId() == getFileID()) { - updateUI(); - } + handleTagChanged(evt.getAddedTag().getContent().getId()); } @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - if (getFile() != null && evt.getDeletedTag().getContent().getId() == getFileID()) { - updateUI(); - } + handleTagChanged(evt.getDeletedTag().getContent().getId()); } + private void handleTagChanged(Long tagFileID) { + getFileID().ifPresent(fileID -> { + if (Objects.equals(tagFileID, fileID)) { + updateUI(); + } + }); + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index 7977eb0219..ab74554b39 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.imagegallery.gui; import java.util.ArrayList; +import java.util.function.Function; import java.util.logging.Level; import javafx.application.Platform; import javafx.beans.Observable; @@ -48,14 +49,15 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.ImageFile; import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile; +import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.CAT_BORDER_WIDTH; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.HASH_BORDER; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.getCategoryBorder; import org.sleuthkit.datamodel.TagName; @@ -235,9 +237,9 @@ public class SlideShowView extends DrawableViewBase { @Override synchronized public void setFile(final Long fileID) { super.setFile(fileID); - if (this.getFileID() != null) { - getGroupPane().makeSelection(false, this.getFileID()); - } + getFileID().ifPresent((Long id) -> { + getGroupPane().makeSelection(false, id); + }); } @Override @@ -254,24 +256,33 @@ public class SlideShowView extends DrawableViewBase { @Override protected Runnable getContentUpdateRunnable() { - if (getFile().isVideo()) { - return () -> { - imageBorder.setCenter(MediaControl.create((VideoFile) getFile())); - }; - } else { - ImageView imageView = new ImageView(((ImageFile) getFile()).getFullSizeImage()); - imageView.setPreserveRatio(true); - imageView.fitWidthProperty().bind(imageBorder.widthProperty().subtract(CAT_BORDER_WIDTH * 2)); - imageView.fitHeightProperty().bind(this.heightProperty().subtract(CAT_BORDER_WIDTH * 4).subtract(footer.heightProperty()).subtract(toolBar.heightProperty())); - return () -> { - imageBorder.setCenter(imageView); - }; - } + + return getFile().map(new Function, Runnable>() { + + @Override + public Runnable apply(DrawableFile file) { + + if (file.isVideo()) { + return () -> { + imageBorder.setCenter(MediaControl.create((VideoFile) file)); + }; + } else { + ImageView imageView = new ImageView(((ImageFile) file).getFullSizeImage()); + imageView.setPreserveRatio(true); + imageView.fitWidthProperty().bind(imageBorder.widthProperty().subtract(CAT_BORDER_WIDTH * 2)); + imageView.fitHeightProperty().bind(heightProperty().subtract(CAT_BORDER_WIDTH * 4).subtract(footer.heightProperty()).subtract(toolBar.heightProperty())); + return () -> { + imageBorder.setCenter(imageView); + }; + } + } + }).orElse(() -> { + }); } @Override protected String getTextForLabel() { - return getFile().getName() + " " + getSupplementalText(); + return getFile().map(file -> file.getName() + " " + getSupplementalText()).orElse(""); } @ThreadConfined(type = ThreadType.JFX) @@ -302,18 +313,19 @@ public class SlideShowView extends DrawableViewBase { @Override @ThreadConfined(type = ThreadType.ANY) public Category updateCategoryBorder() { - final Category category = getFile().getCategory(); - final Border border = hasHashHit() && (category == Category.ZERO) - ? HASH_BORDER - : getCategoryBorder(category); - ToggleButton toggleForCategory = getToggleForCategory(category); + return getFile().map(file -> { + final Category category = file.getCategory(); + final Border border1 = hasHashHit() && (category == Category.ZERO) + ? HASH_BORDER + : getCategoryBorder(category); + ToggleButton toggleForCategory = getToggleForCategory(category); + Platform.runLater(() -> { + getCategoryBorderRegion().setBorder(border1); + toggleForCategory.setSelected(true); + }); + return category; + }).orElse(Category.ZERO); - Platform.runLater(() -> { - getCategoryBorderRegion().setBorder(border); - toggleForCategory.setSelected(true); - }); - - return category; } private ToggleButton getToggleForCategory(Category category) { @@ -345,10 +357,13 @@ public class SlideShowView extends DrawableViewBase { @Override public void changed(ObservableValue ov, Boolean t, Boolean t1) { - if (t1) { - FileIDSelectionModel.getInstance().clearAndSelect(getFileID()); - new CategorizeAction(getController()).addTag(getController().getTagsManager().getTagName(cat), ""); - } + getFileID().ifPresent(fileID -> { + if (t1) { + FileIDSelectionModel.getInstance().clearAndSelect(fileID); + new CategorizeAction(getController()).addTag(getController().getTagsManager().getTagName(cat), ""); + } + }); + } } } From f1000486b79557d475334435a62e92d858d6344c Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 13:33:07 -0400 Subject: [PATCH 144/198] fix bugs updating tags/categpries in slideshowview and metadata pane make new abstract base calss DrawableUIBase and move fileid and file object access to it. --- .../actions/DeleteFollowUpTagAction.java | 2 - .../datamodel/CategoryManager.java | 4 +- .../imagegallery/gui/DrawableTile.java | 7 +- ...bleViewBase.java => DrawableTileBase.java} | 121 +++++------------- .../imagegallery/gui/DrawableUIBase.java | 97 ++++++++++++++ .../imagegallery/gui/DrawableView.java | 18 +-- .../imagegallery/gui/MetaDataPane.java | 70 ++-------- .../imagegallery/gui/SlideShowView.java | 23 ++-- 8 files changed, 161 insertions(+), 181 deletions(-) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{DrawableViewBase.java => DrawableTileBase.java} (79%) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 74082fcd1c..934a3fb258 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -37,11 +37,9 @@ import org.sleuthkit.datamodel.TskCoreException; public class DeleteFollowUpTagAction extends Action { private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTagAction.class.getName()); - private final long fileID; public DeleteFollowUpTagAction(final ImageGalleryController controller, final DrawableFile file) { super("Delete Follow Up Tag"); - this.fileID = file.getId(); setEventHandler((ActionEvent t) -> { new SwingWorker() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 466278f588..4d2591aa1e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -251,7 +251,7 @@ public class CategoryManager { incrementCategoryCount(newCat); } - fireChange(Collections.singleton(addedTag.getId()), newCat); + fireChange(Collections.singleton(addedTag.getContent().getId()), newCat); } } @Subscribe @@ -263,7 +263,7 @@ public class CategoryManager { if (deletedCat != Category.ZERO) { decrementCategoryCount(deletedCat); } - fireChange(Collections.singleton(deleted.getId()), null); + fireChange(Collections.singleton(deleted.getContent().getId()), null); } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java index 96f05dd9c1..86a0b2ddee 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java @@ -32,7 +32,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableViewBase.globalSelectionModel; +import static org.sleuthkit.autopsy.imagegallery.gui.DrawableTileBase.globalSelectionModel; import org.sleuthkit.datamodel.AbstractContent; /** @@ -43,7 +43,7 @@ import org.sleuthkit.datamodel.AbstractContent; * * TODO: refactor this to extend from {@link Control}? -jm */ -public class DrawableTile extends DrawableViewBase { +public class DrawableTile extends DrawableTileBase { private static final DropShadow LAST_SELECTED_EFFECT = new DropShadow(10, Color.BLUE); @@ -67,7 +67,6 @@ public class DrawableTile extends DrawableViewBase { assert imageBorder != null : "fx:id=\"imageAnchor\" was not injected: check your FXML file 'DrawableTile.fxml'."; assert imageView != null : "fx:id=\"imageView\" was not injected: check your FXML file 'DrawableTile.fxml'."; assert nameLabel != null : "fx:id=\"nameLabel\" was not injected: check your FXML file 'DrawableTile.fxml'."; - //set up properties and binding setCache(true); setCacheHint(CacheHint.SPEED); @@ -87,9 +86,11 @@ public class DrawableTile extends DrawableViewBase { public DrawableTile(GroupPane gp) { super(gp); + FXMLConstructor.construct(this, "DrawableTile.fxml"); } + @Override @ThreadConfined(type = ThreadType.JFX) protected void clearContent() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java similarity index 79% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java index a1ee32a108..80c73b1ae9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableViewBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java @@ -22,8 +22,6 @@ package org.sleuthkit.autopsy.imagegallery.gui; import com.google.common.eventbus.Subscribe; import java.util.ArrayList; import java.util.Collection; -import java.util.Objects; -import static java.util.Objects.nonNull; import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; @@ -39,7 +37,6 @@ import javafx.scene.control.Tooltip; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; -import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Border; import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderStroke; @@ -66,13 +63,11 @@ import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.TagName; @@ -84,9 +79,9 @@ import org.sleuthkit.datamodel.TskCoreException; * of {@link DrawableView}s should implement the interface directly * */ -public abstract class DrawableViewBase extends AnchorPane implements DrawableView { +public abstract class DrawableTileBase extends DrawableUIBase { - private static final Logger LOGGER = Logger.getLogger(DrawableViewBase.class.getName()); + private static final Logger LOGGER = Logger.getLogger(DrawableTileBase.class.getName()); private static final Border UNSELECTED_BORDER = new Border(new BorderStroke(Color.GRAY, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3))); @@ -99,6 +94,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie protected static final Image followUpGray = new Image("org/sleuthkit/autopsy/imagegallery/images/flag_gray.png"); protected static final FileIDSelectionModel globalSelectionModel = FileIDSelectionModel.getInstance(); + private static ContextMenu contextMenu; /** * displays the icon representing video files @@ -130,50 +126,16 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @FXML protected BorderPane imageBorder; - static private ContextMenu contextMenu; - - volatile private Optional> fileOpt = Optional.empty(); - - volatile private Optional fileIDOpt = Optional.empty(); - - @Override - public Optional getFileID() { - return fileIDOpt; - } - - @Override - public Optional> getFile() { - if (fileIDOpt.isPresent()) { - if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { - return fileOpt; - } else { - try { - fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); - } catch (TskCoreException ex) { - Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); - fileOpt = Optional.empty(); - } - return fileOpt; - } - } else { - return Optional.empty(); - } - } - /** - * the groupPane this {@link DrawableViewBase} is embedded in + * the groupPane this {@link DrawableTileBase} is embedded in */ final private GroupPane groupPane; - private boolean registered = false; - private final ImageGalleryController controller; + volatile private boolean registered = false; - GroupPane getGroupPane() { - return groupPane; - } + protected DrawableTileBase(GroupPane groupPane) { + super(groupPane.getController()); - protected DrawableViewBase(GroupPane groupPane) { this.groupPane = groupPane; - this.controller = groupPane.getController(); globalSelectionModel.getSelected().addListener((Observable observable) -> { updateSelectionState(); }); @@ -213,7 +175,7 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie groupContextMenu.hide(); } contextMenu = buildContextMenu(file); - contextMenu.show(DrawableViewBase.this, t.getScreenX(), t.getScreenY()); + contextMenu.show(DrawableTileBase.this, t.getScreenX(), t.getScreenY()); break; } }); @@ -224,9 +186,9 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie private ContextMenu buildContextMenu(DrawableFile file) { final ArrayList menuItems = new ArrayList<>(); - menuItems.add(new CategorizeAction(controller).getPopupMenu()); + menuItems.add(new CategorizeAction(getController()).getPopupMenu()); - menuItems.add(new AddDrawableTagAction(controller).getPopupMenu()); + menuItems.add(new AddDrawableTagAction(getController()).getPopupMenu()); final MenuItem extractMenuItem = new MenuItem("Extract File(s)"); extractMenuItem.setOnAction((ActionEvent t) -> { @@ -274,6 +236,10 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie }); } + GroupPane getGroupPane() { + return groupPane; + } + @ThreadConfined(type = ThreadType.UI) protected abstract void clearContent(); @@ -283,31 +249,29 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie protected abstract String getTextForLabel(); - @SuppressWarnings("deprecation") protected void initialize() { followUpToggle.setOnAction((ActionEvent event) -> { getFile().ifPresent(file -> { if (followUpToggle.isSelected() == true) { try { - final TagName followUpTagName = controller.getTagsManager().getFollowUpTagName(); globalSelectionModel.clearAndSelect(file.getId()); - new AddDrawableTagAction(controller).addTag(followUpTagName, ""); + new AddDrawableTagAction(getController()).addTag(getController().getTagsManager().getFollowUpTagName(), ""); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); } } else { - new DeleteFollowUpTagAction(controller, file).handle(event); + new DeleteFollowUpTagAction(getController(), file).handle(event); } }); }); } protected boolean hasFollowUp() { - if (getFile().isPresent()) { + if (getFileID().isPresent()) { try { TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); - Collection tagNames = DrawableAttribute.TAGS.getValue(getFile().get()); - return tagNames.stream().anyMatch((tn) -> tn.equals(followUpTagName)); + return DrawableAttribute.TAGS.getValue(getFile().get()).stream() + .anyMatch(followUpTagName::equals); } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "failed to get follow up tag name ", ex); return true; @@ -318,29 +282,17 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie } @Override - public void setFile(final Long newFileID) { - if (fileIDOpt.isPresent()) { - if (Objects.equals(newFileID, fileIDOpt.get()) == false) { - setFileHelper(newFileID); - } - } else { - if (nonNull(newFileID)) { - setFileHelper(newFileID); - } - } - } - - private void setFileHelper(final Long newFileID) { - fileIDOpt = Optional.ofNullable(newFileID); + protected void setFileHelper(final Long newFileID) { + setFileIDOpt(Optional.ofNullable(newFileID)); disposeContent(); - if (fileIDOpt.isPresent() == false || Case.isCaseOpen() == false) { + if (getFileID().isPresent() == false || Case.isCaseOpen() == false) { if (registered == true) { getController().getCategoryManager().unregisterListener(this); getController().getTagsManager().unregisterListener(this); registered = false; } - fileOpt = Optional.empty(); + setFileOpt(Optional.empty()); Platform.runLater(() -> { clearContent(); }); @@ -350,10 +302,10 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie getController().getTagsManager().registerListener(this); registered = true; } - fileOpt = Optional.empty(); + setFileOpt(Optional.empty()); updateSelectionState(); - updateCategoryBorder(); + updateCategory(); updateFollowUpIcon(); updateUI(); Platform.runLater(getContentUpdateRunnable()); @@ -397,10 +349,10 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { - fileIDOpt.ifPresent(fileID -> { + getFileID().ifPresent(fileID -> { try { if (fileID == evt.getAddedTag().getContent().getId() - && evt.getAddedTag().getName() == getController().getTagsManager().getFollowUpTagName()) { + && evt.getAddedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { Platform.runLater(() -> { followUpImageView.setImage(followUpIcon); @@ -417,10 +369,10 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - fileIDOpt.ifPresent(fileID -> { + getFileID().ifPresent(fileID -> { try { if (fileID == evt.getDeletedTag().getContent().getId() - && evt.getDeletedTag().getName() == controller.getTagsManager().getFollowUpTagName()) { + && evt.getDeletedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { updateFollowUpIcon(); } } catch (TskCoreException ex) { @@ -436,19 +388,4 @@ public abstract class DrawableViewBase extends AnchorPane implements DrawableVie followUpToggle.setSelected(hasFollowUp); }); } - - @Subscribe - @Override - public void handleCategoryChanged(CategoryChangeEvent evt) { - fileIDOpt.ifPresent(fileID -> { - if (evt.getFileIDs().contains(fileID)) { - updateCategoryBorder(); - } - }); - } - - @Override - public ImageGalleryController getController() { - return controller; - } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java new file mode 100644 index 0000000000..ec794eabae --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java @@ -0,0 +1,97 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery.gui; + +import java.util.Objects; +import static java.util.Objects.nonNull; +import java.util.Optional; +import java.util.logging.Level; +import javafx.scene.layout.AnchorPane; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * + */ +abstract public class DrawableUIBase extends AnchorPane implements DrawableView { + + private final ImageGalleryController controller; + + volatile private Optional> fileOpt = Optional.empty(); + + volatile private Optional fileIDOpt = Optional.empty(); + + public DrawableUIBase(ImageGalleryController controller) { + this.controller = controller; + } + + @Override + public ImageGalleryController getController() { + return controller; + } + + @Override + public Optional getFileID() { + return fileIDOpt; + } + + void setFileIDOpt(Optional fileIDOpt) { + this.fileIDOpt = fileIDOpt; + } + + void setFileOpt(Optional> fileOpt) { + this.fileOpt = fileOpt; + } + + @Override + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + try { + fileOpt = Optional.of(getController().getFileFromId(fileIDOpt.get())); + } catch (TskCoreException ex) { + Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); + fileOpt = Optional.empty(); + } + return fileOpt; + } + } else { + return Optional.empty(); + } + } + + protected abstract void setFileHelper(Long newFileID); + + @Override + public void setFile(Long newFileID) { + if (getFileID().isPresent()) { + if (Objects.equals(newFileID, getFileID().get()) == false) { + setFileHelper(newFileID); + } + } else if (nonNull(newFileID)) { + setFileHelper(newFileID); + } + } + + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java index e4e6faf1de..709679173e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java @@ -68,7 +68,13 @@ public interface DrawableView { * @param evt the CategoryChangeEvent to handle */ @Subscribe - void handleCategoryChanged(CategoryChangeEvent evt); + default void handleCategoryChanged(CategoryChangeEvent evt) { + getFileID().ifPresent(fileID -> { + if (evt.getFileIDs().contains(fileID)) { + updateCategory(); + } + }); + } @Subscribe void handleTagAdded(ContentTagAddedEvent evt); @@ -116,16 +122,12 @@ public interface DrawableView { } @ThreadConfined(type = ThreadConfined.ThreadType.ANY) - default Category updateCategoryBorder() { - if (getFile() != null) { + default Category updateCategory() { + if (getFile().isPresent()) { final Category category = getFile().map(DrawableFile::getCategory).orElse(Category.ZERO); - final Border border = hasHashHit() && (category == Category.ZERO) - ? HASH_BORDER - : getCategoryBorder(category); - + final Border border = hasHashHit() && (category == Category.ZERO) ? HASH_BORDER : getCategoryBorder(category); Platform.runLater(() -> { getCategoryBorderRegion().setBorder(border); - getCategoryBorderRegion().requestLayout(); }); return category; } else { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index 87bd64491f..d89db4116c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -23,9 +23,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.Objects; -import static java.util.Objects.nonNull; import java.util.Optional; -import java.util.logging.Level; import java.util.stream.Collectors; import javafx.application.Platform; import javafx.beans.property.SimpleObjectProperty; @@ -39,7 +37,6 @@ import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.image.Image; import javafx.scene.image.ImageView; -import javafx.scene.layout.AnchorPane; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Region; import static javafx.scene.layout.Region.USE_COMPUTED_SIZE; @@ -53,24 +50,15 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; /** * Shows details of the selected file. */ -public class MetaDataPane extends AnchorPane implements DrawableView { +public class MetaDataPane extends DrawableUIBase { private static final Logger LOGGER = Logger.getLogger(MetaDataPane.class.getName()); - private final ImageGalleryController controller; - - @Override - public ImageGalleryController getController() { - return controller; - } - @FXML private ImageView imageView; @@ -141,56 +129,14 @@ public class MetaDataPane extends AnchorPane implements DrawableView { tableView.getColumns().setAll(Arrays.asList(attributeColumn, valueColumn)); //listen for selection change - controller.getSelectionModel().lastSelectedProperty().addListener((observable, oldFileID, newFileID) -> { + getController().getSelectionModel().lastSelectedProperty().addListener((observable, oldFileID, newFileID) -> { setFile(newFileID); }); } - volatile private Optional> fileOpt = Optional.empty(); - - volatile private Optional fileIDOpt = Optional.empty(); - @Override - public Optional getFileID() { - return fileIDOpt; - } - - @Override - public Optional> getFile() { - if (fileIDOpt.isPresent()) { - if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { - return fileOpt; - } else { - try { - fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); - } catch (TskCoreException ex) { - Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); - fileOpt = Optional.empty(); - } - return fileOpt; - } - } else { - return Optional.empty(); - } - } - - @Override - public void setFile(Long newFileID) { - - if (fileIDOpt.isPresent()) { - if (Objects.equals(newFileID, fileIDOpt.get()) == false) { - setFileHelper(newFileID); - } - } else { - if (nonNull(newFileID)) { - setFileHelper(newFileID); - } - } - setFileHelper(newFileID); - } - - private void setFileHelper(Long newFileID) { - fileIDOpt = Optional.of(newFileID); + synchronized protected void setFileHelper(Long newFileID) { + setFileIDOpt(Optional.ofNullable(newFileID)); if (newFileID == null) { Platform.runLater(() -> { imageView.setImage(null); @@ -204,7 +150,7 @@ public class MetaDataPane extends AnchorPane implements DrawableView { } public MetaDataPane(ImageGalleryController controller) { - this.controller = controller; + super(controller); FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MetaDataPane.fxml")); fxmlLoader.setRoot(this); @@ -224,12 +170,12 @@ public class MetaDataPane extends AnchorPane implements DrawableView { Platform.runLater(() -> { imageView.setImage(icon); + tableView.getItems().clear(); tableView.getItems().setAll(attributesList); }); - updateCategoryBorder(); + updateCategory(); }); - } @Override @@ -248,11 +194,13 @@ public class MetaDataPane extends AnchorPane implements DrawableView { }); } + @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { handleTagChanged(evt.getAddedTag().getContent().getId()); } + @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { handleTagChanged(evt.getDeletedTag().getContent().getId()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index ab74554b39..99944d6d19 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -58,8 +58,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.ImageFile; import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile; import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.CAT_BORDER_WIDTH; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.HASH_BORDER; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.getCategoryBorder; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -68,7 +66,7 @@ import org.sleuthkit.datamodel.TskCoreException; * GroupPane. TODO: Extract a subclass for video files in slideshow mode-jm * TODO: reduce coupling to GroupPane */ -public class SlideShowView extends DrawableViewBase { +public class SlideShowView extends DrawableTileBase { private static final Logger LOGGER = Logger.getLogger(SlideShowView.class.getName()); @@ -223,6 +221,7 @@ public class SlideShowView extends DrawableViewBase { SlideShowView(GroupPane gp) { super(gp); + FXMLConstructor.construct(this, "SlideShow.fxml"); } @@ -237,6 +236,7 @@ public class SlideShowView extends DrawableViewBase { @Override synchronized public void setFile(final Long fileID) { super.setFile(fileID); + getFileID().ifPresent((Long id) -> { getGroupPane().makeSelection(false, id); }); @@ -288,7 +288,7 @@ public class SlideShowView extends DrawableViewBase { @ThreadConfined(type = ThreadType.JFX) private void cycleSlideShowImage(int d) { stopVideo(); - if (getFileID() != null) { + if (getFileID().isPresent()) { int index = getGroupPane().getGrouping().fileIds().indexOf(getFileID()); final int size = getGroupPane().getGrouping().fileIds().size(); index = (index + d) % size; @@ -312,20 +312,17 @@ public class SlideShowView extends DrawableViewBase { @Override @ThreadConfined(type = ThreadType.ANY) - public Category updateCategoryBorder() { - return getFile().map(file -> { - final Category category = file.getCategory(); - final Border border1 = hasHashHit() && (category == Category.ZERO) - ? HASH_BORDER - : getCategoryBorder(category); + public Category updateCategory() { + if (getFile().isPresent()) { + final Category category = super.updateCategory(); ToggleButton toggleForCategory = getToggleForCategory(category); Platform.runLater(() -> { - getCategoryBorderRegion().setBorder(border1); toggleForCategory.setSelected(true); }); return category; - }).orElse(Category.ZERO); - + } else { + return Category.ZERO; + } } private ToggleButton getToggleForCategory(Category category) { From 6fa5b3b14c6e7f443e4b0b52df2647e69b07a16c Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 14:11:44 -0400 Subject: [PATCH 145/198] rename method in CategoryManager to be more descriptive; fix tag and category grouping when tags aer added / removed --- .../datamodel/CategoryManager.java | 6 ++-- .../imagegallery/grouping/GroupManager.java | 35 +++++++++++-------- .../imagegallery/gui/SlideShowView.java | 28 +++++++-------- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 4d2591aa1e..3a1a81e72d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -211,7 +211,7 @@ public class CategoryManager { } - public static Category fromTagName(TagName tagName) { + public static Category categoryFromTagName(TagName tagName) { return Category.fromDisplayName(tagName.getDisplayName()); } @@ -246,7 +246,7 @@ public class CategoryManager { } catch (TskCoreException tskException) { LOGGER.log(Level.SEVERE, "Failed to get content tags for content. Unable to maintain category in a consistent state.", tskException); } - Category newCat = CategoryManager.fromTagName(addedTag.getName()); + Category newCat = CategoryManager.categoryFromTagName(addedTag.getName()); if (newCat != Category.ZERO) { incrementCategoryCount(newCat); } @@ -259,7 +259,7 @@ public class CategoryManager { ContentTag deleted = event.getDeletedTag(); if (isCategoryTagName(deleted.getName())) { - Category deletedCat = CategoryManager.fromTagName(deleted.getName()); + Category deletedCat = CategoryManager.categoryFromTagName(deleted.getName()); if (deletedCat != Category.ZERO) { decrementCategoryCount(deletedCat); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 9ac899742c..90adfa76b8 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -539,20 +539,25 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { - if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); - final long fileID = evt.getAddedTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); + GroupKey groupKey = null; + if (groupBy == DrawableAttribute.TAGS) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + } else if (groupBy == DrawableAttribute.CATEGORY) { + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getAddedTag().getName())); } + final long fileID = evt.getAddedTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); } + @SuppressWarnings("AssignmentToMethodParameter") private void addFileToGroup(DrawableGroup g, final GroupKey groupKey, final long fileID) { if (g == null) { //if there wasn't already a group check if there should be one now - popuplateIfAnalyzed(groupKey, null); - } else { + g = popuplateIfAnalyzed(groupKey, null); + } + if (g != null) { //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. g.addFile(fileID); } @@ -560,11 +565,14 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { @Subscribe public void handleTagDeleted(ContentTagDeletedEvent evt) { - if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); - final long fileID = evt.getDeletedTag().getContent().getId(); - DrawableGroup g = removeFromGroup(groupKey, fileID); + GroupKey groupKey = null; + if (groupBy == DrawableAttribute.TAGS) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); + } else if (groupBy == DrawableAttribute.CATEGORY) { + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getDeletedTag().getName())); } + final long fileID = evt.getDeletedTag().getContent().getId(); + DrawableGroup g = removeFromGroup(groupKey, fileID); } @Override @@ -631,7 +639,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { /* for attributes other than path we can't be sure a group is * fully analyzed because we don't know all the files that - * will be a part of that group */ + * will be a part of that group,. just show them no matter what. */ try { Set fileIDs = getFileIDsInGroup(groupKey); @@ -643,9 +651,8 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { group = groupMap.get(groupKey); group.setFiles(ObjectUtils.defaultIfNull(fileIDs, Collections.emptySet())); } else { - group = new DrawableGroup(groupKey, fileIDs, groupSeen); - group.seenProperty().addListener((observable, oldSeen, newSeen) -> { + group.seenProperty().addListener((o, oldSeen, newSeen) -> { markGroupSeen(group, newSeen); }); groupMap.put(groupKey, group); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java index 99944d6d19..d7d0f684ed 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java @@ -25,6 +25,7 @@ import javafx.application.Platform; import javafx.beans.Observable; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; +import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; @@ -282,24 +283,20 @@ public class SlideShowView extends DrawableTileBase { @Override protected String getTextForLabel() { - return getFile().map(file -> file.getName() + " " + getSupplementalText()).orElse(""); + return getFile().map(file -> file.getName()).orElse("") + " " + getSupplementalText(); } @ThreadConfined(type = ThreadType.JFX) - private void cycleSlideShowImage(int d) { + private void cycleSlideShowImage(int direction) { stopVideo(); - if (getFileID().isPresent()) { - int index = getGroupPane().getGrouping().fileIds().indexOf(getFileID()); - final int size = getGroupPane().getGrouping().fileIds().size(); - index = (index + d) % size; - if (index < 0) { - index += size; - } - setFile(getGroupPane().getGrouping().fileIds().get(index)); + final int groupSize = getGroupPane().getGrouping().fileIds().size(); + final Integer nextIndex = getFileID().map(fileID -> { + final int currentIndex = getGroupPane().getGrouping().fileIds().indexOf(fileID); + return (currentIndex + direction + groupSize) % groupSize; + }).orElse(0); + setFile(getGroupPane().getGrouping().fileIds().get(nextIndex) + ); - } else { - setFile(getGroupPane().getGrouping().fileIds().get(0)); - } } /** @@ -307,7 +304,10 @@ public class SlideShowView extends DrawableTileBase { * of y" */ private String getSupplementalText() { - return " ( " + (getGroupPane().getGrouping().fileIds().indexOf(getFileID()) + 1) + " of " + getGroupPane().getGrouping().fileIds().size() + " in group )"; + final ObservableList fileIds = getGroupPane().getGrouping().fileIds(); + return getFileID().map(fileID -> " ( " + (fileIds.indexOf(fileID) + 1) + " of " + fileIds.size() + " in group )") + .orElse(""); + } @Override From e4811246bab502595331fa9e198b1107a96b1e18 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:11:16 -0400 Subject: [PATCH 146/198] reduce duplicate code --- .../imagegallery/ImageGalleryController.java | 4 +-- .../datamodel/CategoryManager.java | 4 +-- .../imagegallery/grouping/GroupManager.java | 12 +++---- .../imagegallery/gui/DrawableTileBase.java | 34 ++++++++++--------- .../imagegallery/gui/MetaDataPane.java | 17 +++++++--- 5 files changed, 40 insertions(+), 31 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 6c6bd7c789..d81ff29938 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -491,13 +491,13 @@ public final class ImageGalleryController { break; case CONTENT_TAG_ADDED: final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt; - if (getDatabase().isInDB((tagAddedEvent).getAddedTag().getContent().getId())) { + if (getDatabase().isInDB((tagAddedEvent).getTag().getContent().getId())) { getTagsManager().fireTagAddedEvent(tagAddedEvent); } break; case CONTENT_TAG_DELETED: final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) evt; - if (getDatabase().isInDB((tagDeletedEvent).getDeletedTag().getContent().getId())) { + if (getDatabase().isInDB((tagDeletedEvent).getTag().getContent().getId())) { getTagsManager().fireTagDeletedEvent(tagDeletedEvent); } break; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 3a1a81e72d..309173f153 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -226,7 +226,7 @@ public class CategoryManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent event) { - ContentTag addedTag = event.getAddedTag(); + ContentTag addedTag = event.getTag(); if (isCategoryTagName(addedTag.getName())) { final DrawableTagsManager tagsManager = controller.getTagsManager(); try { @@ -256,7 +256,7 @@ public class CategoryManager { } @Subscribe public void handleTagDeleted(ContentTagDeletedEvent event) { - ContentTag deleted = event.getDeletedTag(); + ContentTag deleted = event.getTag(); if (isCategoryTagName(deleted.getName())) { Category deletedCat = CategoryManager.categoryFromTagName(deleted.getName()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java index 90adfa76b8..d7819c6d5e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java @@ -541,11 +541,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public void handleTagAdded(ContentTagAddedEvent evt) { GroupKey groupKey = null; if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } else if (groupBy == DrawableAttribute.CATEGORY) { - groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getAddedTag().getName())); + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); } - final long fileID = evt.getAddedTag().getContent().getId(); + final long fileID = evt.getTag().getContent().getId(); DrawableGroup g = getGroupForKey(groupKey); addFileToGroup(g, groupKey, fileID); @@ -567,11 +567,11 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public void handleTagDeleted(ContentTagDeletedEvent evt) { GroupKey groupKey = null; if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getDeletedTag().getName()); + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } else if (groupBy == DrawableAttribute.CATEGORY) { - groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getDeletedTag().getName())); + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); } - final long fileID = evt.getDeletedTag().getContent().getId(); + final long fileID = evt.getTag().getContent().getId(); DrawableGroup g = removeFromGroup(groupKey, fileID); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java index 80c73b1ae9..428bd0b5f4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java @@ -62,6 +62,7 @@ import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.events.TagEvent; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; @@ -70,6 +71,7 @@ import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -349,36 +351,36 @@ public abstract class DrawableTileBase extends DrawableUIBase { @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { - getFileID().ifPresent(fileID -> { - try { - if (fileID == evt.getAddedTag().getContent().getId() - && evt.getAddedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { - Platform.runLater(() -> { - followUpImageView.setImage(followUpIcon); - followUpToggle.setSelected(true); - }); - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); - } + handleTagEvent(evt, () -> { + Platform.runLater(() -> { + followUpImageView.setImage(followUpIcon); + followUpToggle.setSelected(true); + }); }); } @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { + handleTagEvent(evt, this::updateFollowUpIcon); + } + void handleTagEvent(TagEvent evt, Runnable runnable) { getFileID().ifPresent(fileID -> { try { - if (fileID == evt.getDeletedTag().getContent().getId() - && evt.getDeletedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { - updateFollowUpIcon(); + final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); + final ContentTag deletedTag = evt.getTag(); + + if (fileID == deletedTag.getContent().getId() + && deletedTag.getName().equals(followUpTagName)) { + runnable.run(); } } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + LOGGER.log(Level.SEVERE, "Failed to get followup tag name. Unable to update follow up status for file. ", ex); } }); + } private void updateFollowUpIcon() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java index d89db4116c..780513d16a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java @@ -46,10 +46,12 @@ import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.events.TagEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; /** @@ -197,19 +199,24 @@ public class MetaDataPane extends DrawableUIBase { @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { - handleTagChanged(evt.getAddedTag().getContent().getId()); + handleTagEvent(evt, this::updateUI); } @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - handleTagChanged(evt.getDeletedTag().getContent().getId()); + handleTagEvent(evt, this::updateUI); } - private void handleTagChanged(Long tagFileID) { + /** + * + * @param tagFileID the value of tagEvent + * @param runnable the value of runnable + */ + void handleTagEvent(TagEvent tagEvent, final Runnable runnable) { getFileID().ifPresent(fileID -> { - if (Objects.equals(tagFileID, fileID)) { - updateUI(); + if (Objects.equals(tagEvent.getTag().getContent().getId(), fileID)) { + runnable.run(); } }); } From 617a4959a03056453e18e36fcacae628163d2acd Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:22:14 -0400 Subject: [PATCH 147/198] move DrawableView and GroupPane to a new package --- .../ImageGalleryTopComponent.java | 4 +- .../autopsy/imagegallery/gui/GroupView.java | 8 --- .../gui/{ => drawableviews}/DrawableTile.fxml | 0 .../gui/{ => drawableviews}/DrawableTile.java | 5 +- .../{ => drawableviews}/DrawableTileBase.java | 2 +- .../{ => drawableviews}/DrawableUIBase.java | 2 +- .../gui/{ => drawableviews}/DrawableView.java | 2 +- .../gui/{ => drawableviews}/GroupPane.fxml | 0 .../gui/{ => drawableviews}/GroupPane.java | 6 +- .../gui/{ => drawableviews}/MetaDataPane.fxml | 0 .../gui/{ => drawableviews}/MetaDataPane.java | 32 +++++----- .../gui/{ => drawableviews}/SlideShow.fxml | 0 .../{ => drawableviews}/SlideShowView.java | 63 ++++++++++--------- 13 files changed, 62 insertions(+), 62 deletions(-) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupView.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableTile.fxml (100%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableTile.java (95%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableTileBase.java (99%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableUIBase.java (97%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/DrawableView.java (98%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/GroupPane.fxml (100%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/GroupPane.java (99%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/MetaDataPane.fxml (100%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/MetaDataPane.java (98%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/SlideShow.fxml (100%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/{ => drawableviews}/SlideShowView.java (95%) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java index 850230cb88..658e523be9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java @@ -35,8 +35,8 @@ import org.openide.windows.Mode; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.gui.GroupPane; -import org.sleuthkit.autopsy.imagegallery.gui.MetaDataPane; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.GroupPane; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.MetaDataPane; import org.sleuthkit.autopsy.imagegallery.gui.StatusBar; import org.sleuthkit.autopsy.imagegallery.gui.SummaryTablePane; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupView.java deleted file mode 100644 index 73d2f3373c..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupView.java +++ /dev/null @@ -1,8 +0,0 @@ - -package org.sleuthkit.autopsy.imagegallery.gui; - - - -public interface GroupView { - -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml similarity index 100% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.fxml rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.java similarity index 95% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.java index 86a0b2ddee..86eed0a814 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import java.util.Objects; import java.util.logging.Level; @@ -32,7 +32,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableTileBase.globalSelectionModel; +import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; +import static org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableTileBase.globalSelectionModel; import org.sleuthkit.datamodel.AbstractContent; /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java similarity index 99% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index 428bd0b5f4..ed12891589 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.eventbus.Subscribe; import java.util.ArrayList; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java similarity index 97% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java index ec794eabae..0657385aff 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import java.util.Objects; import static java.util.Objects.nonNull; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java similarity index 98% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java index 709679173e..6b9a532e86 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java @@ -1,4 +1,4 @@ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.eventbus.Subscribe; import java.util.Collection; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml similarity index 100% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.fxml rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java similarity index 99% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 09042abaf4..266b578f46 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -16,8 +16,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.SlideShowView; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableTile; import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.Arrays; @@ -116,6 +118,8 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewMode; import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils; +import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.fxml similarity index 100% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.fxml rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.fxml diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java similarity index 98% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index 780513d16a..4814357a68 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.eventbus.Subscribe; import java.io.IOException; @@ -76,6 +76,20 @@ public class MetaDataPane extends DrawableUIBase { @FXML private BorderPane imageBorder; + public MetaDataPane(ImageGalleryController controller) { + super(controller); + + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MetaDataPane.fxml")); + fxmlLoader.setRoot(this); + fxmlLoader.setController(this); + + try { + fxmlLoader.load(); + } catch (IOException exception) { + throw new RuntimeException(exception); + } + } + @FXML @SuppressWarnings("unchecked") void initialize() { @@ -137,7 +151,7 @@ public class MetaDataPane extends DrawableUIBase { } @Override - synchronized protected void setFileHelper(Long newFileID) { + protected synchronized void setFileHelper(Long newFileID) { setFileIDOpt(Optional.ofNullable(newFileID)); if (newFileID == null) { Platform.runLater(() -> { @@ -151,20 +165,6 @@ public class MetaDataPane extends DrawableUIBase { } } - public MetaDataPane(ImageGalleryController controller) { - super(controller); - - FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MetaDataPane.fxml")); - fxmlLoader.setRoot(this); - fxmlLoader.setController(this); - - try { - fxmlLoader.load(); - } catch (IOException exception) { - throw new RuntimeException(exception); - } - } - public void updateUI() { getFile().ifPresent(file -> { final Image icon = file.getThumbnail(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShow.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml similarity index 100% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShow.fxml rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java similarity index 95% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java index d7d0f684ed..2b29e57d39 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.gui; +package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import java.util.ArrayList; import java.util.function.Function; @@ -58,13 +58,16 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.ImageFile; import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile; -import static org.sleuthkit.autopsy.imagegallery.gui.DrawableView.CAT_BORDER_WIDTH; +import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils; +import org.sleuthkit.autopsy.imagegallery.gui.MediaControl; +import static org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableView.CAT_BORDER_WIDTH; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** * Displays the files of a group one at a time. Designed to be embedded in a * GroupPane. TODO: Extract a subclass for video files in slideshow mode-jm + * * TODO: reduce coupling to GroupPane */ public class SlideShowView extends DrawableTileBase { @@ -73,40 +76,36 @@ public class SlideShowView extends DrawableTileBase { @FXML private ToggleButton cat0Toggle; - + @FXML + private ToggleButton cat1Toggle; @FXML private ToggleButton cat2Toggle; + @FXML + private ToggleButton cat3Toggle; + @FXML + private ToggleButton cat4Toggle; + @FXML + private ToggleButton cat5Toggle; @FXML private SplitMenuButton tagSplitButton; - @FXML - private ToggleButton cat3Toggle; - @FXML private Region spring; - @FXML private Button leftButton; - - @FXML - private ToggleButton cat4Toggle; - - @FXML - private ToggleButton cat5Toggle; - - @FXML - private ToggleButton cat1Toggle; - @FXML private Button rightButton; - @FXML private ToolBar toolBar; - @FXML private BorderPane footer; + SlideShowView(GroupPane gp) { + super(gp); + FXMLConstructor.construct(this, "SlideShow.fxml"); + } + @FXML @Override protected void initialize() { @@ -145,6 +144,8 @@ public class SlideShowView extends DrawableTileBase { tagSplitButton.getItems().setAll(selTagMenues); } }); + + //configure category toggles cat0Toggle.setBorder(new Border(new BorderStroke(Category.ZERO.getColor(), BorderStrokeStyle.SOLID, new CornerRadii(1), new BorderWidths(1)))); cat1Toggle.setBorder(new Border(new BorderStroke(Category.ONE.getColor(), BorderStrokeStyle.SOLID, new CornerRadii(1), new BorderWidths(1)))); cat2Toggle.setBorder(new Border(new BorderStroke(Category.TWO.getColor(), BorderStrokeStyle.SOLID, new CornerRadii(1), new BorderWidths(1)))); @@ -176,9 +177,7 @@ public class SlideShowView extends DrawableTileBase { //set up key listener equivalents of buttons addEventFilter(KeyEvent.KEY_PRESSED, (KeyEvent t) -> { - if (t.getEventType() == KeyEvent.KEY_PRESSED) { - switch (t.getCode()) { case LEFT: cycleSlideShowImage(-1); @@ -220,20 +219,14 @@ public class SlideShowView extends DrawableTileBase { } } - SlideShowView(GroupPane gp) { - super(gp); - - FXMLConstructor.construct(this, "SlideShow.fxml"); - - } - - @ThreadConfined(type = ThreadType.UI) + @ThreadConfined(type = ThreadType.JFX) public void stopVideo() { if (imageBorder.getCenter() instanceof MediaControl) { ((MediaControl) imageBorder.getCenter()).stopVideo(); } } + /** {@inheritDoc } */ @Override synchronized public void setFile(final Long fileID) { super.setFile(fileID); @@ -255,6 +248,7 @@ public class SlideShowView extends DrawableTileBase { imageBorder.setCenter(null); } + /** {@inheritDoc } */ @Override protected Runnable getContentUpdateRunnable() { @@ -281,11 +275,20 @@ public class SlideShowView extends DrawableTileBase { }); } + /** {@inheritDoc } */ @Override protected String getTextForLabel() { return getFile().map(file -> file.getName()).orElse("") + " " + getSupplementalText(); } + /** + * cycle the image displayed in thes SlideShowview, to the next/previous one + * in the group. + * + * @param direction the direction to cycle: + * -1 => left / back + * 1 => right / forward + */ @ThreadConfined(type = ThreadType.JFX) private void cycleSlideShowImage(int direction) { stopVideo(); @@ -296,7 +299,6 @@ public class SlideShowView extends DrawableTileBase { }).orElse(0); setFile(getGroupPane().getGrouping().fileIds().get(nextIndex) ); - } /** @@ -310,6 +312,7 @@ public class SlideShowView extends DrawableTileBase { } + /** {@inheritDoc } */ @Override @ThreadConfined(type = ThreadType.ANY) public Category updateCategory() { From 6434d9e8b94b9a161ee49f977cc75cb9b878bc5c Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:23:36 -0400 Subject: [PATCH 148/198] remove unneeded interface --- .../imagegallery/gui/drawableviews/GroupPane.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 266b578f46..b95e5d51f6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -18,8 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; -import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.SlideShowView; -import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableTile; import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.Arrays; @@ -102,7 +100,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.directorytree.ExtractAction; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -130,13 +127,13 @@ import org.sleuthkit.datamodel.TskCoreException; * * * TODO: Extract the The GridView instance to a separate class analogous to the - * SlideShow. Move selection model into controlsfx GridView and submit pull + * SlideShow. + * + * TODO: Move selection model into controlsfx GridView and submit pull * request to them. * https://bitbucket.org/controlsfx/controlsfx/issue/4/add-a-multipleselectionmodel-to-gridview - * - * */ -public class GroupPane extends BorderPane implements GroupView { +public class GroupPane extends BorderPane { private static final Logger LOGGER = Logger.getLogger(GroupPane.class.getName()); From 376c6c4a3316babd8c4691644229789f89694d59 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:42:48 -0400 Subject: [PATCH 149/198] move classes to better packages; remove FileUpdateEvent --- .../autopsy/imagegallery/FileUpdateEvent.java | 93 ------------------- .../imagegallery/ImageGalleryController.java | 5 +- .../imagegallery/actions/AddTagAction.java | 2 +- .../actions/CategorizeAction.java | 2 +- .../actions/DeleteFollowUpTagAction.java | 2 +- .../imagegallery/actions/NextUnseenGroup.java | 2 +- .../datamodel/CategoryChangeEvent.java | 50 ---------- .../datamodel/CategoryManager.java | 34 ++++++- .../imagegallery/datamodel/DrawableDB.java | 39 ++------ .../{ => datamodel}/DrawableTagsManager.java | 3 +- .../datamodel/HashSetManager.java | 1 + .../grouping/DrawableGroup.java | 2 +- .../{ => datamodel}/grouping/GroupKey.java | 2 +- .../grouping/GroupManager.java | 30 ++---- .../{ => datamodel}/grouping/GroupSortBy.java | 2 +- .../datamodel/grouping/GroupViewMode.java | 7 ++ .../grouping/GroupViewState.java | 2 +- .../imagegallery/grouping/GroupViewMode.java | 7 -- .../imagegallery/gui/SortByListCell.java | 2 +- .../imagegallery/gui/SummaryTablePane.java | 3 +- .../autopsy/imagegallery/gui/Toolbar.java | 4 +- .../gui/drawableviews/DrawableView.java | 3 +- .../gui/drawableviews/GroupPane.java | 6 +- .../gui/drawableviews/MetaDataPane.java | 4 +- .../gui/navpanel/GroupTreeCell.java | 2 +- .../gui/navpanel/GroupTreeItem.java | 2 +- .../imagegallery/gui/navpanel/NavPanel.java | 4 +- .../imagegallery/gui/navpanel/TreeNode.java | 2 +- 28 files changed, 88 insertions(+), 229 deletions(-) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/DrawableTagsManager.java (98%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/DrawableGroup.java (98%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/GroupKey.java (97%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/GroupManager.java (96%) rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/GroupSortBy.java (99%) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewMode.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/{ => datamodel}/grouping/GroupViewState.java (97%) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewMode.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java deleted file mode 100644 index c2803a5090..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileUpdateEvent.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery; - -import java.util.Collection; -import java.util.Collections; -import java.util.EventListener; -import java.util.HashSet; -import java.util.Set; -import javax.annotation.concurrent.Immutable; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; - -/** represents a change in the database for one or more files. */ -@Immutable -public class FileUpdateEvent { - - /** the obj_ids of affected files */ - private final Set fileIDs; - - /** the attribute that was modified */ - private final DrawableAttribute changedAttribute; - - /** the type of update ( updated/removed) */ - private final UpdateType updateType; - - public UpdateType getUpdateType() { - return updateType; - } - - public Collection getFileIDs() { - return Collections.unmodifiableCollection(fileIDs); - } - - public DrawableAttribute getChangedAttribute() { - return changedAttribute; - } - - public static FileUpdateEvent newRemovedEvent(Collection updatedFiles) { - return new FileUpdateEvent(updatedFiles, UpdateType.REMOVE, null); - } - - /** - * - * @param updatedFiles the files that have been added or changed in the - * database - * @param changedAttribute the attribute that was changed for the files, or - * null if this represents new files - * - * @return a new FileUpdateEvent - */ - public static FileUpdateEvent newUpdateEvent(Collection updatedFiles, DrawableAttribute changedAttribute) { - return new FileUpdateEvent(updatedFiles, UpdateType.UPDATE, changedAttribute); - } - - private FileUpdateEvent(Collection updatedFiles, UpdateType updateType, DrawableAttribute changedAttribute) { - this.fileIDs = new HashSet<>(updatedFiles); - this.updateType = updateType; - this.changedAttribute = changedAttribute; - } - - static public enum UpdateType { - - /** files have been added or updated in the db */ - UPDATE, - /** files have been removed - * from the db */ - REMOVE; - } - - /** Interface for listening to FileUpdateEvents */ - public static interface FileUpdateListener extends EventListener { - - public void handleFileUpdate(FileUpdateEvent evt); - - public void handleFileRemoved(FileUpdateEvent evt); - } -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index d81ff29938..44fa8950a3 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import java.beans.PropertyChangeEvent; import java.util.ArrayList; import java.util.List; @@ -63,8 +64,8 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 615b9b7f7d..cefa7aad60 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -29,7 +29,7 @@ import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.datamodel.TagName; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index afe2b3bb5d..518a49b87a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -28,7 +28,7 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 934a3fb258..fb729807c0 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -24,7 +24,7 @@ import javafx.event.ActionEvent; import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.ContentTag; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java index 550581d8b2..6a68810457 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java @@ -28,7 +28,7 @@ import javafx.scene.image.ImageView; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; /** * Marks the currently fisplayed group as "seen" and advances to the next unseen diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java deleted file mode 100644 index 3868864737..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryChangeEvent.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery.datamodel; - -import java.util.Collection; -import java.util.Collections; -import javax.annotation.concurrent.Immutable; - -/** - * Event broadcast to various UI componenets when one or more files' category - * has been changed - */ -@Immutable -public class CategoryChangeEvent { - - private final Collection fileIDs; - private final Category newCategory; - - public CategoryChangeEvent(Collection fileIDs, Category newCategory) { - this.fileIDs = fileIDs; - this.newCategory = newCategory; - } - - public Category getNewCategory() { - return newCategory; - } - - /** - * @return the fileIDs of the files whose categories have changed - */ - public Collection getFileIDs() { - return Collections.unmodifiableCollection(fileIDs); - } -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 309173f153..f84f759d37 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -27,11 +27,13 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; +import javax.annotation.concurrent.Immutable; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -254,6 +256,7 @@ public class CategoryManager { fireChange(Collections.singleton(addedTag.getContent().getId()), newCat); } } + @Subscribe public void handleTagDeleted(ContentTagDeletedEvent event) { ContentTag deleted = event.getTag(); @@ -266,4 +269,33 @@ public class CategoryManager { fireChange(Collections.singleton(deleted.getContent().getId()), null); } } + + /** + * Event broadcast to various UI componenets when one or more files' + * category + * has been changed + */ + @Immutable + public static class CategoryChangeEvent { + + private final Collection fileIDs; + private final Category newCategory; + + public CategoryChangeEvent(Collection fileIDs, Category newCategory) { + super(); + this.fileIDs = fileIDs; + this.newCategory = newCategory; + } + + public Category getNewCategory() { + return newCategory; + } + + /** + * @return the fileIDs of the files whose categories have changed + */ + public Collection getFileIDs() { + return Collections.unmodifiableCollection(fileIDs); + } + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 9dfbbdc239..87fa001827 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -46,13 +46,12 @@ import org.apache.commons.lang3.StringUtils; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupSortBy; -import static org.sleuthkit.autopsy.imagegallery.grouping.GroupSortBy.GROUP_BY_VALUE; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupKey; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy; +import static org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy.GROUP_BY_VALUE; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -125,11 +124,6 @@ public final class DrawableDB { */ private final Map, PreparedStatement> groupStatementMap = new HashMap<>(); - /** - * list of observers to be notified if the database changes - */ - private final HashSet updateListeners = new HashSet<>(); - private GroupManager groupManager; private final Path dbPath; @@ -201,6 +195,7 @@ public final class DrawableDB { this.dbPath = dbPath; this.controller = controller; this.tskCase = controller.getSleuthKitCase(); + this.groupManager = controller.getGroupManager(); Files.createDirectories(dbPath.getParent()); if (initializeDBSchema()) { updateFileStmt = prepareStatement( @@ -644,22 +639,6 @@ public final class DrawableDB { tr.commit(notify); } - public void addUpdatedFileListener(FileUpdateEvent.FileUpdateListener l) { - updateListeners.add(l); - } - - private void fireUpdatedFiles(Collection fileIDs) { - for (FileUpdateEvent.FileUpdateListener listener : updateListeners) { - listener.handleFileUpdate(FileUpdateEvent.newUpdateEvent(fileIDs, null)); - } - } - - private void fireRemovedFiles(Collection fileIDs) { - for (FileUpdateEvent.FileUpdateListener listener : updateListeners) { - listener.handleFileRemoved(FileUpdateEvent.newRemovedEvent(fileIDs)); - } - } - public Boolean isFileAnalyzed(DrawableFile f) { return isFileAnalyzed(f.getId()); } @@ -1149,7 +1128,7 @@ public final class DrawableDB { * in the drawable db? */ @Nonnull - Set getHashSetsForFile(long fileID) { + public Set getHashSetsForFile(long fileID) { try { Set hashNames = new HashSet<>(); List arts = tskCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT, fileID); @@ -1312,8 +1291,10 @@ public final class DrawableDB { close(); if (notify) { - fireUpdatedFiles(updatedFiles); - fireRemovedFiles(removedFiles); + if (groupManager != null) { + groupManager.handleFileUpdate(updatedFiles); + groupManager.handleFileRemoved(removedFiles); + } } } catch (SQLException ex) { if (Case.isCaseOpen()) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java similarity index 98% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index 0bbc4b9d5a..57d7152967 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery; +package org.sleuthkit.autopsy.imagegallery.datamodel; import com.google.common.eventbus.EventBus; import java.util.Collection; @@ -30,7 +30,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java index 1ca547c81e..1071a6ee0a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/HashSetManager.java @@ -4,6 +4,7 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.util.Set; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; /** * Manages a cache of hashset hits as a map from fileID to hashset names. diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java similarity index 98% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java index 0ad8b2640e..ac0493d75e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import java.util.Objects; import java.util.Set; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupKey.java similarity index 97% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupKey.java index cd41534078..ce64bebaa3 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupKey.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupKey.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import java.util.Map; import java.util.Objects; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java similarity index 96% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index d7819c6d5e..ad99d94407 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import com.google.common.eventbus.Subscribe; import java.sql.ResultSet; @@ -50,7 +50,6 @@ import javax.annotation.concurrent.GuardedBy; import javax.swing.SortOrder; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; @@ -62,8 +61,6 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; @@ -71,6 +68,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -84,7 +82,7 @@ import org.sleuthkit.datamodel.TskCoreException; * extent {@link SleuthkitCase} ) to facilitate creation, retrieval, updating, * and sorting of {@link DrawableGroup}s. */ -public class GroupManager implements FileUpdateEvent.FileUpdateListener { +public class GroupManager { private static final Logger LOGGER = Logger.getLogger(GroupManager.class.getName()); @@ -123,7 +121,6 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { public void setDB(DrawableDB db) { this.db = db; - db.addUpdatedFileListener(this); regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); } @@ -575,11 +572,10 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { DrawableGroup g = removeFromGroup(groupKey, fileID); } - @Override - synchronized public void handleFileRemoved(FileUpdateEvent evt) { - Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.REMOVE); + @Subscribe + synchronized public void handleFileRemoved(Collection removedFileIDs) { - for (final long fileId : evt.getFileIDs()) { + for (final long fileId : removedFileIDs) { //get grouping(s) this file would be in Set> groupsForFile = getGroupKeysForFileID(fileId); @@ -595,17 +591,15 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { * * @param evt */ - @Override - synchronized public void handleFileUpdate(FileUpdateEvent evt) { - Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.UPDATE); - Collection fileIDs = evt.getFileIDs(); + @Subscribe + synchronized public void handleFileUpdate(Collection updatedFileIDs) { /** * TODO: is there a way to optimize this to avoid quering to db * so much. the problem is that as a new files are analyzed they * might be in new groups( if we are grouping by say make or * model) -jm */ - for (long fileId : fileIDs) { + for (long fileId : updatedFileIDs) { controller.getHashSetManager().invalidateHashSetsForFile(fileId); @@ -618,11 +612,7 @@ public class GroupManager implements FileUpdateEvent.FileUpdateListener { } //we fire this event for all files so that the category counts get updated during initial db population - controller.getCategoryManager().fireChange(fileIDs, null); - -// if (evt.getChangedAttribute() == DrawableAttribute.TAGS) { -// controller.getTagsManager().fireChange(fileIDs); -// } + controller.getCategoryManager().fireChange(updatedFileIDs, null); } private DrawableGroup popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupSortBy.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java similarity index 99% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupSortBy.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java index fa2b3e88d0..a7bdbb342e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupSortBy.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import java.util.Arrays; import java.util.Comparator; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewMode.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewMode.java new file mode 100644 index 0000000000..17a970ca13 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewMode.java @@ -0,0 +1,7 @@ +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; + +public enum GroupViewMode { + + TILE, SLIDE_SHOW + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewState.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewState.java similarity index 97% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewState.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewState.java index 4d4905a80a..86679340ab 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewState.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewState.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.grouping; +package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; import java.util.Objects; import java.util.Optional; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewMode.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewMode.java deleted file mode 100644 index 5506223429..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/grouping/GroupViewMode.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.sleuthkit.autopsy.imagegallery.grouping; - -public enum GroupViewMode { - - TILE, SLIDE_SHOW - -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortByListCell.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortByListCell.java index 22985ff341..c9845fff3a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortByListCell.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SortByListCell.java @@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.imagegallery.gui; import javafx.scene.control.ListCell; import javafx.scene.image.ImageView; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupSortBy; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy; public class SortByListCell extends ListCell { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java index 955cf0760f..6fe4ce9b44 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java @@ -36,7 +36,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; /** * Displays summary statistics (counts) for each group @@ -88,7 +87,7 @@ public class SummaryTablePane extends AnchorPane { * listen to Category updates and rebuild the table */ @Subscribe - public void handleCategoryChanged(CategoryChangeEvent evt) { + public void handleCategoryChanged(org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager.CategoryChangeEvent evt) { final ObservableList> data = FXCollections.observableArrayList(); if (Case.isCaseOpen()) { for (Category cat : Category.values()) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index 2131ff73fc..33083c45b4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -41,7 +41,7 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javax.swing.SortOrder; import org.openide.util.Exceptions; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; @@ -49,7 +49,7 @@ import org.sleuthkit.autopsy.imagegallery.ThumbnailCache; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupSortBy; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java index 6b9a532e86..4d7f31a52a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java @@ -18,7 +18,6 @@ import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -68,7 +67,7 @@ public interface DrawableView { * @param evt the CategoryChangeEvent to handle */ @Subscribe - default void handleCategoryChanged(CategoryChangeEvent evt) { + default void handleCategoryChanged(org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager.CategoryChangeEvent evt) { getFileID().ifPresent(fileID -> { if (evt.getFileIDs().contains(fileID)) { updateCategory(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index b95e5d51f6..4c2a056d46 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -112,9 +112,9 @@ import org.sleuthkit.autopsy.imagegallery.actions.NextUnseenGroup; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewMode; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewMode; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.datamodel.TagName; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index 4814357a68..5ebc6c1984 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -49,8 +49,8 @@ import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.events.TagEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -188,7 +188,7 @@ public class MetaDataPane extends DrawableUIBase { /** {@inheritDoc } */ @Subscribe @Override - public void handleCategoryChanged(CategoryChangeEvent evt) { + public void handleCategoryChanged(CategoryManager.CategoryChangeEvent evt) { getFileID().ifPresent(fileID -> { if (evt.getFileIDs().contains(fileID)) { updateUI(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java index 5deaf88aa8..8103a55cf6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java @@ -31,7 +31,7 @@ import javafx.scene.image.ImageView; import javax.annotation.Nonnull; import org.apache.commons.lang3.StringUtils; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; /** * A cell in the NavPanel tree that listens to its associated group's fileids diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java index 37925b47bb..3bd5ff72bf 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeItem.java @@ -27,7 +27,7 @@ import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.scene.control.TreeItem; import org.apache.commons.lang3.StringUtils; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; /** * A node in the nav/hash tree. Manages inserts and removals. Has parents and diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java index efc855e8ca..64aa5a681e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java @@ -45,8 +45,8 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; /** * Display two trees. one shows all folders (groups) and calls out folders with diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/TreeNode.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/TreeNode.java index 0c7b2c2806..b230409075 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/TreeNode.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/TreeNode.java @@ -18,7 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.gui.navpanel; -import org.sleuthkit.autopsy.imagegallery.grouping.DrawableGroup; +import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; /** * From ad39755fe4750dc6c7eb31e2b8b1c200d3e48008 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 16:42:44 -0400 Subject: [PATCH 150/198] better handling of exceptions in event bus eventhandlers --- .../datamodel/CategoryManager.java | 11 ++++++-- .../datamodel/DrawableTagsManager.java | 18 ++++++++---- .../datamodel/grouping/GroupManager.java | 28 +++++++++++-------- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index f84f759d37..31be08e71a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -20,20 +20,21 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.google.common.eventbus.AsyncEventBus; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.concurrent.Executors; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; import javax.annotation.concurrent.Immutable; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -66,7 +67,11 @@ public class CategoryManager { /** * Used to distribute {@link CategoryChangeEvent}s */ - private final EventBus categoryEventBus = new EventBus("Category Event Bus"); + private final EventBus categoryEventBus = new AsyncEventBus(Executors.newSingleThreadExecutor( + new BasicThreadFactory.Builder().namingPattern("Category Event Bus").uncaughtExceptionHandler((Thread t, Throwable e) -> { + LOGGER.log(Level.SEVERE, "uncaught exception in event bus handler", e); + }).build() + )); /** * For performance reasons, keep current category counts in memory. All of diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index 57d7152967..af5a0ebced 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -18,19 +18,20 @@ */ package org.sleuthkit.autopsy.imagegallery.datamodel; +import com.google.common.eventbus.AsyncEventBus; import com.google.common.eventbus.EventBus; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -42,13 +43,20 @@ import org.sleuthkit.datamodel.TskCoreException; */ public class DrawableTagsManager { + private static final Logger LOGGER = Logger.getLogger(DrawableTagsManager.class.getName()); + private static final String FOLLOW_UP = "Follow Up"; final private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; /** Used to distribute {@link TagsChangeEvent}s */ - private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); + private final EventBus tagsEventBus = new AsyncEventBus( + Executors.newSingleThreadExecutor( + new BasicThreadFactory.Builder().namingPattern("Tags Event Bus").uncaughtExceptionHandler((Thread t, Throwable e) -> { + LOGGER.log(Level.SEVERE, "uncaught exception in event bus handler", e); + }).build() + )); /** The tag name corresponding to the "built-in" tag "Follow Up" */ private TagName followUpTagName; @@ -130,7 +138,7 @@ public class DrawableTagsManager { .filter(CategoryManager::isCategoryTagName) .collect(Collectors.toSet()); } catch (TskCoreException | IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + LOGGER.log(Level.WARNING, "couldn't access case", ex); } return Collections.emptySet(); } @@ -166,7 +174,7 @@ public class DrawableTagsManager { throw new TskCoreException("tagame exists but wasn't found", ex); } } catch (IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); + LOGGER.log(Level.SEVERE, "Case was closed out from underneath", ex); throw new TskCoreException("Case was closed out from underneath", ex); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index ad99d94407..dc27ac136b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -537,15 +537,16 @@ public class GroupManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { GroupKey groupKey = null; - if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); - } else if (groupBy == DrawableAttribute.CATEGORY) { + if (groupBy == DrawableAttribute.CATEGORY && CategoryManager.isCategoryTagName(evt.getTag().getName())) { groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); + } + if (groupKey != null) { + final long fileID = evt.getTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); } - final long fileID = evt.getTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); - } @SuppressWarnings("AssignmentToMethodParameter") @@ -563,13 +564,16 @@ public class GroupManager { @Subscribe public void handleTagDeleted(ContentTagDeletedEvent evt) { GroupKey groupKey = null; - if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); - } else if (groupBy == DrawableAttribute.CATEGORY) { + if (groupBy == DrawableAttribute.CATEGORY && CategoryManager.isCategoryTagName(evt.getTag().getName())) { groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); + } + + if (groupKey != null) { + final long fileID = evt.getTag().getContent().getId(); + DrawableGroup g = removeFromGroup(groupKey, fileID); } - final long fileID = evt.getTag().getContent().getId(); - DrawableGroup g = removeFromGroup(groupKey, fileID); } @Subscribe From 7dba4be3cc05f323920171b11b3082dab4c096f0 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 15:46:12 -0400 Subject: [PATCH 151/198] only add new cat tag if there is no existing cat tag. put adding and removing fileids to/from group on jfx thread; remove file from groups when adding to new catagory based on new tag --- .../imagegallery/ImageGalleryController.java | 2 +- .../actions/CategorizeAction.java | 23 +++++++++---- .../datamodel/CategoryManager.java | 6 ++-- .../datamodel/grouping/GroupManager.java | 32 ++++++++++++------- 4 files changed, 41 insertions(+), 22 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 44fa8950a3..e71aaf434c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import java.beans.PropertyChangeEvent; import java.util.ArrayList; import java.util.List; @@ -63,6 +62,7 @@ import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 518a49b87a..f7c20ab56b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -19,8 +19,10 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.logging.Level; +import java.util.stream.Collectors; import javafx.event.ActionEvent; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; @@ -28,12 +30,14 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -127,11 +131,10 @@ public class CategorizeAction extends AddTagAction { try { DrawableFile file = controller.getFileFromId(fileID); //drawable db - - if (tagName != categoryManager.getTagName(Category.ZERO)) { // no tags for cat-0 - tagsManager.addContentTag(file, tagName, comment); //tsk db - } else { - tagsManager.getContentTagsByContent(file).stream() + final List fileTags = tagsManager.getContentTagsByContent(file); + if (tagName == categoryManager.getTagName(Category.ZERO)) { + // delete all cat tags for cat-0 + fileTags.stream() .filter(tag -> CategoryManager.isCategoryTagName(tag.getName())) .forEach((ct) -> { try { @@ -140,6 +143,14 @@ public class CategorizeAction extends AddTagAction { LOGGER.log(Level.SEVERE, "Error removing old categories result", ex); } }); + } else { + //add cat tag if no existing cat tag for that cat + if (fileTags.stream() + .map(Tag::getName) + .filter(tagName::equals) + .collect(Collectors.toList()).isEmpty()) { + tagsManager.addContentTag(file, tagName, comment); + } } } catch (TskCoreException ex) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 31be08e71a..3377fdce6e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -233,14 +233,12 @@ public class CategoryManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent event) { - ContentTag addedTag = event.getTag(); + final ContentTag addedTag = event.getTag(); if (isCategoryTagName(addedTag.getName())) { final DrawableTagsManager tagsManager = controller.getTagsManager(); try { //remove old category tag(s) if necessary - List allContentTags = tagsManager.getContentTagsByContent(addedTag.getContent()); - - for (ContentTag ct : allContentTags) { + for (ContentTag ct : tagsManager.getContentTagsByContent(addedTag.getContent())) { if (ct.getId() != addedTag.getId() && CategoryManager.isCategoryTagName(ct.getName())) { try { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index dc27ac136b..8b7844d9c4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -270,7 +270,9 @@ public class GroupManager { //get grouping this file would be in final DrawableGroup group = getGroupForKey(groupKey); if (group != null) { - group.removeFile(fileID); + Platform.runLater(() -> { + group.removeFile(fileID); + }); // If we're grouping by category, we don't want to remove empty groups. if (groupKey.getAttribute() != DrawableAttribute.CATEGORY) { @@ -536,16 +538,21 @@ public class GroupManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { - GroupKey groupKey = null; + GroupKey newGroupKey = null; + final long fileID = evt.getTag().getContent().getId(); if (groupBy == DrawableAttribute.CATEGORY && CategoryManager.isCategoryTagName(evt.getTag().getName())) { - groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + newGroupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + for (GroupKey oldGroupKey : groupMap.keySet()) { + if (oldGroupKey.equals(newGroupKey) == false) { + removeFromGroup(oldGroupKey, fileID); + } + } } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); + newGroupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } - if (groupKey != null) { - final long fileID = evt.getTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); + if (newGroupKey != null) { + DrawableGroup g = getGroupForKey(newGroupKey); + addFileToGroup(g, newGroupKey, fileID); } } @@ -555,9 +562,13 @@ public class GroupManager { //if there wasn't already a group check if there should be one now g = popuplateIfAnalyzed(groupKey, null); } - if (g != null) { + DrawableGroup group = g; + if (group != null) { //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. - g.addFile(fileID); + Platform.runLater(() -> { + group.addFile(fileID); + }); + } } @@ -569,7 +580,6 @@ public class GroupManager { } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } - if (groupKey != null) { final long fileID = evt.getTag().getContent().getId(); DrawableGroup g = removeFromGroup(groupKey, fileID); From 28e3c015c34bfa3c191a6af67da106606fae1422 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 16:12:55 -0400 Subject: [PATCH 152/198] clean up add tag action, use invokeLater not invokeAndWait; getNonCategoryTagNames returns TagNames in alphabetical order by displayname --- .../imagegallery/actions/AddTagAction.java | 63 +++++++------------ .../datamodel/DrawableTagsManager.java | 14 ++++- 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index cefa7aad60..6e45f9bbdc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -18,22 +18,17 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.util.List; +import java.util.Collection; import java.util.Set; -import java.util.logging.Level; import javafx.event.ActionEvent; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; import javax.swing.SwingUtilities; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; /** * An abstract base class for actions that allow users to tag SleuthKit data @@ -77,42 +72,31 @@ abstract class AddTagAction { TagMenu(ImageGalleryController controller) { super(getActionDisplayName()); - // Get the current set of tag names. - DrawableTagsManager tagsManager = controller.getTagsManager(); - List tagNames = null; - try { - tagNames = tagsManager.getAllTagNames(); - } catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); - } - // Create a "Quick Tag" sub-menu. Menu quickTagMenu = new Menu("Quick Tag"); getItems().add(quickTagMenu); - // Each tag name in the current set of tags gets its own menu item in - // the "Quick Tags" sub-menu. Selecting one of these menu items adds - // a tag with the associated tag name. - if (null != tagNames && !tagNames.isEmpty()) { - for (final TagName tagName : tagNames) { - if (CategoryManager.isNotCategoryTagName(tagName)) { - MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); - tagNameItem.setOnAction((ActionEvent t) -> { - addTag(tagName, NO_COMMENT); - }); - quickTagMenu.getItems().add(tagNameItem); - } - } - } else { + /* Each non-Category tag name in the current set of tags gets its + * own menu item in the "Quick Tags" sub-menu. Selecting one of + * these menu items adds a tag with the associated tag name. */ + Collection tagNames = controller.getTagsManager().getNonCategoryTagNames(); + if (tagNames.isEmpty()) { MenuItem empty = new MenuItem("No tags"); empty.setDisable(true); quickTagMenu.getItems().add(empty); + } else { + for (final TagName tagName : tagNames) { + MenuItem tagNameItem = new MenuItem(tagName.getDisplayName()); + tagNameItem.setOnAction((ActionEvent t) -> { + addTag(tagName, NO_COMMENT); + }); + quickTagMenu.getItems().add(tagNameItem); + } } - // quickTagMenu.addSeparator(); - // The "Quick Tag" menu also gets an "Choose Tag..." menu item. - // Selecting this item initiates a dialog that can be used to create - // or select a tag name and adds a tag with the resulting name. + /* The "Quick Tag" menu also gets an "New Tag..." menu item. + * Selecting this item initiates a dialog that can be used to create + * or select a tag name and adds a tag with the resulting name. */ MenuItem newTagMenuItem = new MenuItem("New Tag..."); newTagMenuItem.setOnAction((ActionEvent t) -> { SwingUtilities.invokeLater(() -> { @@ -125,18 +109,19 @@ abstract class AddTagAction { }); quickTagMenu.getItems().add(newTagMenuItem); - // Create a "Choose Tag and Comment..." menu item. Selecting this item initiates - // a dialog that can be used to create or select a tag name with an - // optional comment and adds a tag with the resulting name. + /* Create a "Tag and Comment..." menu item. Selecting this item + * initiates a dialog that can be used to create or select a tag + * name with an optional comment and adds a tag with the resulting + * name. */ MenuItem tagAndCommentItem = new MenuItem("Tag and Comment..."); tagAndCommentItem.setOnAction((ActionEvent t) -> { SwingUtilities.invokeLater(() -> { GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); if (null != tagNameAndComment) { - if (CategoryManager.isCategoryTagName(tagNameAndComment.getTagName())) { - new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); + if (CategoryManager.isCategoryTagName(tagNameAndComment.getTagName())) { + new CategorizeAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } else { - new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); + new AddDrawableTagAction(controller).addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index af5a0ebced..547ab7a858 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -27,6 +27,7 @@ import java.util.Objects; import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; +import javax.annotation.Nonnull; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; @@ -131,12 +132,21 @@ public class DrawableTagsManager { } } + /** + * get all the TagNames that are not categories + * + * @return all the TagNames that are not categories, in alphabetical order + * by displayName, or, an empty set if there was an exception looking them + * up from the db. + */ + @Nonnull public Collection getNonCategoryTagNames() { synchronized (autopsyTagsManagerLock) { try { return autopsyTagsManager.getAllTagNames().stream() - .filter(CategoryManager::isCategoryTagName) - .collect(Collectors.toSet()); + .filter(CategoryManager::isNotCategoryTagName) + .distinct().sorted() + .collect(Collectors.toList()); } catch (TskCoreException | IllegalStateException ex) { LOGGER.log(Level.WARNING, "couldn't access case", ex); } From 5c0085d039c39af822babcc3c332c8d75fde420b Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 16:23:59 -0400 Subject: [PATCH 153/198] SlideShow toggle is disabled initialy; fix relative paths to images in fxml --- .../gui/drawableviews/DrawableTile.fxml | 112 +++++++++--------- .../gui/drawableviews/GroupPane.fxml | 12 +- .../gui/drawableviews/SlideShow.fxml | 12 +- 3 files changed, 69 insertions(+), 67 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml index 4d34061c77..acfcdc1336 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml @@ -7,60 +7,62 @@ - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+
-
-
- -
-
-
-
-
- - - + + + +
diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml index 6eb799970d..4760d1f0cf 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml @@ -23,7 +23,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -53,7 +53,7 @@ - + @@ -108,16 +108,16 @@ - + - + - + diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml index fb9e0aade4..fd3862afee 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShow.fxml @@ -18,7 +18,7 @@ - + @@ -42,7 +42,7 @@ - + @@ -88,12 +88,12 @@ - + - + @@ -110,7 +110,7 @@ - + @@ -135,7 +135,7 @@ - + From f191829cd1eba10eb9d0c17a7792559c9b52d652 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 16:27:03 -0400 Subject: [PATCH 154/198] SlideShow toggle is disabled when there is no group selected; fix relative paths to images in fxml --- .../autopsy/imagegallery/gui/drawableviews/GroupPane.fxml | 2 +- .../autopsy/imagegallery/gui/drawableviews/GroupPane.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml index 4760d1f0cf..6dfe0d02ed 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml @@ -113,7 +113,7 @@ - + diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 4c2a056d46..ab011fc493 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -590,6 +590,7 @@ public class GroupPane extends BorderPane { Platform.runLater(() -> { gridView.getItems().setAll(Collections.emptyList()); setCenter(null); + slideShowToggle.setDisable(true); groupLabel.setText(""); resetScrollBar(); if (false == Case.isCaseOpen()) { From 5d73db18362998feea515f1ad5824f4a43ed8ec5 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 16 Jun 2015 11:14:44 -0400 Subject: [PATCH 155/198] make new DeleteFollowUpTag action; use Set instead of List to prevent duplicate files in groups --- .../actions/DeleteFollowUpTag.java | 86 +++++++++++++++++++ .../datamodel/grouping/GroupManager.java | 8 ++ .../gui/drawableviews/DrawableTileBase.java | 28 +++++- 3 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java new file mode 100644 index 0000000000..0399b545ed --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java @@ -0,0 +1,86 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery.actions; + +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import javafx.event.ActionEvent; +import org.controlsfx.control.action.Action; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.TagUtils; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; +import org.sleuthkit.autopsy.ingest.IngestServices; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * + */ +public class DeleteFollowUpTag extends Action { + + private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTag.class.getName()); + private final long fileID; + private final DrawableFile file; + + public DeleteFollowUpTag(DrawableFile file) { + super("Delete Follow Up Tag"); + this.file = file; + this.fileID = file.getId(); + + setEventHandler((ActionEvent t) -> { + deleteFollowupTag(); + }); + } + + /** + * + * @param fileID1 the value of fileID1 + * + * @throws IllegalStateException + */ + private void deleteFollowupTag() throws IllegalStateException { + + final ImageGalleryController controller = ImageGalleryController.getDefault(); + final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + try { + // remove file from old category group + controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); + + List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); + for (ContentTag ct : contentTagsByContent) { + if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { + sleuthKitCase.deleteContentTag(ct); + } + } + IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); + } + } +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index 8b7844d9c4..2c0da12044 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -243,6 +243,9 @@ public class GroupManager { /** * 'mark' the given group as seen. This removes it from the queue of * groups + public DrawableGroup makeGroup(GroupKey groupKey, Set files) { + + Set newFiles = ObjectUtils.defaultIfNull(files, new HashSet()); * to review, and is persisted in the drawable db. * * @param group the {@link DrawableGroup} to mark as seen @@ -284,6 +287,8 @@ public class GroupManager { if (unSeenGroups.contains(group)) { unSeenGroups.remove(group); } + public synchronized void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup) { + private synchronized
> void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup, ReGroupTask task) { }); } } @@ -291,6 +296,7 @@ public class GroupManager { // It may be that this was the last unanalyzed file in the group, so test // whether the group is now fully analyzed. popuplateIfAnalyzed(groupKey, null); + public Set checkAnalyzed(final GroupKey groupKey) { } return group; @@ -595,6 +601,7 @@ public class GroupManager { for (GroupKey gk : groupsForFile) { removeFromGroup(gk, fileId); + Set checkAnalyzed = checkAnalyzed(gk); } } } @@ -739,6 +746,7 @@ public class GroupManager { updateProgress(p, vals.size()); groupProgress.progress("regrouping files by " + groupBy.attrName.toString() + " : " + val, p); popuplateIfAnalyzed(new GroupKey(groupBy, val), this); + Set checkAnalyzed = checkAnalyzed(groupKey); } updateProgress(1, 1); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index ed12891589..4f601f9400 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -67,11 +67,9 @@ import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; -import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -268,6 +266,32 @@ public abstract class DrawableTileBase extends DrawableUIBase { }); } +// /** +// * +// * @param fileID1 the value of fileID1 +// * +// * @throws IllegalStateException +// */ +// private void deleteFollowupTag(final Long fileID1) throws IllegalStateException { +// //TODO: convert this to an action! +// final ImageGalleryController controller = ImageGalleryController.getDefault(); +// try { +// // remove file from old category group +// controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID1); +// +// List contentTagsByContent = controller.getSleuthKitCase().getContentTagsByContent(file); +// for (ContentTag ct : contentTagsByContent) { +// if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { +// controller.getSleuthKitCase().deleteContentTag(ct); +// } +// } +// IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS +// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID1), DrawableAttribute.TAGS)); +// } catch (TskCoreException ex) { +// LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); +// } +// } + protected boolean hasFollowUp() { if (getFileID().isPresent()) { try { From cfe44bde9f71134fa9a9181e105e9a7519c77955 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 16 Jun 2015 12:51:06 -0400 Subject: [PATCH 156/198] cleanup Follow Up tag and Category TagNames (prevent short name version from being added, by removing commas) --- .../autopsy/imagegallery/actions/DeleteFollowUpTag.java | 2 ++ .../sleuthkit/autopsy/imagegallery/datamodel/Category.java | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java index 0399b545ed..0fe88de953 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java @@ -78,6 +78,8 @@ public class DeleteFollowUpTag extends Action { } } IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + + //make sure rest of ui hears category change. controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 8999fff2f1..7cae09067f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -53,6 +53,10 @@ public enum Category { return nameMap.containsKey(tName); } + public static boolean isCategoryTagName(TagName tName) { + return nameMap.containsKey(tName.getDisplayName()); + } + public static boolean isNotCategoryName(String tName) { return nameMap.containsKey(tName) == false; } From 1be231107d1e14bc73316366487b1a77b34732c6 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 16 Jun 2015 16:53:16 -0400 Subject: [PATCH 157/198] clean up and refactor code related to Tagging and actions; move away from singleton by injecting controller rather than using getDefault(); use EventBus in DrawableTagsManager (used to be TagUtils) requires equal and hashcode method implemented on TagName --- .../imagegallery/DrawableTagsManager.java | 161 ++++++++++++++++++ .../imagegallery/ImageGalleryController.java | 4 + .../autopsy/imagegallery/TagsChangeEvent.java | 41 +++++ .../imagegallery/actions/AddTagAction.java | 1 + .../actions/CategorizeAction.java | 2 + ...eFollowUpTag.java => DeleteTagAction.java} | 42 +++-- .../datamodel/CategoryManager.java | 1 + .../imagegallery/datamodel/DrawableDB.java | 1 + .../gui/drawableviews/DrawableTileBase.java | 28 +-- .../gui/drawableviews/DrawableView.java | 1 - .../gui/drawableviews/GroupPane.java | 1 + .../gui/drawableviews/MetaDataPane.java | 5 + .../gui/drawableviews/SlideShowView.java | 1 + 13 files changed, 244 insertions(+), 45 deletions(-) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java rename ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/{DeleteFollowUpTag.java => DeleteTagAction.java} (66%) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java new file mode 100644 index 0000000000..3c1dd42de3 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -0,0 +1,161 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery; + +import com.google.common.eventbus.EventBus; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import java.util.stream.Collectors; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Manages Tags, Tagging, and the relationship between Categories and Tags in + * the autopsy Db. delegates some, work to the backing {@link TagsManager}. + */ +public class DrawableTagsManager { + + private static final String FOLLOW_UP = "Follow Up"; + + private TagsManager autopsyTagsManager; + + /** Used to distribute {@link TagsChangeEvent}s */ + private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); + + /** The tag name corresponging to the "built-in" tag "Follow Up" */ + private TagName followUpTagName; + + public DrawableTagsManager(TagsManager autopsyTagsManager) { + this.autopsyTagsManager = autopsyTagsManager; + + } + + /** + * assign a new TagsManager to back this one, ie when the current case + * changes + * + * @param autopsyTagsManager + */ + public synchronized void setAutopsyTagsManager(TagsManager autopsyTagsManager) { + this.autopsyTagsManager = autopsyTagsManager; + clearFollowUpTagName(); + } + + /** + * Use when closing a case to make sure everything is re-initialized in the + * next case. + */ + public synchronized void clearFollowUpTagName() { + followUpTagName = null; + } + + /** + * fire a CategoryChangeEvent with the given fileIDs + * + * @param fileIDs + */ + public final void fireChange(Collection fileIDs) { + tagsEventBus.post(new TagsChangeEvent(fileIDs)); + } + + /** + * register an object to receive CategoryChangeEvents + * + * @param listner + */ + public void registerListener(Object listner) { + tagsEventBus.register(listner); + } + + /** + * unregister an object from receiving CategoryChangeEvents + * + * @param listener + */ + public void unregisterListener(Object listener) { + tagsEventBus.unregister(listener); + } + + /** + * get the (cached) follow up TagName + * + * @return + * + * @throws TskCoreException + */ + synchronized public TagName getFollowUpTagName() throws TskCoreException { + if (followUpTagName == null) { + followUpTagName = getTagName(FOLLOW_UP); + } + return followUpTagName; + } + + public Collection getNonCategoryTagNames() { + try { + return autopsyTagsManager.getAllTagNames().stream() + .filter(Category::isCategoryTagName) + .collect(Collectors.toSet()); + } catch (TskCoreException | IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + } + return Collections.emptySet(); + } + + public synchronized TagName getTagName(String displayName) throws TskCoreException { + try { + for (TagName tn : autopsyTagsManager.getAllTagNames()) { + if (displayName.equals(tn.getDisplayName())) { + return tn; + } + } + try { + return autopsyTagsManager.addTagName(displayName); + } catch (TagsManager.TagNameAlreadyExistsException ex) { + throw new TskCoreException("tagame exists but wasn't found", ex); + } + } catch (IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); + throw new TskCoreException("Case was closed out from underneath", ex); + } + } + + public synchronized TagName getTagName(Category cat) { + try { + return getTagName(cat.getDisplayName()); + } catch (TskCoreException ex) { + return null; + } + } + + public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { + autopsyTagsManager.addContentTag(file, tagName, comment); + } + + public List getContentTagsByTagName(TagName t) throws TskCoreException { + return autopsyTagsManager.getContentTagsByTagName(t); + } + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index e71aaf434c..95b7141f78 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -518,6 +518,10 @@ public final class ImageGalleryController { return tagsManager; } + public DrawableTagsManager getTagsManager() { + return tagsManager; + } + // @@@ REVIEW IF THIS SHOLD BE STATIC... //TODO: concept seems like the controller deal with how much work to do at a given time // @@@ review this class for synchronization issues (i.e. reset and cancel being called, add, etc.) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java new file mode 100644 index 0000000000..0647a18456 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java @@ -0,0 +1,41 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery; + +import java.util.Collection; +import java.util.Collections; +import javax.annotation.concurrent.Immutable; + +/** + * + */ +@Immutable +public class TagsChangeEvent { + + private final Collection fileIDs; + + public Collection getFileIDs() { + return Collections.unmodifiableCollection(fileIDs); + } + + public TagsChangeEvent(Collection fileIDs) { + this.fileIDs = fileIDs; + } + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 6e45f9bbdc..44bb02f0e0 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -28,6 +28,7 @@ import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.datamodel.TagName; /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index f7c20ab56b..ff0c939ee3 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -36,6 +36,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TagName; @@ -129,6 +130,7 @@ public class CategorizeAction extends AddTagAction { final CategoryManager categoryManager = controller.getCategoryManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); + try { DrawableFile file = controller.getFileFromId(fileID); //drawable db final List fileTags = tagsManager.getContentTagsByContent(file); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java similarity index 66% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java rename to ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java index 0fe88de953..38a8e40256 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTag.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java @@ -19,17 +19,16 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.Collections; -import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.TagUtils; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -39,21 +38,26 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** + * Action to delete the follow up tag a + * * */ -public class DeleteFollowUpTag extends Action { +public class DeleteTagAction extends Action { - private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTag.class.getName()); + private static final Logger LOGGER = Logger.getLogger(DeleteTagAction.class.getName()); private final long fileID; private final DrawableFile file; + private final ImageGalleryController controller; + private final ContentTag tag; - public DeleteFollowUpTag(DrawableFile file) { + public DeleteTagAction(ImageGalleryController controller, DrawableFile file, ContentTag tag) { super("Delete Follow Up Tag"); + this.controller = controller; this.file = file; this.fileID = file.getId(); - + this.tag = tag; setEventHandler((ActionEvent t) -> { - deleteFollowupTag(); + deleteTag(); }); } @@ -63,24 +67,26 @@ public class DeleteFollowUpTag extends Action { * * @throws IllegalStateException */ - private void deleteFollowupTag() throws IllegalStateException { + private void deleteTag() throws IllegalStateException { - final ImageGalleryController controller = ImageGalleryController.getDefault(); final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + final GroupManager groupManager = controller.getGroupManager(); + try { // remove file from old category group - controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); - - List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { - sleuthKitCase.deleteContentTag(ct); - } - } + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, tag.getName()), fileID); + sleuthKitCase.deleteContentTag(tag); +// +// List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); +// for (ContentTag ct : contentTagsByContent) { +// if (ct.getName().getDisplayName().equals(tagsManager.getFollowUpTagName().getDisplayName())) { +// sleuthKitCase.deleteContentTag(ct); +// } +// } IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS //make sure rest of ui hears category change. - controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 3377fdce6e..551db0e6c6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -54,6 +54,7 @@ import org.sleuthkit.datamodel.TskCoreException; public class CategoryManager { private static final java.util.logging.Logger LOGGER = Logger.getLogger(CategoryManager.class.getName()); + private final ImageGalleryController controller; private final ImageGalleryController controller; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 87fa001827..db378c9917 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -47,6 +47,7 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index 4f601f9400..b3bf25ee96 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -131,11 +131,13 @@ public abstract class DrawableTileBase extends DrawableUIBase { */ final private GroupPane groupPane; volatile private boolean registered = false; + private final ImageGalleryController controller; protected DrawableTileBase(GroupPane groupPane) { super(groupPane.getController()); this.groupPane = groupPane; + this.controller = groupPane.getController(); globalSelectionModel.getSelected().addListener((Observable observable) -> { updateSelectionState(); }); @@ -266,32 +268,6 @@ public abstract class DrawableTileBase extends DrawableUIBase { }); } -// /** -// * -// * @param fileID1 the value of fileID1 -// * -// * @throws IllegalStateException -// */ -// private void deleteFollowupTag(final Long fileID1) throws IllegalStateException { -// //TODO: convert this to an action! -// final ImageGalleryController controller = ImageGalleryController.getDefault(); -// try { -// // remove file from old category group -// controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID1); -// -// List contentTagsByContent = controller.getSleuthKitCase().getContentTagsByContent(file); -// for (ContentTag ct : contentTagsByContent) { -// if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { -// controller.getSleuthKitCase().deleteContentTag(ct); -// } -// } -// IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS -// controller.getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID1), DrawableAttribute.TAGS)); -// } catch (TskCoreException ex) { -// LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); -// } -// } - protected boolean hasFollowUp() { if (getFileID().isPresent()) { try { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java index 4d7f31a52a..67647334d6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java @@ -1,7 +1,6 @@ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.eventbus.Subscribe; -import java.util.Collection; import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index ab011fc493..9bc0cf493e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -100,6 +100,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index 5ebc6c1984..45399e2f79 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -61,6 +61,11 @@ public class MetaDataPane extends DrawableUIBase { private static final Logger LOGGER = Logger.getLogger(MetaDataPane.class.getName()); + @Override + public ImageGalleryController getController() { + return controller; + } + @FXML private ImageView imageView; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java index 2b29e57d39..91fbec5a24 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java @@ -50,6 +50,7 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; From e94f29e16df4357fd5be1b96007c1c84e9cbe1a7 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 17 Jun 2015 15:51:15 -0400 Subject: [PATCH 158/198] make sure all code is using the correct TagsManager (DrawableTagsManager) from controller; more cleanup --- .../imagegallery/DrawableTagsManager.java | 49 +++++++++- .../actions/AddDrawableTagAction.java | 1 + .../imagegallery/actions/AddTagAction.java | 1 + .../actions/CategorizeAction.java | 1 + .../actions/DeleteFollowUpTagAction.java | 72 +++++++++----- .../imagegallery/actions/DeleteTagAction.java | 94 ------------------- .../datamodel/grouping/GroupManager.java | 14 +++ .../gui/drawableviews/DrawableTileBase.java | 1 + 8 files changed, 111 insertions(+), 122 deletions(-) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 3c1dd42de3..7ba9ceb842 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -28,6 +28,10 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.ingest.IngestServices; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -45,7 +49,7 @@ public class DrawableTagsManager { /** Used to distribute {@link TagsChangeEvent}s */ private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); - /** The tag name corresponging to the "built-in" tag "Follow Up" */ + /** The tag name corresponding to the "built-in" tag "Follow Up" */ private TagName followUpTagName; public DrawableTagsManager(TagsManager autopsyTagsManager) { @@ -113,7 +117,7 @@ public class DrawableTagsManager { return followUpTagName; } - public Collection getNonCategoryTagNames() { + synchronized public Collection getNonCategoryTagNames() { try { return autopsyTagsManager.getAllTagNames().stream() .filter(Category::isCategoryTagName) @@ -124,6 +128,20 @@ public class DrawableTagsManager { return Collections.emptySet(); } + /** + * Gets content tags count by content. + * + * @param The content of interest. + * + * @return A list, possibly empty, of the tags that have been applied to the + * artifact. + * + * @throws TskCoreException + */ + public synchronized List getContentTagsByContent(Content content) throws TskCoreException { + return autopsyTagsManager.getContentTagsByContent(content); + } + public synchronized TagName getTagName(String displayName) throws TskCoreException { try { for (TagName tn : autopsyTagsManager.getAllTagNames()) { @@ -150,12 +168,35 @@ public class DrawableTagsManager { } } - public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { + synchronized public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { autopsyTagsManager.addContentTag(file, tagName, comment); } - public List getContentTagsByTagName(TagName t) throws TskCoreException { + synchronized public List getContentTagsByTagName(TagName t) throws TskCoreException { return autopsyTagsManager.getContentTagsByTagName(t); } + /** + * Fire the ModuleDataEvent that we use as a place holder for a real Tag + * Event. This is used to refresh the autopsy tag tree and the ui in + * ImageGallery + * + * + * Note: this is a hack. In an ideal world, TagsManager would fire + * events so that the directory tree would refresh. But, we haven't + * had a chance to add that so, we fire these events and the tree + * refreshes based on them. + */ + static public void fireTagsChangedEvent() { + + IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS + } + + public synchronized List getAllTagNames() throws TskCoreException { + return autopsyTagsManager.getAllTagNames(); + } + + public synchronized List getTagNamesInUse() throws TskCoreException { + return autopsyTagsManager.getTagNamesInUse(); + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index 3c115d9134..b3a45b3030 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -27,6 +27,7 @@ import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.openide.util.Utilities; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 44bb02f0e0..af42c5ef2c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -26,6 +26,7 @@ import javafx.scene.control.MenuItem; import javax.swing.SwingUtilities; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index ff0c939ee3..24e59dda65 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -30,6 +30,7 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index fb729807c0..6a1a54c30d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -18,16 +18,21 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; +import java.util.Collections; import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; -import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; +import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -37,31 +42,50 @@ import org.sleuthkit.datamodel.TskCoreException; public class DeleteFollowUpTagAction extends Action { private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTagAction.class.getName()); + private final long fileID; + private final DrawableFile file; + private final ImageGalleryController controller; - public DeleteFollowUpTagAction(final ImageGalleryController controller, final DrawableFile file) { + public DeleteFollowUpTagAction(ImageGalleryController controller, DrawableFile file) { super("Delete Follow Up Tag"); + this.controller = controller; + this.file = file; + this.fileID = file.getId(); setEventHandler((ActionEvent t) -> { - new SwingWorker() { - - @Override - protected Void doInBackground() throws Exception { - final DrawableTagsManager tagsManager = controller.getTagsManager(); - - try { - final TagName followUpTagName = tagsManager.getFollowUpTagName(); - - List contentTagsByContent = tagsManager.getContentTagsByContent(file); - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { - tagsManager.deleteContentTag(ct); - } - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); - } - return null; - } - }.execute(); + deleteTag(); }); } + + /** + * + * + * + */ + private void deleteTag() { + + final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + final GroupManager groupManager = controller.getGroupManager(); + final DrawableTagsManager tagsManager = controller.getTagsManager(); + + try { + final TagName followUpTagName = tagsManager.getFollowUpTagName(); + // remove file from old category group + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); + + List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); + for (ContentTag ct : contentTagsByContent) { + if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { + sleuthKitCase.deleteContentTag(ct); + } + } + + DrawableTagsManager.fireTagsChangedEvent(); + + //make sure rest of ui hears category change. + groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); + } + } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java deleted file mode 100644 index 38a8e40256..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery.actions; - -import java.util.Collections; -import java.util.logging.Level; -import javafx.event.ActionEvent; -import org.controlsfx.control.action.Action; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; -import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Action to delete the follow up tag a - * - * - */ -public class DeleteTagAction extends Action { - - private static final Logger LOGGER = Logger.getLogger(DeleteTagAction.class.getName()); - private final long fileID; - private final DrawableFile file; - private final ImageGalleryController controller; - private final ContentTag tag; - - public DeleteTagAction(ImageGalleryController controller, DrawableFile file, ContentTag tag) { - super("Delete Follow Up Tag"); - this.controller = controller; - this.file = file; - this.fileID = file.getId(); - this.tag = tag; - setEventHandler((ActionEvent t) -> { - deleteTag(); - }); - } - - /** - * - * @param fileID1 the value of fileID1 - * - * @throws IllegalStateException - */ - private void deleteTag() throws IllegalStateException { - - final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); - final GroupManager groupManager = controller.getGroupManager(); - - try { - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, tag.getName()), fileID); - sleuthKitCase.deleteContentTag(tag); -// -// List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); -// for (ContentTag ct : contentTagsByContent) { -// if (ct.getName().getDisplayName().equals(tagsManager.getFollowUpTagName().getDisplayName())) { -// sleuthKitCase.deleteContentTag(ct); -// } -// } - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - - //make sure rest of ui hears category change. - groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); - } - } -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index 2c0da12044..61281a519c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -199,7 +199,21 @@ public class GroupManager { @Nullable public DrawableGroup getGroupForKey(@Nonnull GroupKey groupKey) { synchronized (groupMap) { + if (groupKey.getAttribute() == DrawableAttribute.TAGS) { + + System.out.println(groupKey); +// @SuppressWarnings("unchecked") +// GroupKey tagKey = (GroupKey) groupKey; +// +// return groupMap.keySet().stream() +// .filter((GroupKey t) -> t.getAttribute() == DrawableAttribute.TAGS) +// .map((GroupKey t) -> (GroupKey) t) +// .filter(t -> tagKey.getValue().getDisplayName().equals(t.getValue().getDisplayName())) +// .findFirst().map(groupMap::get).orElse(null); + + } //else { return groupMap.get(groupKey); +// } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index b3bf25ee96..f579a35aed 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -258,6 +258,7 @@ public abstract class DrawableTileBase extends DrawableUIBase { try { globalSelectionModel.clearAndSelect(file.getId()); new AddDrawableTagAction(getController()).addTag(getController().getTagsManager().getFollowUpTagName(), ""); + new AddDrawableTagAction(controller).addTag(followUpTagName, ""); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); } From 2eecaa297e8c432773a913720b1dc3cdf8bfd9f1 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 17 Jun 2015 15:54:34 -0400 Subject: [PATCH 159/198] more cleanup of Categories/Tags and listening to autopsy generated "Tag Events" -remove unused code from Category.java -use Category.isCategoryTagName instead of .getDisplayName().startsWith(Category.CATEGORY_PREFIX) -regroup when notified of Tag Change from autopsy --- .../imagegallery/DrawableTagsManager.java | 3 +- .../imagegallery/ImageGalleryController.java | 224 +++++++++--------- .../imagegallery/datamodel/Category.java | 8 +- .../datamodel/grouping/GroupManager.java | 10 + 4 files changed, 133 insertions(+), 112 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 7ba9ceb842..2639de7617 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -22,6 +22,7 @@ import com.google.common.eventbus.EventBus; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.logging.Level; import java.util.stream.Collectors; import org.sleuthkit.autopsy.casemodule.services.TagsManager; @@ -111,7 +112,7 @@ public class DrawableTagsManager { * @throws TskCoreException */ synchronized public TagName getFollowUpTagName() throws TskCoreException { - if (followUpTagName == null) { + if (Objects.isNull(followUpTagName)) { followUpTagName = getTagName(FOLLOW_UP); } return followUpTagName; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 95b7141f78..907ef4556d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.imagegallery; import java.beans.PropertyChangeEvent; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.BlockingQueue; @@ -69,6 +70,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -84,25 +86,25 @@ import org.sleuthkit.datamodel.TskData; * control. */ public final class ImageGalleryController { - + private static final Logger LOGGER = Logger.getLogger(ImageGalleryController.class.getName()); - + private final Region infoOverLayBackground = new Region() { { setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY))); setOpacity(.4); } }; - + private static ImageGalleryController instance; - + public static synchronized ImageGalleryController getDefault() { if (instance == null) { instance = new ImageGalleryController(); } return instance; } - + private final History historyManager = new History<>(); /** @@ -110,75 +112,75 @@ public final class ImageGalleryController { * not listen to speed up ingest */ private final SimpleBooleanProperty listeningEnabled = new SimpleBooleanProperty(false); - + private final ReadOnlyIntegerWrapper queueSizeProperty = new ReadOnlyIntegerWrapper(0); - + private final ReadOnlyBooleanWrapper regroupDisabled = new ReadOnlyBooleanWrapper(false); - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private final ReadOnlyBooleanWrapper stale = new ReadOnlyBooleanWrapper(false); - + private final ReadOnlyBooleanWrapper metaDataCollapsed = new ReadOnlyBooleanWrapper(false); - + private final FileIDSelectionModel selectionModel = FileIDSelectionModel.getInstance(); - + private DBWorkerThread dbWorkerThread; - + private DrawableDB db; - + private final GroupManager groupManager = new GroupManager(this); private final HashSetManager hashSetManager = new HashSetManager(); private final CategoryManager categoryManager = new CategoryManager(this); private final DrawableTagsManager tagsManager = new DrawableTagsManager(null); - + private StackPane fullUIStackPane; - + private StackPane centralStackPane; - + private Node infoOverlay; private SleuthkitCase sleuthKitCase; - + public ReadOnlyBooleanProperty getMetaDataCollapsed() { return metaDataCollapsed.getReadOnlyProperty(); } - + public void setMetaDataCollapsed(Boolean metaDataCollapsed) { this.metaDataCollapsed.set(metaDataCollapsed); } - + private GroupViewState getViewState() { return historyManager.getCurrentState(); } - + public ReadOnlyBooleanProperty regroupDisabled() { return regroupDisabled.getReadOnlyProperty(); } - + public ReadOnlyObjectProperty viewState() { return historyManager.currentState(); } - + public synchronized FileIDSelectionModel getSelectionModel() { - + return selectionModel; } - + public GroupManager getGroupManager() { return groupManager; } - + public DrawableDB getDatabase() { return db; } - + synchronized public void setListeningEnabled(boolean enabled) { listeningEnabled.set(enabled); } - + synchronized boolean isListeningEnabled() { return listeningEnabled.get(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.ANY) void setStale(Boolean b) { Platform.runLater(() -> { @@ -188,18 +190,18 @@ public final class ImageGalleryController { new PerCaseProperties(Case.getCurrentCase()).setConfigSetting(ImageGalleryModule.getModuleName(), PerCaseProperties.STALE, b.toString()); } } - + public ReadOnlyBooleanProperty stale() { return stale.getReadOnlyProperty(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) boolean isStale() { return stale.get(); } - + private ImageGalleryController() { - + listeningEnabled.addListener((observable, oldValue, newValue) -> { //if we just turned on listening and a case is open and that case is not up to date if (newValue && !oldValue && Case.existsCurrentCase() && ImageGalleryModule.isDrawableDBStale(Case.getCurrentCase())) { @@ -207,28 +209,28 @@ public final class ImageGalleryController { queueDBWorkerTask(new CopyAnalyzedFiles()); } }); - + groupManager.getAnalyzedGroups().addListener((Observable o) -> { if (Case.isCaseOpen()) { checkForGroups(); } }); - + groupManager.getUnSeenGroups().addListener((Observable observable) -> { //if there are unseen groups and none being viewed if (groupManager.getUnSeenGroups().isEmpty() == false && (getViewState() == null || getViewState().getGroup() == null)) { advance(GroupViewState.tile(groupManager.getUnSeenGroups().get(0))); } }); - + viewState().addListener((Observable observable) -> { selectionModel.clearSelection(); }); - + regroupDisabled.addListener((Observable observable) -> { checkForGroups(); }); - + IngestManager.getInstance().addIngestModuleEventListener((PropertyChangeEvent evt) -> { Platform.runLater(this::updateRegroupDisabled); }); @@ -237,27 +239,27 @@ public final class ImageGalleryController { }); // metaDataCollapsed.bind(Toolbar.getDefault().showMetaDataProperty()); } - + public ReadOnlyBooleanProperty getCanAdvance() { return historyManager.getCanAdvance(); } - + public ReadOnlyBooleanProperty getCanRetreat() { return historyManager.getCanRetreat(); } - + public void advance(GroupViewState newState) { historyManager.advance(newState); } - + public GroupViewState advance() { return historyManager.advance(); } - + public GroupViewState retreat() { return historyManager.retreat(); } - + private void updateRegroupDisabled() { regroupDisabled.set(getFileUpdateQueueSizeProperty().get() > 0 || IngestManager.getInstance().isIngestRunning()); } @@ -279,7 +281,7 @@ public final class ImageGalleryController { new NoGroupsDialog("No groups are fully analyzed yet, but ingest is still ongoing. Please Wait.", new ProgressIndicator())); } - + } else if (getFileUpdateQueueSizeProperty().get() > 0) { replaceNotification(fullUIStackPane, new NoGroupsDialog("No groups are fully analyzed yet, but image / video data is still being populated. Please Wait.", @@ -293,19 +295,19 @@ public final class ImageGalleryController { replaceNotification(fullUIStackPane, new NoGroupsDialog("There are no images/videos in the added datasources.")); } - + } else if (!groupManager.isRegrouping()) { replaceNotification(centralStackPane, new NoGroupsDialog("There are no fully analyzed groups to display:" + " the current Group By setting resulted in no groups, " + "or no groups are fully analyzed but ingest is not running.")); } - + } else { clearNotification(); } } - + private void clearNotification() { //remove the ingest spinner if (fullUIStackPane != null) { @@ -316,27 +318,27 @@ public final class ImageGalleryController { centralStackPane.getChildren().remove(infoOverlay); } } - + private void replaceNotification(StackPane stackPane, Node newNode) { clearNotification(); - + infoOverlay = new StackPane(infoOverLayBackground, newNode); if (stackPane != null) { stackPane.getChildren().add(infoOverlay); } } - + private void restartWorker() { if (dbWorkerThread != null) { // Keep using the same worker thread if one exists return; } dbWorkerThread = new DBWorkerThread(); - + getFileUpdateQueueSizeProperty().addListener((Observable o) -> { Platform.runLater(this::updateRegroupDisabled); }); - + Thread th = new Thread(dbWorkerThread, "DB-Worker-Thread"); th.setDaemon(false); // we want it to go away when it is done th.start(); @@ -351,7 +353,7 @@ public final class ImageGalleryController { if (Objects.nonNull(theNewCase)) { this.sleuthKitCase = theNewCase.getSleuthkitCase(); this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); - + setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); @@ -385,7 +387,7 @@ public final class ImageGalleryController { tagsManager.clearFollowUpTagName(); tagsManager.unregisterListener(groupManager); tagsManager.unregisterListener(categoryManager); - + Toolbar.getDefault(this).reset(); groupManager.clear(); if (db != null) { @@ -407,21 +409,21 @@ public final class ImageGalleryController { } dbWorkerThread.addTask(innerTask); } - + public DrawableFile getFileFromId(Long fileID) throws TskCoreException { return db.getFileFromID(fileID); } - + public void setStacks(StackPane fullUIStack, StackPane centralStack) { fullUIStackPane = fullUIStack; this.centralStackPane = centralStack; Platform.runLater(this::checkForGroups); } - + public ReadOnlyIntegerProperty getFileUpdateQueueSizeProperty() { return queueSizeProperty.getReadOnlyProperty(); } - + public ReadOnlyDoubleProperty regroupProgress() { return groupManager.regroupProgress(); } @@ -440,6 +442,10 @@ public final class ImageGalleryController { case CONTENT_CHANGED: //TODO: do we need to do anything here? -jm case DATA_ADDED: + ModuleDataEvent oldValue = (ModuleDataEvent) evt.getOldValue(); + if ("TagAction".equals(oldValue.getModuleName()) && oldValue.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { + getTagsManager().fireChange(Collections.singleton(-1L)); + } /* we could listen to DATA events and progressivly * update files, and get data from DataSource ingest * modules, but given that most modules don't post new @@ -505,11 +511,11 @@ public final class ImageGalleryController { } }); } - + public HashSetManager getHashSetManager() { return hashSetManager; } - + public CategoryManager getCategoryManager() { return categoryManager; } @@ -517,7 +523,7 @@ public final class ImageGalleryController { public DrawableTagsManager getTagsManager() { return tagsManager; } - + public DrawableTagsManager getTagsManager() { return tagsManager; } @@ -558,7 +564,7 @@ public final class ImageGalleryController { queueSizeProperty.set(workQueue.size()); }); } - + @Override public void run() { @@ -569,22 +575,22 @@ public final class ImageGalleryController { } try { InnerTask it = workQueue.take(); - + if (it.cancelled == false) { it.run(); } - + Platform.runLater(() -> { queueSizeProperty.set(workQueue.size()); }); - + } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); } } } } - + public synchronized SleuthkitCase getSleuthKitCase() { return sleuthKitCase; } @@ -593,55 +599,55 @@ public final class ImageGalleryController { * Abstract base class for task to be done on {@link DBWorkerThread} */ static public abstract class InnerTask implements Runnable { - + public double getProgress() { return progress.get(); } - + public final void updateProgress(Double workDone) { this.progress.set(workDone); } - + public String getMessage() { return message.get(); } - + public final void updateMessage(String Status) { this.message.set(Status); } SimpleObjectProperty state = new SimpleObjectProperty<>(Worker.State.READY); SimpleDoubleProperty progress = new SimpleDoubleProperty(this, "pregress"); SimpleStringProperty message = new SimpleStringProperty(this, "status"); - + public SimpleDoubleProperty progressProperty() { return progress; } - + public SimpleStringProperty messageProperty() { return message; } - + public Worker.State getState() { return state.get(); } - + protected void updateState(Worker.State newState) { state.set(newState); } - + public ReadOnlyObjectProperty stateProperty() { return new ReadOnlyObjectWrapper<>(state.get()); } - + protected InnerTask() { } - + protected volatile boolean cancelled = false; - + public void cancel() { updateState(Worker.State.CANCELLED); } - + protected boolean isCancelled() { return getState() == Worker.State.CANCELLED; } @@ -651,25 +657,25 @@ public final class ImageGalleryController { * Abstract base class for tasks associated with a file in the database */ static public abstract class FileTask extends InnerTask { - + private final AbstractFile file; - + public AbstractFile getFile() { return file; } - + public FileTask(AbstractFile f) { super(); this.file = f; } - + } /** * task that updates one file in database with results from ingest */ private class UpdateFileTask extends FileTask { - + public UpdateFileTask(AbstractFile f) { super(f); } @@ -696,7 +702,7 @@ public final class ImageGalleryController { * task that updates one file in database with results from ingest */ private class RemoveFileTask extends FileTask { - + public RemoveFileTask(AbstractFile f) { super(f); } @@ -715,7 +721,7 @@ public final class ImageGalleryController { Logger.getLogger(RemoveFileTask.class.getName()).log(Level.SEVERE, "Case was closed out from underneath RemoveFile task"); } } - + } } @@ -727,16 +733,16 @@ public final class ImageGalleryController { * adds them to the Drawable DB */ private class CopyAnalyzedFiles extends InnerTask { - + final private String DRAWABLE_QUERY = "name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "'"; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("populating analyzed image/video database"); - + @Override public void run() { progressHandle.start(); updateMessage("populating analyzed image/video database"); - + try { //grab all files with supported extension or detected mime types final List files = getSleuthKitCase().findAllFilesWhere(DRAWABLE_QUERY + " or tsk_files.obj_id in (select tsk_files.obj_id from tsk_files , blackboard_artifacts, blackboard_attributes" @@ -746,7 +752,7 @@ public final class ImageGalleryController { + " and blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID() + " and blackboard_attributes.value_text in ('" + StringUtils.join(ImageGalleryModule.getSupportedMimes(), "','") + "'))"); progressHandle.switchToDeterminate(files.size()); - + updateProgress(0.0); //do in transaction @@ -760,7 +766,7 @@ public final class ImageGalleryController { } final Boolean hasMimeType = ImageGalleryModule.hasSupportedMimeType(f); final boolean known = f.getKnown() == TskData.FileKnown.KNOWN; - + if (known) { db.removeFile(f.getId(), tr); //remove known files } else { @@ -780,38 +786,38 @@ public final class ImageGalleryController { } } } - + units++; final int prog = units; progressHandle.progress(f.getName(), units); updateProgress(prog - 1 / (double) files.size()); updateMessage(f.getName()); } - + progressHandle.finish(); - + progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); updateMessage("commiting image/video database"); updateProgress(1.0); - + progressHandle.start(); db.commitTransaction(tr, true); - + } catch (TskCoreException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.SEVERE, "Case was closed out from underneath CopyDataSource task", ex); } - + progressHandle.finish(); - + updateMessage( ""); updateProgress( -1.0); setStale(false); } - + } /** @@ -822,7 +828,7 @@ public final class ImageGalleryController { * netbeans and ImageGallery progress/status */ class PrePopulateDataSourceFiles extends InnerTask { - + private final Content dataSource; /** @@ -832,7 +838,7 @@ public final class ImageGalleryController { */ // (name like '.jpg' or name like '.png' ...) private final String DRAWABLE_QUERY = "(name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "') "; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("prepopulating image/video database"); /** @@ -858,7 +864,7 @@ public final class ImageGalleryController { final List files; try { List fsObjIds = new ArrayList<>(); - + String fsQuery; if (dataSource instanceof Image) { Image image = (Image) dataSource; @@ -872,7 +878,7 @@ public final class ImageGalleryController { else { fsQuery = "(fs_obj_id IS NULL) "; } - + files = getSleuthKitCase().findAllFilesWhere(fsQuery + " and " + DRAWABLE_QUERY); progressHandle.switchToDeterminate(files.size()); @@ -890,21 +896,21 @@ public final class ImageGalleryController { final int prog = units; progressHandle.progress(f.getName(), units); } - + progressHandle.finish(); progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); - + progressHandle.start(); db.commitTransaction(tr, false); - + } catch (TskCoreException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException | NullPointerException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "Case was closed out from underneath prepopulating database"); } - + progressHandle.finish(); } } - + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 7cae09067f..d2160e9196 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -53,8 +53,12 @@ public enum Category { return nameMap.containsKey(tName); } - public static boolean isCategoryTagName(TagName tName) { - return nameMap.containsKey(tName.getDisplayName()); + public static boolean isNotCategoryTagName(TagName tName) { + return isNotCategoryName(tName.getDisplayName()); + } + + public static boolean isNotCategoryName(String tName) { + return nameMap.containsKey(tName) == false; } public static boolean isNotCategoryName(String tName) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index 61281a519c..921cd9b8ff 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -63,6 +63,7 @@ import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; +import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -556,6 +557,15 @@ public class GroupManager { return regroupProgress.getReadOnlyProperty(); } + @Subscribe + public void handleAutopsyTagChange(TagsChangeEvent evt) { + if (groupBy == DrawableAttribute.TAGS + && evt.getFileIDs().size() == 1 + && evt.getFileIDs().contains(-1L)) { + regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); + } + } + @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { GroupKey newGroupKey = null; From 1f813a6708af73e555fb7ccd3cec2e414b604d2c Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 17 Jun 2015 17:42:00 -0400 Subject: [PATCH 160/198] more work to keep autopsy and ImageGallery tags in sync add setFiles method to DrawableGroup; don't clear groups from GroupMap except for CaseChange; reuse groups via setFiles method when regrouping reselect group in navpanel after regroup --- .../imagegallery/DrawableTagsManager.java | 2 +- .../datamodel/grouping/DrawableGroup.java | 6 +++-- .../datamodel/grouping/GroupManager.java | 22 ++++++------------- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 2639de7617..149c7fd888 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-15 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java index ac0493d75e..6fdc9c236a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java @@ -165,11 +165,13 @@ public class DrawableGroup implements Comparable { // By default, sort by group key name @Override - public int compareTo(DrawableGroup other) { + public int compareTo(DrawableGroup other + ) { return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName()); } - void setSeen(boolean isSeen) { + void setSeen(boolean isSeen + ) { this.seen.set(isSeen); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index 921cd9b8ff..d373e29728 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -200,21 +200,7 @@ public class GroupManager { @Nullable public DrawableGroup getGroupForKey(@Nonnull GroupKey groupKey) { synchronized (groupMap) { - if (groupKey.getAttribute() == DrawableAttribute.TAGS) { - - System.out.println(groupKey); -// @SuppressWarnings("unchecked") -// GroupKey tagKey = (GroupKey) groupKey; -// -// return groupMap.keySet().stream() -// .filter((GroupKey t) -> t.getAttribute() == DrawableAttribute.TAGS) -// .map((GroupKey t) -> (GroupKey) t) -// .filter(t -> tagKey.getValue().getDisplayName().equals(t.getValue().getDisplayName())) -// .findFirst().map(groupMap::get).orElse(null); - - } //else { return groupMap.get(groupKey); -// } } } @@ -258,15 +244,19 @@ public class GroupManager { /** * 'mark' the given group as seen. This removes it from the queue of * groups + * files. public DrawableGroup makeGroup(GroupKey groupKey, Set files) { Set newFiles = ObjectUtils.defaultIfNull(files, new HashSet()); + } + * groups * to review, and is persisted in the drawable db. * * @param group the {@link DrawableGroup} to mark as seen */ @ThreadConfined(type = ThreadType.JFX) - public void markGroupSeen(DrawableGroup group, boolean seen) { + public void markGroupSeen(DrawableGroup group, boolean seen + ) { db.markGroupSeen(group.getGroupKey(), seen); group.setSeen(seen); if (seen) { @@ -546,6 +536,7 @@ public class GroupManager { unmodifiableUnSeenGroups.setComparator(sortBy.getGrpComparator(sortOrder)); }); } + } /** @@ -705,6 +696,7 @@ public class GroupManager { LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); } } + } return null; } From e336dccfb2968b4a995d3bbeab0d2933d6264bec Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 11:39:16 -0400 Subject: [PATCH 161/198] refactor in GroupManager, to make logic and flow cleaner split FileUpdateEvent handlers to seperate update and removed methods name DbWorkerThread, Thread --- .../imagegallery/ImageGalleryController.java | 218 +++++++++--------- .../datamodel/grouping/DrawableGroup.java | 6 +- .../datamodel/grouping/GroupManager.java | 58 ++++- 3 files changed, 160 insertions(+), 122 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 907ef4556d..3bb7f83f97 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -86,25 +86,25 @@ import org.sleuthkit.datamodel.TskData; * control. */ public final class ImageGalleryController { - + private static final Logger LOGGER = Logger.getLogger(ImageGalleryController.class.getName()); - + private final Region infoOverLayBackground = new Region() { { setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY))); setOpacity(.4); } }; - + private static ImageGalleryController instance; - + public static synchronized ImageGalleryController getDefault() { if (instance == null) { instance = new ImageGalleryController(); } return instance; } - + private final History historyManager = new History<>(); /** @@ -112,75 +112,75 @@ public final class ImageGalleryController { * not listen to speed up ingest */ private final SimpleBooleanProperty listeningEnabled = new SimpleBooleanProperty(false); - + private final ReadOnlyIntegerWrapper queueSizeProperty = new ReadOnlyIntegerWrapper(0); - + private final ReadOnlyBooleanWrapper regroupDisabled = new ReadOnlyBooleanWrapper(false); - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private final ReadOnlyBooleanWrapper stale = new ReadOnlyBooleanWrapper(false); - + private final ReadOnlyBooleanWrapper metaDataCollapsed = new ReadOnlyBooleanWrapper(false); - + private final FileIDSelectionModel selectionModel = FileIDSelectionModel.getInstance(); - + private DBWorkerThread dbWorkerThread; - + private DrawableDB db; - + private final GroupManager groupManager = new GroupManager(this); private final HashSetManager hashSetManager = new HashSetManager(); private final CategoryManager categoryManager = new CategoryManager(this); private final DrawableTagsManager tagsManager = new DrawableTagsManager(null); - + private StackPane fullUIStackPane; - + private StackPane centralStackPane; - + private Node infoOverlay; private SleuthkitCase sleuthKitCase; - + public ReadOnlyBooleanProperty getMetaDataCollapsed() { return metaDataCollapsed.getReadOnlyProperty(); } - + public void setMetaDataCollapsed(Boolean metaDataCollapsed) { this.metaDataCollapsed.set(metaDataCollapsed); } - + private GroupViewState getViewState() { return historyManager.getCurrentState(); } - + public ReadOnlyBooleanProperty regroupDisabled() { return regroupDisabled.getReadOnlyProperty(); } - + public ReadOnlyObjectProperty viewState() { return historyManager.currentState(); } - + public synchronized FileIDSelectionModel getSelectionModel() { - + return selectionModel; } - + public GroupManager getGroupManager() { return groupManager; } - + public DrawableDB getDatabase() { return db; } - + synchronized public void setListeningEnabled(boolean enabled) { listeningEnabled.set(enabled); } - + synchronized boolean isListeningEnabled() { return listeningEnabled.get(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.ANY) void setStale(Boolean b) { Platform.runLater(() -> { @@ -190,18 +190,18 @@ public final class ImageGalleryController { new PerCaseProperties(Case.getCurrentCase()).setConfigSetting(ImageGalleryModule.getModuleName(), PerCaseProperties.STALE, b.toString()); } } - + public ReadOnlyBooleanProperty stale() { return stale.getReadOnlyProperty(); } - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) boolean isStale() { return stale.get(); } - + private ImageGalleryController() { - + listeningEnabled.addListener((observable, oldValue, newValue) -> { //if we just turned on listening and a case is open and that case is not up to date if (newValue && !oldValue && Case.existsCurrentCase() && ImageGalleryModule.isDrawableDBStale(Case.getCurrentCase())) { @@ -209,28 +209,28 @@ public final class ImageGalleryController { queueDBWorkerTask(new CopyAnalyzedFiles()); } }); - + groupManager.getAnalyzedGroups().addListener((Observable o) -> { if (Case.isCaseOpen()) { checkForGroups(); } }); - + groupManager.getUnSeenGroups().addListener((Observable observable) -> { //if there are unseen groups and none being viewed if (groupManager.getUnSeenGroups().isEmpty() == false && (getViewState() == null || getViewState().getGroup() == null)) { advance(GroupViewState.tile(groupManager.getUnSeenGroups().get(0))); } }); - + viewState().addListener((Observable observable) -> { selectionModel.clearSelection(); }); - + regroupDisabled.addListener((Observable observable) -> { checkForGroups(); }); - + IngestManager.getInstance().addIngestModuleEventListener((PropertyChangeEvent evt) -> { Platform.runLater(this::updateRegroupDisabled); }); @@ -239,27 +239,27 @@ public final class ImageGalleryController { }); // metaDataCollapsed.bind(Toolbar.getDefault().showMetaDataProperty()); } - + public ReadOnlyBooleanProperty getCanAdvance() { return historyManager.getCanAdvance(); } - + public ReadOnlyBooleanProperty getCanRetreat() { return historyManager.getCanRetreat(); } - + public void advance(GroupViewState newState) { historyManager.advance(newState); } - + public GroupViewState advance() { return historyManager.advance(); } - + public GroupViewState retreat() { return historyManager.retreat(); } - + private void updateRegroupDisabled() { regroupDisabled.set(getFileUpdateQueueSizeProperty().get() > 0 || IngestManager.getInstance().isIngestRunning()); } @@ -281,7 +281,7 @@ public final class ImageGalleryController { new NoGroupsDialog("No groups are fully analyzed yet, but ingest is still ongoing. Please Wait.", new ProgressIndicator())); } - + } else if (getFileUpdateQueueSizeProperty().get() > 0) { replaceNotification(fullUIStackPane, new NoGroupsDialog("No groups are fully analyzed yet, but image / video data is still being populated. Please Wait.", @@ -295,19 +295,19 @@ public final class ImageGalleryController { replaceNotification(fullUIStackPane, new NoGroupsDialog("There are no images/videos in the added datasources.")); } - + } else if (!groupManager.isRegrouping()) { replaceNotification(centralStackPane, new NoGroupsDialog("There are no fully analyzed groups to display:" + " the current Group By setting resulted in no groups, " + "or no groups are fully analyzed but ingest is not running.")); } - + } else { clearNotification(); } } - + private void clearNotification() { //remove the ingest spinner if (fullUIStackPane != null) { @@ -318,27 +318,27 @@ public final class ImageGalleryController { centralStackPane.getChildren().remove(infoOverlay); } } - + private void replaceNotification(StackPane stackPane, Node newNode) { clearNotification(); - + infoOverlay = new StackPane(infoOverLayBackground, newNode); if (stackPane != null) { stackPane.getChildren().add(infoOverlay); } } - + private void restartWorker() { if (dbWorkerThread != null) { // Keep using the same worker thread if one exists return; } dbWorkerThread = new DBWorkerThread(); - + getFileUpdateQueueSizeProperty().addListener((Observable o) -> { Platform.runLater(this::updateRegroupDisabled); }); - + Thread th = new Thread(dbWorkerThread, "DB-Worker-Thread"); th.setDaemon(false); // we want it to go away when it is done th.start(); @@ -353,7 +353,7 @@ public final class ImageGalleryController { if (Objects.nonNull(theNewCase)) { this.sleuthKitCase = theNewCase.getSleuthkitCase(); this.db = DrawableDB.getDrawableDB(ImageGalleryModule.getModuleOutputDir(theNewCase), this); - + setListeningEnabled(ImageGalleryModule.isEnabledforCase(theNewCase)); setStale(ImageGalleryModule.isDrawableDBStale(theNewCase)); @@ -387,7 +387,7 @@ public final class ImageGalleryController { tagsManager.clearFollowUpTagName(); tagsManager.unregisterListener(groupManager); tagsManager.unregisterListener(categoryManager); - + Toolbar.getDefault(this).reset(); groupManager.clear(); if (db != null) { @@ -409,21 +409,21 @@ public final class ImageGalleryController { } dbWorkerThread.addTask(innerTask); } - + public DrawableFile getFileFromId(Long fileID) throws TskCoreException { return db.getFileFromID(fileID); } - + public void setStacks(StackPane fullUIStack, StackPane centralStack) { fullUIStackPane = fullUIStack; this.centralStackPane = centralStack; Platform.runLater(this::checkForGroups); } - + public ReadOnlyIntegerProperty getFileUpdateQueueSizeProperty() { return queueSizeProperty.getReadOnlyProperty(); } - + public ReadOnlyDoubleProperty regroupProgress() { return groupManager.regroupProgress(); } @@ -511,11 +511,11 @@ public final class ImageGalleryController { } }); } - + public HashSetManager getHashSetManager() { return hashSetManager; } - + public CategoryManager getCategoryManager() { return categoryManager; } @@ -523,7 +523,7 @@ public final class ImageGalleryController { public DrawableTagsManager getTagsManager() { return tagsManager; } - + public DrawableTagsManager getTagsManager() { return tagsManager; } @@ -564,7 +564,7 @@ public final class ImageGalleryController { queueSizeProperty.set(workQueue.size()); }); } - + @Override public void run() { @@ -575,22 +575,22 @@ public final class ImageGalleryController { } try { InnerTask it = workQueue.take(); - + if (it.cancelled == false) { it.run(); } - + Platform.runLater(() -> { queueSizeProperty.set(workQueue.size()); }); - + } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); } } } } - + public synchronized SleuthkitCase getSleuthKitCase() { return sleuthKitCase; } @@ -599,55 +599,55 @@ public final class ImageGalleryController { * Abstract base class for task to be done on {@link DBWorkerThread} */ static public abstract class InnerTask implements Runnable { - + public double getProgress() { return progress.get(); } - + public final void updateProgress(Double workDone) { this.progress.set(workDone); } - + public String getMessage() { return message.get(); } - + public final void updateMessage(String Status) { this.message.set(Status); } SimpleObjectProperty state = new SimpleObjectProperty<>(Worker.State.READY); SimpleDoubleProperty progress = new SimpleDoubleProperty(this, "pregress"); SimpleStringProperty message = new SimpleStringProperty(this, "status"); - + public SimpleDoubleProperty progressProperty() { return progress; } - + public SimpleStringProperty messageProperty() { return message; } - + public Worker.State getState() { return state.get(); } - + protected void updateState(Worker.State newState) { state.set(newState); } - + public ReadOnlyObjectProperty stateProperty() { return new ReadOnlyObjectWrapper<>(state.get()); } - + protected InnerTask() { } - + protected volatile boolean cancelled = false; - + public void cancel() { updateState(Worker.State.CANCELLED); } - + protected boolean isCancelled() { return getState() == Worker.State.CANCELLED; } @@ -657,25 +657,25 @@ public final class ImageGalleryController { * Abstract base class for tasks associated with a file in the database */ static public abstract class FileTask extends InnerTask { - + private final AbstractFile file; - + public AbstractFile getFile() { return file; } - + public FileTask(AbstractFile f) { super(); this.file = f; } - + } /** * task that updates one file in database with results from ingest */ private class UpdateFileTask extends FileTask { - + public UpdateFileTask(AbstractFile f) { super(f); } @@ -702,7 +702,7 @@ public final class ImageGalleryController { * task that updates one file in database with results from ingest */ private class RemoveFileTask extends FileTask { - + public RemoveFileTask(AbstractFile f) { super(f); } @@ -721,7 +721,7 @@ public final class ImageGalleryController { Logger.getLogger(RemoveFileTask.class.getName()).log(Level.SEVERE, "Case was closed out from underneath RemoveFile task"); } } - + } } @@ -733,16 +733,16 @@ public final class ImageGalleryController { * adds them to the Drawable DB */ private class CopyAnalyzedFiles extends InnerTask { - + final private String DRAWABLE_QUERY = "name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "'"; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("populating analyzed image/video database"); - + @Override public void run() { progressHandle.start(); updateMessage("populating analyzed image/video database"); - + try { //grab all files with supported extension or detected mime types final List files = getSleuthKitCase().findAllFilesWhere(DRAWABLE_QUERY + " or tsk_files.obj_id in (select tsk_files.obj_id from tsk_files , blackboard_artifacts, blackboard_attributes" @@ -752,7 +752,7 @@ public final class ImageGalleryController { + " and blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID() + " and blackboard_attributes.value_text in ('" + StringUtils.join(ImageGalleryModule.getSupportedMimes(), "','") + "'))"); progressHandle.switchToDeterminate(files.size()); - + updateProgress(0.0); //do in transaction @@ -766,7 +766,7 @@ public final class ImageGalleryController { } final Boolean hasMimeType = ImageGalleryModule.hasSupportedMimeType(f); final boolean known = f.getKnown() == TskData.FileKnown.KNOWN; - + if (known) { db.removeFile(f.getId(), tr); //remove known files } else { @@ -786,38 +786,38 @@ public final class ImageGalleryController { } } } - + units++; final int prog = units; progressHandle.progress(f.getName(), units); updateProgress(prog - 1 / (double) files.size()); updateMessage(f.getName()); } - + progressHandle.finish(); - + progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); updateMessage("commiting image/video database"); updateProgress(1.0); - + progressHandle.start(); db.commitTransaction(tr, true); - + } catch (TskCoreException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException ex) { Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.SEVERE, "Case was closed out from underneath CopyDataSource task", ex); } - + progressHandle.finish(); - + updateMessage( ""); updateProgress( -1.0); setStale(false); } - + } /** @@ -828,7 +828,7 @@ public final class ImageGalleryController { * netbeans and ImageGallery progress/status */ class PrePopulateDataSourceFiles extends InnerTask { - + private final Content dataSource; /** @@ -838,7 +838,7 @@ public final class ImageGalleryController { */ // (name like '.jpg' or name like '.png' ...) private final String DRAWABLE_QUERY = "(name LIKE '%." + StringUtils.join(ImageGalleryModule.getAllSupportedExtensions(), "' or name LIKE '%.") + "') "; - + private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("prepopulating image/video database"); /** @@ -864,7 +864,7 @@ public final class ImageGalleryController { final List files; try { List fsObjIds = new ArrayList<>(); - + String fsQuery; if (dataSource instanceof Image) { Image image = (Image) dataSource; @@ -878,7 +878,7 @@ public final class ImageGalleryController { else { fsQuery = "(fs_obj_id IS NULL) "; } - + files = getSleuthKitCase().findAllFilesWhere(fsQuery + " and " + DRAWABLE_QUERY); progressHandle.switchToDeterminate(files.size()); @@ -896,21 +896,21 @@ public final class ImageGalleryController { final int prog = units; progressHandle.progress(f.getName(), units); } - + progressHandle.finish(); progressHandle = ProgressHandleFactory.createHandle("commiting image/video database"); - + progressHandle.start(); db.commitTransaction(tr, false); - + } catch (TskCoreException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "failed to transfer all database contents", ex); } catch (IllegalStateException | NullPointerException ex) { Logger.getLogger(PrePopulateDataSourceFiles.class.getName()).log(Level.WARNING, "Case was closed out from underneath prepopulating database"); } - + progressHandle.finish(); } } - + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java index 6fdc9c236a..ac0493d75e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java @@ -165,13 +165,11 @@ public class DrawableGroup implements Comparable { // By default, sort by group key name @Override - public int compareTo(DrawableGroup other - ) { + public int compareTo(DrawableGroup other) { return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName()); } - void setSeen(boolean isSeen - ) { + void setSeen(boolean isSeen) { this.seen.set(isSeen); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index d373e29728..edbe0c1ff9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -50,6 +50,7 @@ import javax.annotation.concurrent.GuardedBy; import javax.swing.SortOrder; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; @@ -255,6 +256,7 @@ public class GroupManager { * @param group the {@link DrawableGroup} to mark as seen */ @ThreadConfined(type = ThreadType.JFX) + public void markGroupSeen(DrawableGroup group, boolean seen) { public void markGroupSeen(DrawableGroup group, boolean seen ) { db.markGroupSeen(group.getGroupKey(), seen); @@ -292,8 +294,6 @@ public class GroupManager { if (unSeenGroups.contains(group)) { unSeenGroups.remove(group); } - public synchronized void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup) { - private synchronized > void populateAnalyzedGroup(final GroupKey groupKey, Set filesInGroup, ReGroupTask task) { }); } } @@ -301,8 +301,6 @@ public class GroupManager { // It may be that this was the last unanalyzed file in the group, so test // whether the group is now fully analyzed. popuplateIfAnalyzed(groupKey, null); - public Set checkAnalyzed(final GroupKey groupKey) { - } return group; } @@ -536,7 +534,6 @@ public class GroupManager { unmodifiableUnSeenGroups.setComparator(sortBy.getGrpComparator(sortOrder)); }); } - } /** @@ -616,7 +613,6 @@ public class GroupManager { for (GroupKey gk : groupsForFile) { removeFromGroup(gk, fileId); - Set checkAnalyzed = checkAnalyzed(gk); } } } @@ -629,6 +625,8 @@ public class GroupManager { */ @Subscribe synchronized public void handleFileUpdate(Collection updatedFileIDs) { + Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.UPDATE); + Collection fileIDs = evt.getFileIDs(); /** * TODO: is there a way to optimize this to avoid quering to db * so much. the problem is that as a new files are analyzed they @@ -682,6 +680,51 @@ public class GroupManager { markGroupSeen(group, newSeen); }); groupMap.put(groupKey, group); + } + Platform.runLater(() -> { + if (analyzedGroups.contains(group) == false) { + analyzedGroups.add(group); + } + markGroupSeen(group, groupSeen); + }); + return group; + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); + } + } + + private void popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { + + if (Objects.nonNull(task) && (task.isCancelled())) { + /* if this method call is part of a ReGroupTask and that task is + * cancelled, no-op + * + * this allows us to stop if a regroup task has been cancelled (e.g. + * the user picked a different group by attribute, while the + * current task was still running) */ + } else { // no task or un-cancelled task + if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { + /* for attributes other than path we can't be sure a group is + * fully analyzed because we don't know all the files that + * will be a part of that group */ + + try { + Set fileIDs = getFileIDsInGroup(groupKey); + if (Objects.nonNull(fileIDs)) { + DrawableGroup group; + final boolean groupSeen = db.isGroupSeen(groupKey); + synchronized (groupMap) { + if (groupMap.containsKey(groupKey)) { + group = groupMap.get(groupKey); + group.setFiles(ObjectUtils.defaultIfNull(fileIDs, Collections.emptySet())); + } else { + + group = new DrawableGroup(groupKey, fileIDs, groupSeen); + group.seenProperty().addListener((observable, oldSeen, newSeen) -> { + markGroupSeen(group, newSeen); + }); + groupMap.put(groupKey, group); } } Platform.runLater(() -> { @@ -690,13 +733,11 @@ public class GroupManager { } markGroupSeen(group, groupSeen); }); - return group; } } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); } } - } return null; } @@ -762,7 +803,6 @@ public class GroupManager { updateProgress(p, vals.size()); groupProgress.progress("regrouping files by " + groupBy.attrName.toString() + " : " + val, p); popuplateIfAnalyzed(new GroupKey(groupBy, val), this); - Set checkAnalyzed = checkAnalyzed(groupKey); } updateProgress(1, 1); From 5432309c2f35c84980d163bf992aa9955630f331 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 13:51:37 -0400 Subject: [PATCH 162/198] rename method; add synchronization; remove singletonness from SummaryTablePane --- .../sleuthkit/autopsy/imagegallery/DrawableTagsManager.java | 4 ++-- .../autopsy/imagegallery/ImageGalleryController.java | 2 +- .../autopsy/imagegallery/actions/DeleteFollowUpTagAction.java | 2 +- .../autopsy/imagegallery/datamodel/CategoryManager.java | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 149c7fd888..7e0303fe4d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -78,7 +78,7 @@ public class DrawableTagsManager { } /** - * fire a CategoryChangeEvent with the given fileIDs + * fire a TagsChangeEvent with the given fileIDs * * @param fileIDs */ @@ -188,7 +188,7 @@ public class DrawableTagsManager { * had a chance to add that so, we fire these events and the tree * refreshes based on them. */ - static public void fireTagsChangedEvent() { + static public void refreshTagsInAutopsy() { IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 3bb7f83f97..1a5e254d98 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -367,7 +367,6 @@ public final class ImageGalleryController { tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); tagsManager.registerListener(groupManager); tagsManager.registerListener(categoryManager); - } else { reset(); } @@ -445,6 +444,7 @@ public final class ImageGalleryController { ModuleDataEvent oldValue = (ModuleDataEvent) evt.getOldValue(); if ("TagAction".equals(oldValue.getModuleName()) && oldValue.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { getTagsManager().fireChange(Collections.singleton(-1L)); + getCategoryManager().invalidateCaches(); } /* we could listen to DATA events and progressivly * update files, and get data from DataSource ingest diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 6a1a54c30d..bba6d5e4dc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -79,7 +79,7 @@ public class DeleteFollowUpTagAction extends Action { } } - DrawableTagsManager.fireTagsChangedEvent(); + DrawableTagsManager.refreshTagsInAutopsy(); //make sure rest of ui hears category change. groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 551db0e6c6..5e9b407c56 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -54,6 +54,7 @@ import org.sleuthkit.datamodel.TskCoreException; public class CategoryManager { private static final java.util.logging.Logger LOGGER = Logger.getLogger(CategoryManager.class.getName()); + private final ImageGalleryController controller; private final ImageGalleryController controller; From e126aee4cbbc2a1ea10e5d0e0bada3fb44069241 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 16:57:28 -0400 Subject: [PATCH 163/198] new Tag event system --- .../imagegallery/DrawableTagsManager.java | 148 +++++++++++------- .../imagegallery/ImageGalleryController.java | 28 +++- .../actions/DeleteFollowUpTagAction.java | 70 ++++----- .../imagegallery/datamodel/Category.java | 3 + .../datamodel/grouping/GroupManager.java | 1 - .../gui/drawableviews/DrawableTileBase.java | 8 + 6 files changed, 157 insertions(+), 101 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 7e0303fe4d..add7065742 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -45,6 +45,7 @@ public class DrawableTagsManager { private static final String FOLLOW_UP = "Follow Up"; + private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; /** Used to distribute {@link TagsChangeEvent}s */ @@ -64,26 +65,21 @@ public class DrawableTagsManager { * * @param autopsyTagsManager */ - public synchronized void setAutopsyTagsManager(TagsManager autopsyTagsManager) { - this.autopsyTagsManager = autopsyTagsManager; - clearFollowUpTagName(); + public void setAutopsyTagsManager(TagsManager autopsyTagsManager) { + synchronized (autopsyTagsManager) { + this.autopsyTagsManager = autopsyTagsManager; + clearFollowUpTagName(); + } } /** * Use when closing a case to make sure everything is re-initialized in the * next case. */ - public synchronized void clearFollowUpTagName() { - followUpTagName = null; - } - - /** - * fire a TagsChangeEvent with the given fileIDs - * - * @param fileIDs - */ - public final void fireChange(Collection fileIDs) { - tagsEventBus.post(new TagsChangeEvent(fileIDs)); + public void clearFollowUpTagName() { + synchronized (autopsyTagsManager) { + followUpTagName = null; + } } /** @@ -111,22 +107,26 @@ public class DrawableTagsManager { * * @throws TskCoreException */ - synchronized public TagName getFollowUpTagName() throws TskCoreException { - if (Objects.isNull(followUpTagName)) { - followUpTagName = getTagName(FOLLOW_UP); + public TagName getFollowUpTagName() throws TskCoreException { + synchronized (autopsyTagsManager) { + if (Objects.isNull(followUpTagName)) { + followUpTagName = getTagName(FOLLOW_UP); + } + return followUpTagName; } - return followUpTagName; } - synchronized public Collection getNonCategoryTagNames() { - try { - return autopsyTagsManager.getAllTagNames().stream() - .filter(Category::isCategoryTagName) - .collect(Collectors.toSet()); - } catch (TskCoreException | IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + public Collection getNonCategoryTagNames() { + synchronized (autopsyTagsManager) { + try { + return autopsyTagsManager.getAllTagNames().stream() + .filter(Category::isCategoryTagName) + .collect(Collectors.toSet()); + } catch (TskCoreException | IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + } + return Collections.emptySet(); } - return Collections.emptySet(); } /** @@ -139,29 +139,33 @@ public class DrawableTagsManager { * * @throws TskCoreException */ - public synchronized List getContentTagsByContent(Content content) throws TskCoreException { - return autopsyTagsManager.getContentTagsByContent(content); - } - - public synchronized TagName getTagName(String displayName) throws TskCoreException { - try { - for (TagName tn : autopsyTagsManager.getAllTagNames()) { - if (displayName.equals(tn.getDisplayName())) { - return tn; - } - } - try { - return autopsyTagsManager.addTagName(displayName); - } catch (TagsManager.TagNameAlreadyExistsException ex) { - throw new TskCoreException("tagame exists but wasn't found", ex); - } - } catch (IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); - throw new TskCoreException("Case was closed out from underneath", ex); + public List getContentTagsByContent(Content content) throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getContentTagsByContent(content); } } - public synchronized TagName getTagName(Category cat) { + public TagName getTagName(String displayName) throws TskCoreException { + synchronized (autopsyTagsManager) { + try { + for (TagName tn : autopsyTagsManager.getAllTagNames()) { + if (displayName.equals(tn.getDisplayName())) { + return tn; + } + } + try { + return autopsyTagsManager.addTagName(displayName); + } catch (TagsManager.TagNameAlreadyExistsException ex) { + throw new TskCoreException("tagame exists but wasn't found", ex); + } + } catch (IllegalStateException ex) { + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); + throw new TskCoreException("Case was closed out from underneath", ex); + } + } + } + + public TagName getTagName(Category cat) { try { return getTagName(cat.getDisplayName()); } catch (TskCoreException ex) { @@ -169,12 +173,18 @@ public class DrawableTagsManager { } } - synchronized public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { - autopsyTagsManager.addContentTag(file, tagName, comment); + public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { + ContentTag addContentTag; + synchronized (autopsyTagsManager) { + addContentTag = autopsyTagsManager.addContentTag(file, tagName, comment); + } + fireTagAdded(addContentTag); } - synchronized public List getContentTagsByTagName(TagName t) throws TskCoreException { - return autopsyTagsManager.getContentTagsByTagName(t); + public List getContentTagsByTagName(TagName t) throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getContentTagsByTagName(t); + } } /** @@ -189,15 +199,43 @@ public class DrawableTagsManager { * refreshes based on them. */ static public void refreshTagsInAutopsy() { - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS } - public synchronized List getAllTagNames() throws TskCoreException { - return autopsyTagsManager.getAllTagNames(); + public List getAllTagNames() throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getAllTagNames(); + } } - public synchronized List getTagNamesInUse() throws TskCoreException { - return autopsyTagsManager.getTagNamesInUse(); + public List getTagNamesInUse() throws TskCoreException { + synchronized (autopsyTagsManager) { + return autopsyTagsManager.getTagNamesInUse(); + } } + + public void fireTagAdded(ContentTag newTag) { + tagsEventBus.post(new TagsChangeEvent(Collections.singleton(newTag.getContent().getId()))); + } + + public void fireTagDeleted(ContentTag oldTag) { + tagsEventBus.post(new TagsChangeEvent(Collections.singleton(oldTag.getContent().getId()))); + } +// +// /** +// * fire a TagsChangeEvent with the given fileIDs +// * +// * @param fileIDs +// */ +// public final void fireChange(Collection fileIDs) { +// tagsEventBus.post(new TagsChangeEvent(fileIDs)); +// } + + public void deleteContentTag(ContentTag ct) throws TskCoreException { + synchronized (autopsyTagsManager) { + autopsyTagsManager.deleteContentTag(ct); + } + fireTagDeleted(ct); + } + } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 1a5e254d98..76f94e2a92 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -61,6 +61,7 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; @@ -70,11 +71,11 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; import org.sleuthkit.autopsy.imagegallery.gui.NoGroupsDialog; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase; @@ -441,11 +442,6 @@ public final class ImageGalleryController { case CONTENT_CHANGED: //TODO: do we need to do anything here? -jm case DATA_ADDED: - ModuleDataEvent oldValue = (ModuleDataEvent) evt.getOldValue(); - if ("TagAction".equals(oldValue.getModuleName()) && oldValue.getArtifactType() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE) { - getTagsManager().fireChange(Collections.singleton(-1L)); - getCategoryManager().invalidateCaches(); - } /* we could listen to DATA events and progressivly * update files, and get data from DataSource ingest * modules, but given that most modules don't post new @@ -496,6 +492,26 @@ public final class ImageGalleryController { setStale(true); } break; + case CONTENT_TAG_ADDED: + ContentTag newTag = (ContentTag) evt.getNewValue(); + if (Category.isCategoryTagName(newTag.getName())) { + new CategorizeAction(ImageGalleryController.this).addTag(newTag.getName(), ""); + } else { + getTagsManager().fireTagAdded(newTag); + } + break; + case CONTENT_TAG_DELETED: + ContentTag oldTag = (ContentTag) evt.getOldValue(); + final long fileID = oldTag.getContent().getId(); + if (getDatabase().isInDB(fileID)) { + if (Category.isCategoryTagName(oldTag.getName())) { + getCategoryManager().decrementCategoryCount(Category.fromTagName(oldTag.getName())); + getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); + } else { + getTagsManager().fireTagDeleted(oldTag); + } + } + break; case CONTENT_TAG_ADDED: final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt; if (getDatabase().isInDB((tagAddedEvent).getTag().getContent().getId())) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index bba6d5e4dc..98fdc316ad 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; +import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; @@ -43,49 +44,40 @@ public class DeleteFollowUpTagAction extends Action { private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTagAction.class.getName()); private final long fileID; - private final DrawableFile file; - private final ImageGalleryController controller; - public DeleteFollowUpTagAction(ImageGalleryController controller, DrawableFile file) { + public DeleteFollowUpTagAction(final ImageGalleryController controller, final DrawableFile file) { super("Delete Follow Up Tag"); - this.controller = controller; - this.file = file; this.fileID = file.getId(); setEventHandler((ActionEvent t) -> { - deleteTag(); + new SwingWorker() { + + @Override + protected Void doInBackground() throws Exception { + final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); + final GroupManager groupManager = controller.getGroupManager(); + final DrawableTagsManager tagsManager = controller.getTagsManager(); + + try { + final TagName followUpTagName = tagsManager.getFollowUpTagName(); + // remove file from old category group + groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); + + List contentTagsByContent = tagsManager.getContentTagsByContent(file); + for (ContentTag ct : contentTagsByContent) { + if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { + tagsManager.deleteContentTag(ct); + } + } + + DrawableTagsManager.refreshTagsInAutopsy(); + //make sure rest of ui hears category change. + groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); + } + return null; + } + }.execute(); }); } - - /** - * - * - * - */ - private void deleteTag() { - - final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); - final GroupManager groupManager = controller.getGroupManager(); - final DrawableTagsManager tagsManager = controller.getTagsManager(); - - try { - final TagName followUpTagName = tagsManager.getFollowUpTagName(); - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); - - List contentTagsByContent = sleuthKitCase.getContentTagsByContent(file); - for (ContentTag ct : contentTagsByContent) { - if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { - sleuthKitCase.deleteContentTag(ct); - } - } - - DrawableTagsManager.refreshTagsInAutopsy(); - - //make sure rest of ui hears category change. - groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); - } - } - } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index d2160e9196..4743e8b48e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -48,6 +48,9 @@ public enum Category { public static Category fromDisplayName(String displayName) { return nameMap.get(displayName); } + public static Category fromTagName(TagName tagName) { + return nameMap.get(tagName.getDisplayName()); + } public static boolean isCategoryName(String tName) { return nameMap.containsKey(tName); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index edbe0c1ff9..f47feeb804 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -691,7 +691,6 @@ public class GroupManager { } } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); - } } private void popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index f579a35aed..14b660410d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -349,6 +349,14 @@ public abstract class DrawableTileBase extends DrawableUIBase { return imageBorder; } + @Subscribe + @Override + synchronized public void handleTagsChanged(TagsChangeEvent evnt) { + if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { + updateFollowUpIcon(); + } + } + @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { From bc33284c68e55e3bb680b935975482e94c99fe21 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 18 Jun 2015 17:00:05 -0400 Subject: [PATCH 164/198] more granular synchronization in DrawableTagsManager --- .../imagegallery/DrawableTagsManager.java | 34 +++++++------------ 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index add7065742..13455d2fb1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -45,7 +45,7 @@ public class DrawableTagsManager { private static final String FOLLOW_UP = "Follow Up"; - private Object autopsyTagsManagerLock = new Object(); + final private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; /** Used to distribute {@link TagsChangeEvent}s */ @@ -66,7 +66,7 @@ public class DrawableTagsManager { * @param autopsyTagsManager */ public void setAutopsyTagsManager(TagsManager autopsyTagsManager) { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { this.autopsyTagsManager = autopsyTagsManager; clearFollowUpTagName(); } @@ -77,7 +77,7 @@ public class DrawableTagsManager { * next case. */ public void clearFollowUpTagName() { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { followUpTagName = null; } } @@ -108,7 +108,7 @@ public class DrawableTagsManager { * @throws TskCoreException */ public TagName getFollowUpTagName() throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { if (Objects.isNull(followUpTagName)) { followUpTagName = getTagName(FOLLOW_UP); } @@ -117,7 +117,7 @@ public class DrawableTagsManager { } public Collection getNonCategoryTagNames() { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { try { return autopsyTagsManager.getAllTagNames().stream() .filter(Category::isCategoryTagName) @@ -140,13 +140,13 @@ public class DrawableTagsManager { * @throws TskCoreException */ public List getContentTagsByContent(Content content) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getContentTagsByContent(content); } } public TagName getTagName(String displayName) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { try { for (TagName tn : autopsyTagsManager.getAllTagNames()) { if (displayName.equals(tn.getDisplayName())) { @@ -175,14 +175,14 @@ public class DrawableTagsManager { public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { ContentTag addContentTag; - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { addContentTag = autopsyTagsManager.addContentTag(file, tagName, comment); } fireTagAdded(addContentTag); } public List getContentTagsByTagName(TagName t) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getContentTagsByTagName(t); } } @@ -203,13 +203,13 @@ public class DrawableTagsManager { } public List getAllTagNames() throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getAllTagNames(); } } public List getTagNamesInUse() throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getTagNamesInUse(); } } @@ -221,21 +221,11 @@ public class DrawableTagsManager { public void fireTagDeleted(ContentTag oldTag) { tagsEventBus.post(new TagsChangeEvent(Collections.singleton(oldTag.getContent().getId()))); } -// -// /** -// * fire a TagsChangeEvent with the given fileIDs -// * -// * @param fileIDs -// */ -// public final void fireChange(Collection fileIDs) { -// tagsEventBus.post(new TagsChangeEvent(fileIDs)); -// } public void deleteContentTag(ContentTag ct) throws TskCoreException { - synchronized (autopsyTagsManager) { + synchronized (autopsyTagsManagerLock) { autopsyTagsManager.deleteContentTag(ct); } fireTagDeleted(ct); } - } From 39a5b142be258c25f41f5eb8d42a5d1ea7847205 Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 10:22:18 -0400 Subject: [PATCH 165/198] Tag Events - created new Case.Event enum values for BlackBoard/Content tags added/deleted - created new PropertyChangeEvent subclasses for BlackBoard/Content tags added/deleted - replaced ModuleDataEvent hack with new Tag Events - removed [in] from javadocs, other minor cleanup --- .../sleuthkit/autopsy/casemodule/Case.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 30216d3140..e7086cf3b0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -600,6 +600,59 @@ public class Case implements SleuthkitCase.ErrorObserver { } } + /** + * Notifies the UI that a new ContentTag has been added. + * + * @param newTag new ContentTag added + */ + public void notifyContentTagAdded(ContentTag newTag) { + notify(new ContentTagAddedEvent(newTag)); + } + + /** + * Notifies the UI that a ContentTag has been deleted. + * + * @param deletedTag ContentTag deleted + */ + public void notifyContentTagDeleted(ContentTag deletedTag) { + notify(new ContentTagDeletedEvent(deletedTag)); + } + + /** + * Notifies the UI that a new BlackboardArtifactTag has been added. + * + * @param newTag new BlackboardArtifactTag added + */ + public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) { + notify(new BlackBoardArtifactTagAddedEvent(newTag)); + } + + /** + * Notifies the UI that a BlackboardArtifactTag has been. + * + * @param deletedTag BlackboardArtifactTag deleted + */ + public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { + notify(new BlackBoardArtifactTagDeletedEvent(deletedTag)); + } + + /** + * Notifies the UI about a Case level event. + * + * @param propertyChangeEvent the event to distribute + */ + private void notify(final PropertyChangeEvent propertyChangeEvent) { + try { + pcs.firePropertyChange(propertyChangeEvent); + } catch (Exception e) { + logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS + MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), + NbBundle.getMessage(this.getClass(), + "Case.changeCase.errListenToCaseUpdates.msg"), + MessageNotifyUtil.MessageType.ERROR); + } + } + /** * @return The Services object for this case. */ From 1665dc11b913461a94f8c760d42780a60d27ab18 Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 13:53:53 -0400 Subject: [PATCH 166/198] use new Autopsy Tag events, don't fire extra events from ig, but listen to events from autopsy --- .../casemodule/services/TagsManager.java | 1 - .../imagegallery/DrawableTagsManager.java | 82 ++++++++----------- .../imagegallery/ImageGalleryController.java | 24 ++---- .../autopsy/imagegallery/TagsChangeEvent.java | 41 ---------- .../actions/AddDrawableTagAction.java | 1 - .../actions/DeleteFollowUpTagAction.java | 7 +- .../imagegallery/datamodel/Category.java | 9 -- .../datamodel/CategoryManager.java | 1 + .../datamodel/grouping/GroupManager.java | 29 +++++-- .../gui/drawableviews/DrawableTileBase.java | 13 ++- .../gui/drawableviews/MetaDataPane.java | 9 +- 11 files changed, 80 insertions(+), 137 deletions(-) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index f94976b572..d5ec4fc7c2 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -253,7 +253,6 @@ public class TagsManager implements Closeable { } catch (IllegalArgumentException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.addContentTag.noCaseWarning")); } - return newContentTag; } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java index 13455d2fb1..0bbc4b9d5a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java @@ -27,11 +27,11 @@ import java.util.logging.Level; import java.util.stream.Collectors; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.ingest.IngestServices; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -59,6 +59,32 @@ public class DrawableTagsManager { } + /** + * register an object to receive CategoryChangeEvents + * + * @param listner + */ + public void registerListener(Object listner) { + tagsEventBus.register(listner); + } + + /** + * unregister an object from receiving CategoryChangeEvents + * + * @param listener + */ + public void unregisterListener(Object listener) { + tagsEventBus.unregister(listener); + } + + public void fireTagAddedEvent(ContentTagAddedEvent event) { + tagsEventBus.post(event); + } + + public void fireTagDeletedEvent(ContentTagDeletedEvent event) { + tagsEventBus.post(event); + } + /** * assign a new TagsManager to back this one, ie when the current case * changes @@ -82,24 +108,6 @@ public class DrawableTagsManager { } } - /** - * register an object to receive CategoryChangeEvents - * - * @param listner - */ - public void registerListener(Object listner) { - tagsEventBus.register(listner); - } - - /** - * unregister an object from receiving CategoryChangeEvents - * - * @param listener - */ - public void unregisterListener(Object listener) { - tagsEventBus.unregister(listener); - } - /** * get the (cached) follow up TagName * @@ -120,7 +128,7 @@ public class DrawableTagsManager { synchronized (autopsyTagsManagerLock) { try { return autopsyTagsManager.getAllTagNames().stream() - .filter(Category::isCategoryTagName) + .filter(CategoryManager::isCategoryTagName) .collect(Collectors.toSet()); } catch (TskCoreException | IllegalStateException ex) { Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); @@ -173,12 +181,10 @@ public class DrawableTagsManager { } } - public void addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { - ContentTag addContentTag; + public ContentTag addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { synchronized (autopsyTagsManagerLock) { - addContentTag = autopsyTagsManager.addContentTag(file, tagName, comment); + return autopsyTagsManager.addContentTag(file, tagName, comment); } - fireTagAdded(addContentTag); } public List getContentTagsByTagName(TagName t) throws TskCoreException { @@ -187,21 +193,6 @@ public class DrawableTagsManager { } } - /** - * Fire the ModuleDataEvent that we use as a place holder for a real Tag - * Event. This is used to refresh the autopsy tag tree and the ui in - * ImageGallery - * - * - * Note: this is a hack. In an ideal world, TagsManager would fire - * events so that the directory tree would refresh. But, we haven't - * had a chance to add that so, we fire these events and the tree - * refreshes based on them. - */ - static public void refreshTagsInAutopsy() { - IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("TagAction", BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)); //NON-NLS - } - public List getAllTagNames() throws TskCoreException { synchronized (autopsyTagsManagerLock) { return autopsyTagsManager.getAllTagNames(); @@ -214,18 +205,9 @@ public class DrawableTagsManager { } } - public void fireTagAdded(ContentTag newTag) { - tagsEventBus.post(new TagsChangeEvent(Collections.singleton(newTag.getContent().getId()))); - } - - public void fireTagDeleted(ContentTag oldTag) { - tagsEventBus.post(new TagsChangeEvent(Collections.singleton(oldTag.getContent().getId()))); - } - public void deleteContentTag(ContentTag ct) throws TskCoreException { synchronized (autopsyTagsManagerLock) { autopsyTagsManager.deleteContentTag(ct); } - fireTagDeleted(ct); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 76f94e2a92..11646338dc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.imagegallery; import java.beans.PropertyChangeEvent; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.BlockingQueue; @@ -61,7 +60,6 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; @@ -75,7 +73,6 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.FileSystem; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase; @@ -368,6 +365,7 @@ public final class ImageGalleryController { tagsManager.setAutopsyTagsManager(theNewCase.getServices().getTagsManager()); tagsManager.registerListener(groupManager); tagsManager.registerListener(categoryManager); + } else { reset(); } @@ -493,23 +491,15 @@ public final class ImageGalleryController { } break; case CONTENT_TAG_ADDED: - ContentTag newTag = (ContentTag) evt.getNewValue(); - if (Category.isCategoryTagName(newTag.getName())) { - new CategorizeAction(ImageGalleryController.this).addTag(newTag.getName(), ""); - } else { - getTagsManager().fireTagAdded(newTag); + final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt; + if (getDatabase().isInDB((tagAddedEvent).getAddedTag().getContent().getId())) { + getTagsManager().fireTagAddedEvent(tagAddedEvent); } break; case CONTENT_TAG_DELETED: - ContentTag oldTag = (ContentTag) evt.getOldValue(); - final long fileID = oldTag.getContent().getId(); - if (getDatabase().isInDB(fileID)) { - if (Category.isCategoryTagName(oldTag.getName())) { - getCategoryManager().decrementCategoryCount(Category.fromTagName(oldTag.getName())); - getGroupManager().handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); - } else { - getTagsManager().fireTagDeleted(oldTag); - } + final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) evt; + if (getDatabase().isInDB((tagDeletedEvent).getDeletedTag().getContent().getId())) { + getTagsManager().fireTagDeletedEvent(tagDeletedEvent); } break; case CONTENT_TAG_ADDED: diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java deleted file mode 100644 index 0647a18456..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/TagsChangeEvent.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery; - -import java.util.Collection; -import java.util.Collections; -import javax.annotation.concurrent.Immutable; - -/** - * - */ -@Immutable -public class TagsChangeEvent { - - private final Collection fileIDs; - - public Collection getFileIDs() { - return Collections.unmodifiableCollection(fileIDs); - } - - public TagsChangeEvent(Collection fileIDs) { - this.fileIDs = fileIDs; - } - -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index b3a45b3030..3c115d9134 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -27,7 +27,6 @@ import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.openide.util.Utilities; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 98fdc316ad..aab8a9c827 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; -import java.util.Collections; import java.util.List; import java.util.logging.Level; import javafx.event.ActionEvent; @@ -26,14 +25,12 @@ import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; -import org.sleuthkit.autopsy.imagegallery.FileUpdateEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -53,7 +50,6 @@ public class DeleteFollowUpTagAction extends Action { @Override protected Void doInBackground() throws Exception { - final SleuthkitCase sleuthKitCase = controller.getSleuthKitCase(); final GroupManager groupManager = controller.getGroupManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); @@ -69,9 +65,8 @@ public class DeleteFollowUpTagAction extends Action { } } - DrawableTagsManager.refreshTagsInAutopsy(); //make sure rest of ui hears category change. - groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); +// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 4743e8b48e..3fd1a6c92c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -48,17 +48,8 @@ public enum Category { public static Category fromDisplayName(String displayName) { return nameMap.get(displayName); } - public static Category fromTagName(TagName tagName) { - return nameMap.get(tagName.getDisplayName()); - } - public static boolean isCategoryName(String tName) { return nameMap.containsKey(tName); - } - - public static boolean isNotCategoryTagName(TagName tName) { - return isNotCategoryName(tName.getDisplayName()); - } public static boolean isNotCategoryName(String tName) { return nameMap.containsKey(tName) == false; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 5e9b407c56..1f0d490857 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -34,6 +34,7 @@ import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index f47feeb804..e0c865e86e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -64,7 +64,6 @@ import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; -import org.sleuthkit.autopsy.imagegallery.TagsChangeEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -296,6 +295,10 @@ public class GroupManager { } }); } + } else { //group == null + // It may be that this was the last unanalyzed file in the group, so test + // whether the group is now fully analyzed. + popuplateIfAnalyzed(groupKey, null); } } else { //group == null // It may be that this was the last unanalyzed file in the group, so test @@ -546,11 +549,21 @@ public class GroupManager { } @Subscribe - public void handleAutopsyTagChange(TagsChangeEvent evt) { - if (groupBy == DrawableAttribute.TAGS - && evt.getFileIDs().size() == 1 - && evt.getFileIDs().contains(-1L)) { - regroup(groupBy, sortBy, sortOrder, Boolean.TRUE); + public void handleTagAdded(ContentTagAddedEvent evt) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + final long fileID = evt.getAddedTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); + + } + + private void addFileToGroup(DrawableGroup g, final GroupKey groupKey, final long fileID) { + if (g == null) { + //if there wasn't already a group check if there should be one now + popuplateIfAnalyzed(groupKey, null); + } else { + //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. + g.addFile(fileID); } } @@ -693,7 +706,7 @@ public class GroupManager { LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); } - private void popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { + private DrawableGroup popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { if (Objects.nonNull(task) && (task.isCancelled())) { /* if this method call is part of a ReGroupTask and that task is @@ -702,6 +715,7 @@ public class GroupManager { * this allows us to stop if a regroup task has been cancelled (e.g. * the user picked a different group by attribute, while the * current task was still running) */ + } else { // no task or un-cancelled task if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { /* for attributes other than path we can't be sure a group is @@ -732,6 +746,7 @@ public class GroupManager { } markGroupSeen(group, groupSeen); }); + return group; } } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index 14b660410d..6bfbc8a70a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -351,10 +351,15 @@ public abstract class DrawableTileBase extends DrawableUIBase { @Subscribe @Override - synchronized public void handleTagsChanged(TagsChangeEvent evnt) { - if (fileID != null && (evnt.getFileIDs().contains(fileID) || evnt.getFileIDs().contains(-1L))) { - updateFollowUpIcon(); - } + public void handleTagAdded(ContentTagAddedEvent evt) { + + updateFollowUpIcon(); + } + + @Subscribe + @Override + public void handleTagDeleted(ContentTagDeletedEvent evt) { + updateFollowUpIcon(); } @Subscribe diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index 45399e2f79..e9109ab121 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -207,7 +207,6 @@ public class MetaDataPane extends DrawableUIBase { handleTagEvent(evt, this::updateUI); } - @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { handleTagEvent(evt, this::updateUI); @@ -225,4 +224,12 @@ public class MetaDataPane extends DrawableUIBase { } }); } + + @Override + public void handleTagDeleted(ContentTagDeletedEvent evt) { + if (getFile() != null && evt.getDeletedTag().getContent().getId() == getFileID()) { + updateUI(); + } + } + } From 1f1d59d76f49c8d8091d890750a435f7b8d555ff Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 19 Jun 2015 17:20:35 -0400 Subject: [PATCH 167/198] remove uneeded notification code; let event handlers do it all. optionalize DrawableView --- .../actions/CategorizeAction.java | 13 +++- .../actions/DeleteFollowUpTagAction.java | 11 +--- .../datamodel/CategoryManager.java | 2 +- .../datamodel/grouping/GroupManager.java | 12 ++-- .../gui/drawableviews/DrawableTileBase.java | 66 +++++++++++++++++-- .../gui/drawableviews/DrawableView.java | 1 + .../gui/drawableviews/MetaDataPane.java | 41 ++++++++++-- .../gui/drawableviews/SlideShowView.java | 2 +- 8 files changed, 119 insertions(+), 29 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 24e59dda65..3f6a918524 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; @@ -37,8 +36,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; -import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -154,6 +151,16 @@ public class CategorizeAction extends AddTagAction { .collect(Collectors.toList()).isEmpty()) { tagsManager.addContentTag(file, tagName, comment); } + } else { + tagsManager.getContentTagsByContent(file).stream() + .filter(tag -> CategoryManager.isCategoryTagName(tag.getName())) + .forEach((ct) -> { + try { + tagsManager.deleteContentTag(ct); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error removing old categories result", ex); + } + }); } } catch (TskCoreException ex) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index aab8a9c827..74082fcd1c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -26,10 +26,7 @@ import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupKey; -import org.sleuthkit.autopsy.imagegallery.grouping.GroupManager; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -50,23 +47,17 @@ public class DeleteFollowUpTagAction extends Action { @Override protected Void doInBackground() throws Exception { - final GroupManager groupManager = controller.getGroupManager(); final DrawableTagsManager tagsManager = controller.getTagsManager(); try { final TagName followUpTagName = tagsManager.getFollowUpTagName(); - // remove file from old category group - groupManager.removeFromGroup(new GroupKey(DrawableAttribute.TAGS, followUpTagName), fileID); - + List contentTagsByContent = tagsManager.getContentTagsByContent(file); for (ContentTag ct : contentTagsByContent) { if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { tagsManager.deleteContentTag(ct); } } - - //make sure rest of ui hears category change. -// groupManager.handleFileUpdate(FileUpdateEvent.newUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to delete follow up tag.", ex); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 1f0d490857..e685c118f5 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -262,7 +262,7 @@ public class CategoryManager { fireChange(Collections.singleton(addedTag.getContent().getId()), newCat); } } - + @Subscribe @Subscribe public void handleTagDeleted(ContentTagDeletedEvent event) { ContentTag deleted = event.getTag(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index e0c865e86e..ed1b5b3706 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -293,6 +293,7 @@ public class GroupManager { if (unSeenGroups.contains(group)) { unSeenGroups.remove(group); } + } }); } } else { //group == null @@ -550,10 +551,12 @@ public class GroupManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); - final long fileID = evt.getAddedTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); + if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { + final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + final long fileID = evt.getAddedTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); + } } @@ -615,6 +618,7 @@ public class GroupManager { final long fileID = evt.getTag().getContent().getId(); DrawableGroup g = removeFromGroup(groupKey, fileID); } + } } @Subscribe diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index 6bfbc8a70a..c9bfe35b29 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -23,6 +23,8 @@ import com.google.common.eventbus.Subscribe; import java.util.ArrayList; import java.util.Collection; import java.util.Optional; +import static java.util.Objects.nonNull; +import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; import javafx.beans.Observable; @@ -126,6 +128,30 @@ public abstract class DrawableTileBase extends DrawableUIBase { @FXML protected BorderPane imageBorder; + + @Override + public Optional getFileID() { + return fileIDOpt; + } + + @Override + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + try { + fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); + } catch (TskCoreException ex) { + Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); + fileOpt = Optional.empty(); + } + return fileOpt; + } + } else { + return Optional.empty(); + } + } /** * the groupPane this {@link DrawableTileBase} is embedded in */ @@ -258,7 +284,7 @@ public abstract class DrawableTileBase extends DrawableUIBase { try { globalSelectionModel.clearAndSelect(file.getId()); new AddDrawableTagAction(getController()).addTag(getController().getTagsManager().getFollowUpTagName(), ""); - new AddDrawableTagAction(controller).addTag(followUpTagName, ""); + new AddDrawableTagAction(controller).addTag(followUpTagName, ""); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); } @@ -281,10 +307,12 @@ public abstract class DrawableTileBase extends DrawableUIBase { } } else { return false; + if (Objects.equals(newFileID, fileIDOpt.get()) == false) { + setFileHelper(newFileID); } } - @Override + private void setFileHelper(final Long newFileID) { protected void setFileHelper(final Long newFileID) { setFileIDOpt(Optional.ofNullable(newFileID)); disposeContent(); @@ -352,14 +380,44 @@ public abstract class DrawableTileBase extends DrawableUIBase { @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { + fileIDOpt.ifPresent(fileID -> { + try { + if (fileID == evt.getAddedTag().getContent().getId() + && evt.getAddedTag().getName() == getController().getTagsManager().getFollowUpTagName()) { - updateFollowUpIcon(); + Platform.runLater(() -> { + followUpImageView.setImage(followUpIcon); + followUpToggle.setSelected(true); + }); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + } + }); } @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - updateFollowUpIcon(); + + fileIDOpt.ifPresent(fileID -> { + try { + if (fileID == evt.getDeletedTag().getContent().getId() + && evt.getDeletedTag().getName() == controller.getTagsManager().getFollowUpTagName()) { + updateFollowUpIcon(); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + } + }); + } + + private void updateFollowUpIcon() { + boolean hasFollowUp = hasFollowUp(); + Platform.runLater(() -> { + followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray); + followUpToggle.setSelected(hasFollowUp); + }); } @Subscribe diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java index 67647334d6..37737675e5 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java @@ -2,6 +2,7 @@ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.eventbus.Subscribe; import java.util.Optional; +import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; import javafx.scene.layout.Border; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index e9109ab121..232cfe8a6f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -24,6 +24,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Objects; import java.util.Optional; +import java.util.Optional; import java.util.stream.Collectors; import javafx.application.Platform; import javafx.beans.property.SimpleObjectProperty; @@ -83,7 +84,6 @@ public class MetaDataPane extends DrawableUIBase { public MetaDataPane(ImageGalleryController controller) { super(controller); - FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MetaDataPane.fxml")); fxmlLoader.setRoot(this); fxmlLoader.setController(this); @@ -93,8 +93,6 @@ public class MetaDataPane extends DrawableUIBase { } catch (IOException exception) { throw new RuntimeException(exception); } - } - @FXML @SuppressWarnings("unchecked") void initialize() { @@ -155,10 +153,35 @@ public class MetaDataPane extends DrawableUIBase { }); } + volatile private Optional> fileOpt = Optional.empty(); + + volatile private Optional fileIDOpt = Optional.empty(); + @Override protected synchronized void setFileHelper(Long newFileID) { setFileIDOpt(Optional.ofNullable(newFileID)); if (newFileID == null) { + + @Override + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + return fileOpt; + if (Objects.equals(newFileID, fileIDOpt.get()) == false) { + setFileHelper(newFileID); + } + } else { + if (nonNull(newFileID)) { + setFileHelper(newFileID); + } + } + setFileHelper(newFileID); + } + private void setFileHelper(Long newFileID) { + fileIDOpt = Optional.of(newFileID); + if (newFileID == null) { Platform.runLater(() -> { imageView.setImage(null); tableView.getItems().clear(); @@ -183,6 +206,7 @@ public class MetaDataPane extends DrawableUIBase { updateCategory(); }); + } @Override @@ -227,9 +251,14 @@ public class MetaDataPane extends DrawableUIBase { @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - if (getFile() != null && evt.getDeletedTag().getContent().getId() == getFileID()) { - updateUI(); - } + handleTagChanged(evt.getDeletedTag().getContent().getId()); } + private void handleTagChanged(Long tagFileID) { + getFileID().ifPresent(fileID -> { + if (Objects.equals(tagFileID, fileID)) { + updateUI(); + } + }); + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java index 91fbec5a24..ba60735da9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java @@ -50,7 +50,6 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; @@ -319,6 +318,7 @@ public class SlideShowView extends DrawableTileBase { public Category updateCategory() { if (getFile().isPresent()) { final Category category = super.updateCategory(); + final Border border1 = hasHashHit() && (category == Category.ZERO) ToggleButton toggleForCategory = getToggleForCategory(category); Platform.runLater(() -> { toggleForCategory.setSelected(true); From da0554de6a392ff7616e8e4a40a35565ad207034 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 13:33:07 -0400 Subject: [PATCH 168/198] fix bugs updating tags/categpries in slideshowview and metadata pane make new abstract base calss DrawableUIBase and move fileid and file object access to it. --- .../actions/DeleteFollowUpTagAction.java | 2 - .../imagegallery/gui/DrawableTileBase.java | 391 ++++++++++++++++++ .../imagegallery/gui/DrawableUIBase.java | 97 +++++ .../gui/drawableviews/MetaDataPane.java | 32 +- .../gui/drawableviews/SlideShowView.java | 2 +- 5 files changed, 490 insertions(+), 34 deletions(-) create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java create mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 74082fcd1c..934a3fb258 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -37,11 +37,9 @@ import org.sleuthkit.datamodel.TskCoreException; public class DeleteFollowUpTagAction extends Action { private static final Logger LOGGER = Logger.getLogger(DeleteFollowUpTagAction.class.getName()); - private final long fileID; public DeleteFollowUpTagAction(final ImageGalleryController controller, final DrawableFile file) { super("Delete Follow Up Tag"); - this.fileID = file.getId(); setEventHandler((ActionEvent t) -> { new SwingWorker() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java new file mode 100644 index 0000000000..80c73b1ae9 --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java @@ -0,0 +1,391 @@ + +/* + * Autopsy Forensic Browser + * + * Copyright 2013-15 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery.gui; + +import com.google.common.eventbus.Subscribe; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Optional; +import java.util.logging.Level; +import javafx.application.Platform; +import javafx.beans.Observable; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.fxml.FXML; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.Label; +import javafx.scene.control.MenuItem; +import javafx.scene.control.ToggleButton; +import javafx.scene.control.Tooltip; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.Border; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.BorderStroke; +import javafx.scene.layout.BorderStrokeStyle; +import javafx.scene.layout.BorderWidths; +import javafx.scene.layout.CornerRadii; +import javafx.scene.layout.Region; +import javafx.scene.paint.Color; +import javax.swing.Action; +import javax.swing.SwingUtilities; +import org.openide.util.Lookup; +import org.openide.util.actions.Presenter; +import org.openide.windows.TopComponent; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ThreadConfined; +import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; +import org.sleuthkit.autopsy.datamodel.FileNode; +import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; +import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.events.ContentTagAddedEvent; +import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; +import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; +import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; +import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; +import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * An abstract base class for {@link DrawableTile} and {@link SlideShowView}, + * since they share a similar node tree and many behaviors, other implementers + * of {@link DrawableView}s should implement the interface directly + * + */ +public abstract class DrawableTileBase extends DrawableUIBase { + + private static final Logger LOGGER = Logger.getLogger(DrawableTileBase.class.getName()); + + private static final Border UNSELECTED_BORDER = new Border(new BorderStroke(Color.GRAY, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3))); + + private static final Border SELECTED_BORDER = new Border(new BorderStroke(Color.BLUE, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3))); + + //TODO: do this in CSS? -jm + protected static final Image videoIcon = new Image("org/sleuthkit/autopsy/imagegallery/images/video-file.png"); + protected static final Image hashHitIcon = new Image("org/sleuthkit/autopsy/imagegallery/images/hashset_hits.png"); + protected static final Image followUpIcon = new Image("org/sleuthkit/autopsy/imagegallery/images/flag_red.png"); + protected static final Image followUpGray = new Image("org/sleuthkit/autopsy/imagegallery/images/flag_gray.png"); + + protected static final FileIDSelectionModel globalSelectionModel = FileIDSelectionModel.getInstance(); + private static ContextMenu contextMenu; + + /** + * displays the icon representing video files + */ + @FXML + protected ImageView fileTypeImageView; + + /** + * displays the icon representing hash hits + */ + @FXML + protected ImageView hashHitImageView; + + /** + * displays the icon representing follow up tag + */ + @FXML + protected ImageView followUpImageView; + + @FXML + protected ToggleButton followUpToggle; + + /** + * the label that shows the name of the represented file + */ + @FXML + protected Label nameLabel; + + @FXML + protected BorderPane imageBorder; + + /** + * the groupPane this {@link DrawableTileBase} is embedded in + */ + final private GroupPane groupPane; + volatile private boolean registered = false; + + protected DrawableTileBase(GroupPane groupPane) { + super(groupPane.getController()); + + this.groupPane = groupPane; + globalSelectionModel.getSelected().addListener((Observable observable) -> { + updateSelectionState(); + }); + + //set up mouse listener + //TODO: split this between DrawableTile and SingleDrawableViewBase + addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler() { + + @Override + public void handle(MouseEvent t) { + getFile().ifPresent(file -> { + final long fileID = file.getId(); + switch (t.getButton()) { + case PRIMARY: + if (t.getClickCount() == 1) { + if (t.isControlDown()) { + + globalSelectionModel.toggleSelection(fileID); + } else { + groupPane.makeSelection(t.isShiftDown(), fileID); + } + } else if (t.getClickCount() > 1) { + groupPane.activateSlideShowViewer(fileID); + } + break; + case SECONDARY: + if (t.getClickCount() == 1) { + if (globalSelectionModel.isSelected(fileID) == false) { + groupPane.makeSelection(false, fileID); + } + } + if (contextMenu != null) { + contextMenu.hide(); + } + final ContextMenu groupContextMenu = groupPane.getContextMenu(); + if (groupContextMenu != null) { + groupContextMenu.hide(); + } + contextMenu = buildContextMenu(file); + contextMenu.show(DrawableTileBase.this, t.getScreenX(), t.getScreenY()); + break; + } + }); + + t.consume(); + } + + private ContextMenu buildContextMenu(DrawableFile file) { + final ArrayList menuItems = new ArrayList<>(); + + menuItems.add(new CategorizeAction(getController()).getPopupMenu()); + + menuItems.add(new AddDrawableTagAction(getController()).getPopupMenu()); + + final MenuItem extractMenuItem = new MenuItem("Extract File(s)"); + extractMenuItem.setOnAction((ActionEvent t) -> { + SwingUtilities.invokeLater(() -> { + TopComponent etc = WindowManager.getDefault().findTopComponent(ImageGalleryTopComponent.PREFERRED_ID); + ExtractAction.getInstance().actionPerformed(new java.awt.event.ActionEvent(etc, 0, null)); + }); + }); + menuItems.add(extractMenuItem); + + MenuItem contentViewer = new MenuItem("Show Content Viewer"); + contentViewer.setOnAction((ActionEvent t) -> { + SwingUtilities.invokeLater(() -> { + new NewWindowViewAction("Show Content Viewer", new FileNode(file.getAbstractFile())).actionPerformed(null); + }); + }); + menuItems.add(contentViewer); + + MenuItem externalViewer = new MenuItem("Open in External Viewer"); + final ExternalViewerAction externalViewerAction = new ExternalViewerAction("Open in External Viewer", new FileNode(file.getAbstractFile())); + + externalViewer.setDisable(externalViewerAction.isEnabled() == false); + externalViewer.setOnAction((ActionEvent t) -> { + SwingUtilities.invokeLater(() -> { + externalViewerAction.actionPerformed(null); + }); + }); + menuItems.add(externalViewer); + + Collection menuProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class); + + for (ContextMenuActionsProvider provider : menuProviders) { + for (final Action act : provider.getActions()) { + if (act instanceof Presenter.Popup) { + Presenter.Popup aact = (Presenter.Popup) act; + menuItems.add(SwingMenuItemAdapter.create(aact.getPopupPresenter())); + } + } + } + + ContextMenu contextMenu = new ContextMenu(menuItems.toArray(new MenuItem[]{})); + contextMenu.setAutoHide(true); + return contextMenu; + } + }); + } + + GroupPane getGroupPane() { + return groupPane; + } + + @ThreadConfined(type = ThreadType.UI) + protected abstract void clearContent(); + + protected abstract void disposeContent(); + + protected abstract Runnable getContentUpdateRunnable(); + + protected abstract String getTextForLabel(); + + protected void initialize() { + followUpToggle.setOnAction((ActionEvent event) -> { + getFile().ifPresent(file -> { + if (followUpToggle.isSelected() == true) { + try { + globalSelectionModel.clearAndSelect(file.getId()); + new AddDrawableTagAction(getController()).addTag(getController().getTagsManager().getFollowUpTagName(), ""); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); + } + } else { + new DeleteFollowUpTagAction(getController(), file).handle(event); + } + }); + }); + } + + protected boolean hasFollowUp() { + if (getFileID().isPresent()) { + try { + TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); + return DrawableAttribute.TAGS.getValue(getFile().get()).stream() + .anyMatch(followUpTagName::equals); + } catch (TskCoreException ex) { + LOGGER.log(Level.WARNING, "failed to get follow up tag name ", ex); + return true; + } + } else { + return false; + } + } + + @Override + protected void setFileHelper(final Long newFileID) { + setFileIDOpt(Optional.ofNullable(newFileID)); + disposeContent(); + + if (getFileID().isPresent() == false || Case.isCaseOpen() == false) { + if (registered == true) { + getController().getCategoryManager().unregisterListener(this); + getController().getTagsManager().unregisterListener(this); + registered = false; + } + setFileOpt(Optional.empty()); + Platform.runLater(() -> { + clearContent(); + }); + } else { + if (registered == false) { + getController().getCategoryManager().registerListener(this); + getController().getTagsManager().registerListener(this); + registered = true; + } + setFileOpt(Optional.empty()); + + updateSelectionState(); + updateCategory(); + updateFollowUpIcon(); + updateUI(); + Platform.runLater(getContentUpdateRunnable()); + } + } + + private void updateUI() { + getFile().ifPresent(file -> { + final boolean isVideo = file.isVideo(); + final boolean hasHashSetHits = hasHashHit(); + final String text = getTextForLabel(); + + Platform.runLater(() -> { + fileTypeImageView.setImage(isVideo ? videoIcon : null); + hashHitImageView.setImage(hasHashSetHits ? hashHitIcon : null); + nameLabel.setText(text); + nameLabel.setTooltip(new Tooltip(text)); + }); + }); + + } + + /** + * update the visual representation of the selection state of this + * DrawableView + */ + protected void updateSelectionState() { + getFile().ifPresent(file -> { + final boolean selected = globalSelectionModel.isSelected(file.getId()); + Platform.runLater(() -> { + setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER); + }); + }); + } + + @Override + public Region getCategoryBorderRegion() { + return imageBorder; + } + + @Subscribe + @Override + public void handleTagAdded(ContentTagAddedEvent evt) { + getFileID().ifPresent(fileID -> { + try { + if (fileID == evt.getAddedTag().getContent().getId() + && evt.getAddedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { + + Platform.runLater(() -> { + followUpImageView.setImage(followUpIcon); + followUpToggle.setSelected(true); + }); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + } + }); + } + + @Subscribe + @Override + public void handleTagDeleted(ContentTagDeletedEvent evt) { + + getFileID().ifPresent(fileID -> { + try { + if (fileID == evt.getDeletedTag().getContent().getId() + && evt.getDeletedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { + updateFollowUpIcon(); + } + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + } + }); + } + + private void updateFollowUpIcon() { + boolean hasFollowUp = hasFollowUp(); + Platform.runLater(() -> { + followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray); + followUpToggle.setSelected(hasFollowUp); + }); + } +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java new file mode 100644 index 0000000000..ec794eabae --- /dev/null +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java @@ -0,0 +1,97 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2015 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.imagegallery.gui; + +import java.util.Objects; +import static java.util.Objects.nonNull; +import java.util.Optional; +import java.util.logging.Level; +import javafx.scene.layout.AnchorPane; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * + */ +abstract public class DrawableUIBase extends AnchorPane implements DrawableView { + + private final ImageGalleryController controller; + + volatile private Optional> fileOpt = Optional.empty(); + + volatile private Optional fileIDOpt = Optional.empty(); + + public DrawableUIBase(ImageGalleryController controller) { + this.controller = controller; + } + + @Override + public ImageGalleryController getController() { + return controller; + } + + @Override + public Optional getFileID() { + return fileIDOpt; + } + + void setFileIDOpt(Optional fileIDOpt) { + this.fileIDOpt = fileIDOpt; + } + + void setFileOpt(Optional> fileOpt) { + this.fileOpt = fileOpt; + } + + @Override + public Optional> getFile() { + if (fileIDOpt.isPresent()) { + if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { + return fileOpt; + } else { + try { + fileOpt = Optional.of(getController().getFileFromId(fileIDOpt.get())); + } catch (TskCoreException ex) { + Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); + fileOpt = Optional.empty(); + } + return fileOpt; + } + } else { + return Optional.empty(); + } + } + + protected abstract void setFileHelper(Long newFileID); + + @Override + public void setFile(Long newFileID) { + if (getFileID().isPresent()) { + if (Objects.equals(newFileID, getFileID().get()) == false) { + setFileHelper(newFileID); + } + } else if (nonNull(newFileID)) { + setFileHelper(newFileID); + } + } + + +} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index 232cfe8a6f..d8104ad1df 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -62,11 +62,6 @@ public class MetaDataPane extends DrawableUIBase { private static final Logger LOGGER = Logger.getLogger(MetaDataPane.class.getName()); - @Override - public ImageGalleryController getController() { - return controller; - } - @FXML private ImageView imageView; @@ -153,34 +148,9 @@ public class MetaDataPane extends DrawableUIBase { }); } - volatile private Optional> fileOpt = Optional.empty(); - - volatile private Optional fileIDOpt = Optional.empty(); - - @Override protected synchronized void setFileHelper(Long newFileID) { setFileIDOpt(Optional.ofNullable(newFileID)); if (newFileID == null) { - - @Override - public Optional> getFile() { - if (fileIDOpt.isPresent()) { - if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { - return fileOpt; - } else { - return fileOpt; - if (Objects.equals(newFileID, fileIDOpt.get()) == false) { - setFileHelper(newFileID); - } - } else { - if (nonNull(newFileID)) { - setFileHelper(newFileID); - } - } - setFileHelper(newFileID); - } - private void setFileHelper(Long newFileID) { - fileIDOpt = Optional.of(newFileID); if (newFileID == null) { Platform.runLater(() -> { imageView.setImage(null); @@ -206,7 +176,6 @@ public class MetaDataPane extends DrawableUIBase { updateCategory(); }); - } @Override @@ -249,6 +218,7 @@ public class MetaDataPane extends DrawableUIBase { }); } + @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { handleTagChanged(evt.getDeletedTag().getContent().getId()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java index ba60735da9..6459b0f670 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java @@ -220,6 +220,7 @@ public class SlideShowView extends DrawableTileBase { } @ThreadConfined(type = ThreadType.JFX) + public void stopVideo() { if (imageBorder.getCenter() instanceof MediaControl) { ((MediaControl) imageBorder.getCenter()).stopVideo(); @@ -318,7 +319,6 @@ public class SlideShowView extends DrawableTileBase { public Category updateCategory() { if (getFile().isPresent()) { final Category category = super.updateCategory(); - final Border border1 = hasHashHit() && (category == Category.ZERO) ToggleButton toggleForCategory = getToggleForCategory(category); Platform.runLater(() -> { toggleForCategory.setSelected(true); From 4b7285ffd8f8e2865697d6be43b39e5ca298a16a Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 14:11:44 -0400 Subject: [PATCH 169/198] rename method in CategoryManager to be more descriptive; fix tag and category grouping when tags aer added / removed --- .../datamodel/grouping/GroupManager.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index ed1b5b3706..6b357a5457 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -551,20 +551,25 @@ public class GroupManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { - if (groupBy == DrawableAttribute.TAGS || groupBy == DrawableAttribute.CATEGORY) { - final GroupKey groupKey = new GroupKey<>(DrawableAttribute.TAGS, evt.getAddedTag().getName()); - final long fileID = evt.getAddedTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); + GroupKey groupKey = null; + if (groupBy == DrawableAttribute.TAGS) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + } else if (groupBy == DrawableAttribute.CATEGORY) { + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getAddedTag().getName())); } + final long fileID = evt.getAddedTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); } + @SuppressWarnings("AssignmentToMethodParameter") private void addFileToGroup(DrawableGroup g, final GroupKey groupKey, final long fileID) { if (g == null) { //if there wasn't already a group check if there should be one now - popuplateIfAnalyzed(groupKey, null); - } else { + g = popuplateIfAnalyzed(groupKey, null); + } + if (g != null) { //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. g.addFile(fileID); } @@ -616,8 +621,8 @@ public class GroupManager { } if (groupKey != null) { final long fileID = evt.getTag().getContent().getId(); - DrawableGroup g = removeFromGroup(groupKey, fileID); - } + DrawableGroup g = removeFromGroup(groupKey, fileID); + } } } @@ -724,7 +729,7 @@ public class GroupManager { if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { /* for attributes other than path we can't be sure a group is * fully analyzed because we don't know all the files that - * will be a part of that group */ + * will be a part of that group,. just show them no matter what. */ try { Set fileIDs = getFileIDsInGroup(groupKey); @@ -736,9 +741,8 @@ public class GroupManager { group = groupMap.get(groupKey); group.setFiles(ObjectUtils.defaultIfNull(fileIDs, Collections.emptySet())); } else { - group = new DrawableGroup(groupKey, fileIDs, groupSeen); - group.seenProperty().addListener((observable, oldSeen, newSeen) -> { + group.seenProperty().addListener((o, oldSeen, newSeen) -> { markGroupSeen(group, newSeen); }); groupMap.put(groupKey, group); From d11e4b03d54991da4181f979044fc410c425f4cd Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:11:16 -0400 Subject: [PATCH 170/198] reduce duplicate code --- .../imagegallery/ImageGalleryController.java | 4 +-- .../datamodel/grouping/GroupManager.java | 6 ++-- .../imagegallery/gui/DrawableTileBase.java | 34 ++++++++++--------- .../gui/drawableviews/MetaDataPane.java | 13 ++++--- 4 files changed, 32 insertions(+), 25 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 11646338dc..6752b3a44f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -492,13 +492,13 @@ public final class ImageGalleryController { break; case CONTENT_TAG_ADDED: final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt; - if (getDatabase().isInDB((tagAddedEvent).getAddedTag().getContent().getId())) { + if (getDatabase().isInDB((tagAddedEvent).getTag().getContent().getId())) { getTagsManager().fireTagAddedEvent(tagAddedEvent); } break; case CONTENT_TAG_DELETED: final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) evt; - if (getDatabase().isInDB((tagDeletedEvent).getDeletedTag().getContent().getId())) { + if (getDatabase().isInDB((tagDeletedEvent).getTag().getContent().getId())) { getTagsManager().fireTagDeletedEvent(tagDeletedEvent); } break; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index 6b357a5457..c0f0c27725 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -553,11 +553,11 @@ public class GroupManager { public void handleTagAdded(ContentTagAddedEvent evt) { GroupKey groupKey = null; if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getAddedTag().getName()); + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } else if (groupBy == DrawableAttribute.CATEGORY) { - groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getAddedTag().getName())); + groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); } - final long fileID = evt.getAddedTag().getContent().getId(); + final long fileID = evt.getTag().getContent().getId(); DrawableGroup g = getGroupForKey(groupKey); addFileToGroup(g, groupKey, fileID); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java index 80c73b1ae9..428bd0b5f4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java @@ -62,6 +62,7 @@ import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.events.TagEvent; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; @@ -70,6 +71,7 @@ import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -349,36 +351,36 @@ public abstract class DrawableTileBase extends DrawableUIBase { @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { - getFileID().ifPresent(fileID -> { - try { - if (fileID == evt.getAddedTag().getContent().getId() - && evt.getAddedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { - Platform.runLater(() -> { - followUpImageView.setImage(followUpIcon); - followUpToggle.setSelected(true); - }); - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); - } + handleTagEvent(evt, () -> { + Platform.runLater(() -> { + followUpImageView.setImage(followUpIcon); + followUpToggle.setSelected(true); + }); }); } @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { + handleTagEvent(evt, this::updateFollowUpIcon); + } + void handleTagEvent(TagEvent evt, Runnable runnable) { getFileID().ifPresent(fileID -> { try { - if (fileID == evt.getDeletedTag().getContent().getId() - && evt.getDeletedTag().getName().equals(getController().getTagsManager().getFollowUpTagName())) { - updateFollowUpIcon(); + final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); + final ContentTag deletedTag = evt.getTag(); + + if (fileID == deletedTag.getContent().getId() + && deletedTag.getName().equals(followUpTagName)) { + runnable.run(); } } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); + LOGGER.log(Level.SEVERE, "Failed to get followup tag name. Unable to update follow up status for file. ", ex); } }); + } private void updateFollowUpIcon() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index d8104ad1df..aa169053ff 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -221,13 +221,18 @@ public class MetaDataPane extends DrawableUIBase { @Subscribe @Override public void handleTagDeleted(ContentTagDeletedEvent evt) { - handleTagChanged(evt.getDeletedTag().getContent().getId()); + handleTagEvent(evt, this::updateUI); } - private void handleTagChanged(Long tagFileID) { + /** + * + * @param tagFileID the value of tagEvent + * @param runnable the value of runnable + */ + void handleTagEvent(TagEvent tagEvent, final Runnable runnable) { getFileID().ifPresent(fileID -> { - if (Objects.equals(tagFileID, fileID)) { - updateUI(); + if (Objects.equals(tagEvent.getTag().getContent().getId(), fileID)) { + runnable.run(); } }); } From 38732c17ba7bd188ba0156518b832573c4f1fbb1 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:22:14 -0400 Subject: [PATCH 171/198] move DrawableView and GroupPane to a new package --- .../imagegallery/gui/DrawableTileBase.java | 393 ------------------ .../imagegallery/gui/DrawableUIBase.java | 97 ----- .../gui/drawableviews/DrawableTile.fxml | 112 +++-- .../gui/drawableviews/DrawableTileBase.java | 78 +--- .../gui/drawableviews/GroupPane.java | 2 + .../gui/drawableviews/MetaDataPane.java | 3 + .../gui/drawableviews/SlideShowView.java | 1 - 7 files changed, 63 insertions(+), 623 deletions(-) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java deleted file mode 100644 index 428bd0b5f4..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableTileBase.java +++ /dev/null @@ -1,393 +0,0 @@ - -/* - * Autopsy Forensic Browser - * - * Copyright 2013-15 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery.gui; - -import com.google.common.eventbus.Subscribe; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Optional; -import java.util.logging.Level; -import javafx.application.Platform; -import javafx.beans.Observable; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.fxml.FXML; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.Label; -import javafx.scene.control.MenuItem; -import javafx.scene.control.ToggleButton; -import javafx.scene.control.Tooltip; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.Border; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.BorderStroke; -import javafx.scene.layout.BorderStrokeStyle; -import javafx.scene.layout.BorderWidths; -import javafx.scene.layout.CornerRadii; -import javafx.scene.layout.Region; -import javafx.scene.paint.Color; -import javax.swing.Action; -import javax.swing.SwingUtilities; -import org.openide.util.Lookup; -import org.openide.util.actions.Presenter; -import org.openide.windows.TopComponent; -import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.ThreadConfined; -import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; -import org.sleuthkit.autopsy.datamodel.FileNode; -import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; -import org.sleuthkit.autopsy.directorytree.ExtractAction; -import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.events.ContentTagAddedEvent; -import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.events.TagEvent; -import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; -import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; -import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; -import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; -import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; -import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * An abstract base class for {@link DrawableTile} and {@link SlideShowView}, - * since they share a similar node tree and many behaviors, other implementers - * of {@link DrawableView}s should implement the interface directly - * - */ -public abstract class DrawableTileBase extends DrawableUIBase { - - private static final Logger LOGGER = Logger.getLogger(DrawableTileBase.class.getName()); - - private static final Border UNSELECTED_BORDER = new Border(new BorderStroke(Color.GRAY, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3))); - - private static final Border SELECTED_BORDER = new Border(new BorderStroke(Color.BLUE, BorderStrokeStyle.SOLID, new CornerRadii(2), new BorderWidths(3))); - - //TODO: do this in CSS? -jm - protected static final Image videoIcon = new Image("org/sleuthkit/autopsy/imagegallery/images/video-file.png"); - protected static final Image hashHitIcon = new Image("org/sleuthkit/autopsy/imagegallery/images/hashset_hits.png"); - protected static final Image followUpIcon = new Image("org/sleuthkit/autopsy/imagegallery/images/flag_red.png"); - protected static final Image followUpGray = new Image("org/sleuthkit/autopsy/imagegallery/images/flag_gray.png"); - - protected static final FileIDSelectionModel globalSelectionModel = FileIDSelectionModel.getInstance(); - private static ContextMenu contextMenu; - - /** - * displays the icon representing video files - */ - @FXML - protected ImageView fileTypeImageView; - - /** - * displays the icon representing hash hits - */ - @FXML - protected ImageView hashHitImageView; - - /** - * displays the icon representing follow up tag - */ - @FXML - protected ImageView followUpImageView; - - @FXML - protected ToggleButton followUpToggle; - - /** - * the label that shows the name of the represented file - */ - @FXML - protected Label nameLabel; - - @FXML - protected BorderPane imageBorder; - - /** - * the groupPane this {@link DrawableTileBase} is embedded in - */ - final private GroupPane groupPane; - volatile private boolean registered = false; - - protected DrawableTileBase(GroupPane groupPane) { - super(groupPane.getController()); - - this.groupPane = groupPane; - globalSelectionModel.getSelected().addListener((Observable observable) -> { - updateSelectionState(); - }); - - //set up mouse listener - //TODO: split this between DrawableTile and SingleDrawableViewBase - addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler() { - - @Override - public void handle(MouseEvent t) { - getFile().ifPresent(file -> { - final long fileID = file.getId(); - switch (t.getButton()) { - case PRIMARY: - if (t.getClickCount() == 1) { - if (t.isControlDown()) { - - globalSelectionModel.toggleSelection(fileID); - } else { - groupPane.makeSelection(t.isShiftDown(), fileID); - } - } else if (t.getClickCount() > 1) { - groupPane.activateSlideShowViewer(fileID); - } - break; - case SECONDARY: - if (t.getClickCount() == 1) { - if (globalSelectionModel.isSelected(fileID) == false) { - groupPane.makeSelection(false, fileID); - } - } - if (contextMenu != null) { - contextMenu.hide(); - } - final ContextMenu groupContextMenu = groupPane.getContextMenu(); - if (groupContextMenu != null) { - groupContextMenu.hide(); - } - contextMenu = buildContextMenu(file); - contextMenu.show(DrawableTileBase.this, t.getScreenX(), t.getScreenY()); - break; - } - }); - - t.consume(); - } - - private ContextMenu buildContextMenu(DrawableFile file) { - final ArrayList menuItems = new ArrayList<>(); - - menuItems.add(new CategorizeAction(getController()).getPopupMenu()); - - menuItems.add(new AddDrawableTagAction(getController()).getPopupMenu()); - - final MenuItem extractMenuItem = new MenuItem("Extract File(s)"); - extractMenuItem.setOnAction((ActionEvent t) -> { - SwingUtilities.invokeLater(() -> { - TopComponent etc = WindowManager.getDefault().findTopComponent(ImageGalleryTopComponent.PREFERRED_ID); - ExtractAction.getInstance().actionPerformed(new java.awt.event.ActionEvent(etc, 0, null)); - }); - }); - menuItems.add(extractMenuItem); - - MenuItem contentViewer = new MenuItem("Show Content Viewer"); - contentViewer.setOnAction((ActionEvent t) -> { - SwingUtilities.invokeLater(() -> { - new NewWindowViewAction("Show Content Viewer", new FileNode(file.getAbstractFile())).actionPerformed(null); - }); - }); - menuItems.add(contentViewer); - - MenuItem externalViewer = new MenuItem("Open in External Viewer"); - final ExternalViewerAction externalViewerAction = new ExternalViewerAction("Open in External Viewer", new FileNode(file.getAbstractFile())); - - externalViewer.setDisable(externalViewerAction.isEnabled() == false); - externalViewer.setOnAction((ActionEvent t) -> { - SwingUtilities.invokeLater(() -> { - externalViewerAction.actionPerformed(null); - }); - }); - menuItems.add(externalViewer); - - Collection menuProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class); - - for (ContextMenuActionsProvider provider : menuProviders) { - for (final Action act : provider.getActions()) { - if (act instanceof Presenter.Popup) { - Presenter.Popup aact = (Presenter.Popup) act; - menuItems.add(SwingMenuItemAdapter.create(aact.getPopupPresenter())); - } - } - } - - ContextMenu contextMenu = new ContextMenu(menuItems.toArray(new MenuItem[]{})); - contextMenu.setAutoHide(true); - return contextMenu; - } - }); - } - - GroupPane getGroupPane() { - return groupPane; - } - - @ThreadConfined(type = ThreadType.UI) - protected abstract void clearContent(); - - protected abstract void disposeContent(); - - protected abstract Runnable getContentUpdateRunnable(); - - protected abstract String getTextForLabel(); - - protected void initialize() { - followUpToggle.setOnAction((ActionEvent event) -> { - getFile().ifPresent(file -> { - if (followUpToggle.isSelected() == true) { - try { - globalSelectionModel.clearAndSelect(file.getId()); - new AddDrawableTagAction(getController()).addTag(getController().getTagsManager().getFollowUpTagName(), ""); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); - } - } else { - new DeleteFollowUpTagAction(getController(), file).handle(event); - } - }); - }); - } - - protected boolean hasFollowUp() { - if (getFileID().isPresent()) { - try { - TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); - return DrawableAttribute.TAGS.getValue(getFile().get()).stream() - .anyMatch(followUpTagName::equals); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "failed to get follow up tag name ", ex); - return true; - } - } else { - return false; - } - } - - @Override - protected void setFileHelper(final Long newFileID) { - setFileIDOpt(Optional.ofNullable(newFileID)); - disposeContent(); - - if (getFileID().isPresent() == false || Case.isCaseOpen() == false) { - if (registered == true) { - getController().getCategoryManager().unregisterListener(this); - getController().getTagsManager().unregisterListener(this); - registered = false; - } - setFileOpt(Optional.empty()); - Platform.runLater(() -> { - clearContent(); - }); - } else { - if (registered == false) { - getController().getCategoryManager().registerListener(this); - getController().getTagsManager().registerListener(this); - registered = true; - } - setFileOpt(Optional.empty()); - - updateSelectionState(); - updateCategory(); - updateFollowUpIcon(); - updateUI(); - Platform.runLater(getContentUpdateRunnable()); - } - } - - private void updateUI() { - getFile().ifPresent(file -> { - final boolean isVideo = file.isVideo(); - final boolean hasHashSetHits = hasHashHit(); - final String text = getTextForLabel(); - - Platform.runLater(() -> { - fileTypeImageView.setImage(isVideo ? videoIcon : null); - hashHitImageView.setImage(hasHashSetHits ? hashHitIcon : null); - nameLabel.setText(text); - nameLabel.setTooltip(new Tooltip(text)); - }); - }); - - } - - /** - * update the visual representation of the selection state of this - * DrawableView - */ - protected void updateSelectionState() { - getFile().ifPresent(file -> { - final boolean selected = globalSelectionModel.isSelected(file.getId()); - Platform.runLater(() -> { - setBorder(selected ? SELECTED_BORDER : UNSELECTED_BORDER); - }); - }); - } - - @Override - public Region getCategoryBorderRegion() { - return imageBorder; - } - - @Subscribe - @Override - public void handleTagAdded(ContentTagAddedEvent evt) { - - handleTagEvent(evt, () -> { - Platform.runLater(() -> { - followUpImageView.setImage(followUpIcon); - followUpToggle.setSelected(true); - }); - }); - } - - @Subscribe - @Override - public void handleTagDeleted(ContentTagDeletedEvent evt) { - handleTagEvent(evt, this::updateFollowUpIcon); - } - - void handleTagEvent(TagEvent evt, Runnable runnable) { - getFileID().ifPresent(fileID -> { - try { - final TagName followUpTagName = getController().getTagsManager().getFollowUpTagName(); - final ContentTag deletedTag = evt.getTag(); - - if (fileID == deletedTag.getContent().getId() - && deletedTag.getName().equals(followUpTagName)) { - runnable.run(); - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get followup tag name. Unable to update follow up status for file. ", ex); - } - }); - - } - - private void updateFollowUpIcon() { - boolean hasFollowUp = hasFollowUp(); - Platform.runLater(() -> { - followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray); - followUpToggle.setSelected(hasFollowUp); - }); - } -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java deleted file mode 100644 index ec794eabae..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/DrawableUIBase.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2015 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery.gui; - -import java.util.Objects; -import static java.util.Objects.nonNull; -import java.util.Optional; -import java.util.logging.Level; -import javafx.scene.layout.AnchorPane; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * - */ -abstract public class DrawableUIBase extends AnchorPane implements DrawableView { - - private final ImageGalleryController controller; - - volatile private Optional> fileOpt = Optional.empty(); - - volatile private Optional fileIDOpt = Optional.empty(); - - public DrawableUIBase(ImageGalleryController controller) { - this.controller = controller; - } - - @Override - public ImageGalleryController getController() { - return controller; - } - - @Override - public Optional getFileID() { - return fileIDOpt; - } - - void setFileIDOpt(Optional fileIDOpt) { - this.fileIDOpt = fileIDOpt; - } - - void setFileOpt(Optional> fileOpt) { - this.fileOpt = fileOpt; - } - - @Override - public Optional> getFile() { - if (fileIDOpt.isPresent()) { - if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { - return fileOpt; - } else { - try { - fileOpt = Optional.of(getController().getFileFromId(fileIDOpt.get())); - } catch (TskCoreException ex) { - Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); - fileOpt = Optional.empty(); - } - return fileOpt; - } - } else { - return Optional.empty(); - } - } - - protected abstract void setFileHelper(Long newFileID); - - @Override - public void setFile(Long newFileID) { - if (getFileID().isPresent()) { - if (Objects.equals(newFileID, getFileID().get()) == false) { - setFileHelper(newFileID); - } - } else if (nonNull(newFileID)) { - setFileHelper(newFileID); - } - } - - -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml index acfcdc1336..4d34061c77 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml @@ -7,62 +7,60 @@ - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- -
- -
-
-
+ + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
-
- - - + +
+ +
+
+
+
+
+ + +
diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index c9bfe35b29..ed12891589 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -23,8 +23,6 @@ import com.google.common.eventbus.Subscribe; import java.util.ArrayList; import java.util.Collection; import java.util.Optional; -import static java.util.Objects.nonNull; -import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; import javafx.beans.Observable; @@ -69,9 +67,11 @@ import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction; +import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -128,42 +128,16 @@ public abstract class DrawableTileBase extends DrawableUIBase { @FXML protected BorderPane imageBorder; - - @Override - public Optional getFileID() { - return fileIDOpt; - } - - @Override - public Optional> getFile() { - if (fileIDOpt.isPresent()) { - if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { - return fileOpt; - } else { - try { - fileOpt = Optional.of(ImageGalleryController.getDefault().getFileFromId(fileIDOpt.get())); - } catch (TskCoreException ex) { - Logger.getAnonymousLogger().log(Level.WARNING, "failed to get DrawableFile for obj_id" + fileIDOpt.get(), ex); - fileOpt = Optional.empty(); - } - return fileOpt; - } - } else { - return Optional.empty(); - } - } /** * the groupPane this {@link DrawableTileBase} is embedded in */ final private GroupPane groupPane; volatile private boolean registered = false; - private final ImageGalleryController controller; protected DrawableTileBase(GroupPane groupPane) { super(groupPane.getController()); this.groupPane = groupPane; - this.controller = groupPane.getController(); globalSelectionModel.getSelected().addListener((Observable observable) -> { updateSelectionState(); }); @@ -284,7 +258,6 @@ public abstract class DrawableTileBase extends DrawableUIBase { try { globalSelectionModel.clearAndSelect(file.getId()); new AddDrawableTagAction(getController()).addTag(getController().getTagsManager().getFollowUpTagName(), ""); - new AddDrawableTagAction(controller).addTag(followUpTagName, ""); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Failed to add Follow Up tag. Could not load TagName.", ex); } @@ -307,12 +280,10 @@ public abstract class DrawableTileBase extends DrawableUIBase { } } else { return false; - if (Objects.equals(newFileID, fileIDOpt.get()) == false) { - setFileHelper(newFileID); } } - private void setFileHelper(final Long newFileID) { + @Override protected void setFileHelper(final Long newFileID) { setFileIDOpt(Optional.ofNullable(newFileID)); disposeContent(); @@ -377,49 +348,6 @@ public abstract class DrawableTileBase extends DrawableUIBase { return imageBorder; } - @Subscribe - @Override - public void handleTagAdded(ContentTagAddedEvent evt) { - fileIDOpt.ifPresent(fileID -> { - try { - if (fileID == evt.getAddedTag().getContent().getId() - && evt.getAddedTag().getName() == getController().getTagsManager().getFollowUpTagName()) { - - Platform.runLater(() -> { - followUpImageView.setImage(followUpIcon); - followUpToggle.setSelected(true); - }); - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); - } - }); - } - - @Subscribe - @Override - public void handleTagDeleted(ContentTagDeletedEvent evt) { - - fileIDOpt.ifPresent(fileID -> { - try { - if (fileID == evt.getDeletedTag().getContent().getId() - && evt.getDeletedTag().getName() == controller.getTagsManager().getFollowUpTagName()) { - updateFollowUpIcon(); - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Failed to get follow up status for file.", ex); - } - }); - } - - private void updateFollowUpIcon() { - boolean hasFollowUp = hasFollowUp(); - Platform.runLater(() -> { - followUpImageView.setImage(hasFollowUp ? followUpIcon : followUpGray); - followUpToggle.setSelected(hasFollowUp); - }); - } - @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 9bc0cf493e..15d52e56e8 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.SlideShowView; +import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableTile; import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.Arrays; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index aa169053ff..095ec88495 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -88,6 +88,9 @@ public class MetaDataPane extends DrawableUIBase { } catch (IOException exception) { throw new RuntimeException(exception); } + } + } + @FXML @SuppressWarnings("unchecked") void initialize() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java index 6459b0f670..2b29e57d39 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java @@ -220,7 +220,6 @@ public class SlideShowView extends DrawableTileBase { } @ThreadConfined(type = ThreadType.JFX) - public void stopVideo() { if (imageBorder.getCenter() instanceof MediaControl) { ((MediaControl) imageBorder.getCenter()).stopVideo(); From f293485a2f8827f98c44d2a41cf806d59a70af7b Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:23:36 -0400 Subject: [PATCH 172/198] remove unneeded interface --- .../autopsy/imagegallery/gui/drawableviews/GroupPane.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 15d52e56e8..ab011fc493 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -18,8 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; -import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.SlideShowView; -import org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableTile; import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.Arrays; @@ -102,7 +100,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.directorytree.ExtractAction; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; From 8c2f6d274a1fc84204d8588ff7d2a0420a350718 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 15:42:48 -0400 Subject: [PATCH 173/198] move classes to better packages; remove FileUpdateEvent --- .../imagegallery/DrawableTagsManager.java | 213 ------------------ .../imagegallery/ImageGalleryController.java | 1 + .../imagegallery/actions/AddTagAction.java | 2 +- .../actions/CategorizeAction.java | 2 +- .../actions/DeleteFollowUpTagAction.java | 2 +- .../datamodel/CategoryManager.java | 4 +- .../imagegallery/datamodel/DrawableDB.java | 1 - .../datamodel/DrawableTagsManager.java | 32 +-- .../datamodel/grouping/GroupManager.java | 4 - 9 files changed, 14 insertions(+), 247 deletions(-) delete mode 100644 ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java deleted file mode 100644 index 0bbc4b9d5a..0000000000 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/DrawableTagsManager.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013-15 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.imagegallery; - -import com.google.common.eventbus.EventBus; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.logging.Level; -import java.util.stream.Collectors; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.events.ContentTagAddedEvent; -import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Manages Tags, Tagging, and the relationship between Categories and Tags in - * the autopsy Db. delegates some, work to the backing {@link TagsManager}. - */ -public class DrawableTagsManager { - - private static final String FOLLOW_UP = "Follow Up"; - - final private Object autopsyTagsManagerLock = new Object(); - private TagsManager autopsyTagsManager; - - /** Used to distribute {@link TagsChangeEvent}s */ - private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); - - /** The tag name corresponding to the "built-in" tag "Follow Up" */ - private TagName followUpTagName; - - public DrawableTagsManager(TagsManager autopsyTagsManager) { - this.autopsyTagsManager = autopsyTagsManager; - - } - - /** - * register an object to receive CategoryChangeEvents - * - * @param listner - */ - public void registerListener(Object listner) { - tagsEventBus.register(listner); - } - - /** - * unregister an object from receiving CategoryChangeEvents - * - * @param listener - */ - public void unregisterListener(Object listener) { - tagsEventBus.unregister(listener); - } - - public void fireTagAddedEvent(ContentTagAddedEvent event) { - tagsEventBus.post(event); - } - - public void fireTagDeletedEvent(ContentTagDeletedEvent event) { - tagsEventBus.post(event); - } - - /** - * assign a new TagsManager to back this one, ie when the current case - * changes - * - * @param autopsyTagsManager - */ - public void setAutopsyTagsManager(TagsManager autopsyTagsManager) { - synchronized (autopsyTagsManagerLock) { - this.autopsyTagsManager = autopsyTagsManager; - clearFollowUpTagName(); - } - } - - /** - * Use when closing a case to make sure everything is re-initialized in the - * next case. - */ - public void clearFollowUpTagName() { - synchronized (autopsyTagsManagerLock) { - followUpTagName = null; - } - } - - /** - * get the (cached) follow up TagName - * - * @return - * - * @throws TskCoreException - */ - public TagName getFollowUpTagName() throws TskCoreException { - synchronized (autopsyTagsManagerLock) { - if (Objects.isNull(followUpTagName)) { - followUpTagName = getTagName(FOLLOW_UP); - } - return followUpTagName; - } - } - - public Collection getNonCategoryTagNames() { - synchronized (autopsyTagsManagerLock) { - try { - return autopsyTagsManager.getAllTagNames().stream() - .filter(CategoryManager::isCategoryTagName) - .collect(Collectors.toSet()); - } catch (TskCoreException | IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); - } - return Collections.emptySet(); - } - } - - /** - * Gets content tags count by content. - * - * @param The content of interest. - * - * @return A list, possibly empty, of the tags that have been applied to the - * artifact. - * - * @throws TskCoreException - */ - public List getContentTagsByContent(Content content) throws TskCoreException { - synchronized (autopsyTagsManagerLock) { - return autopsyTagsManager.getContentTagsByContent(content); - } - } - - public TagName getTagName(String displayName) throws TskCoreException { - synchronized (autopsyTagsManagerLock) { - try { - for (TagName tn : autopsyTagsManager.getAllTagNames()) { - if (displayName.equals(tn.getDisplayName())) { - return tn; - } - } - try { - return autopsyTagsManager.addTagName(displayName); - } catch (TagsManager.TagNameAlreadyExistsException ex) { - throw new TskCoreException("tagame exists but wasn't found", ex); - } - } catch (IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); - throw new TskCoreException("Case was closed out from underneath", ex); - } - } - } - - public TagName getTagName(Category cat) { - try { - return getTagName(cat.getDisplayName()); - } catch (TskCoreException ex) { - return null; - } - } - - public ContentTag addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { - synchronized (autopsyTagsManagerLock) { - return autopsyTagsManager.addContentTag(file, tagName, comment); - } - } - - public List getContentTagsByTagName(TagName t) throws TskCoreException { - synchronized (autopsyTagsManagerLock) { - return autopsyTagsManager.getContentTagsByTagName(t); - } - } - - public List getAllTagNames() throws TskCoreException { - synchronized (autopsyTagsManagerLock) { - return autopsyTagsManager.getAllTagNames(); - } - } - - public List getTagNamesInUse() throws TskCoreException { - synchronized (autopsyTagsManagerLock) { - return autopsyTagsManager.getTagNamesInUse(); - } - } - - public void deleteContentTag(ContentTag ct) throws TskCoreException { - synchronized (autopsyTagsManagerLock) { - autopsyTagsManager.deleteContentTag(ct); - } - } -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 6752b3a44f..b47bafe5a9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import java.beans.PropertyChangeEvent; import java.util.ArrayList; import java.util.List; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index af42c5ef2c..bcf4e18555 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -26,7 +26,7 @@ import javafx.scene.control.MenuItem; import javax.swing.SwingUtilities; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 3f6a918524..cfe1f3ac42 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -29,7 +29,7 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index 934a3fb258..fb729807c0 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -24,7 +24,7 @@ import javafx.event.ActionEvent; import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.ContentTag; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index e685c118f5..2c7c558997 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -34,8 +34,9 @@ import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.imagegallery.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -262,6 +263,7 @@ public class CategoryManager { fireChange(Collections.singleton(addedTag.getContent().getId()), newCat); } } + @Subscribe @Subscribe public void handleTagDeleted(ContentTagDeletedEvent event) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index db378c9917..87fa001827 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -47,7 +47,6 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupKey; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index 547ab7a858..57d7152967 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -18,21 +18,19 @@ */ package org.sleuthkit.autopsy.imagegallery.datamodel; -import com.google.common.eventbus.AsyncEventBus; import com.google.common.eventbus.EventBus; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -44,20 +42,13 @@ import org.sleuthkit.datamodel.TskCoreException; */ public class DrawableTagsManager { - private static final Logger LOGGER = Logger.getLogger(DrawableTagsManager.class.getName()); - private static final String FOLLOW_UP = "Follow Up"; final private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; /** Used to distribute {@link TagsChangeEvent}s */ - private final EventBus tagsEventBus = new AsyncEventBus( - Executors.newSingleThreadExecutor( - new BasicThreadFactory.Builder().namingPattern("Tags Event Bus").uncaughtExceptionHandler((Thread t, Throwable e) -> { - LOGGER.log(Level.SEVERE, "uncaught exception in event bus handler", e); - }).build() - )); + private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); /** The tag name corresponding to the "built-in" tag "Follow Up" */ private TagName followUpTagName; @@ -132,23 +123,14 @@ public class DrawableTagsManager { } } - /** - * get all the TagNames that are not categories - * - * @return all the TagNames that are not categories, in alphabetical order - * by displayName, or, an empty set if there was an exception looking them - * up from the db. - */ - @Nonnull public Collection getNonCategoryTagNames() { synchronized (autopsyTagsManagerLock) { try { return autopsyTagsManager.getAllTagNames().stream() - .filter(CategoryManager::isNotCategoryTagName) - .distinct().sorted() - .collect(Collectors.toList()); + .filter(CategoryManager::isCategoryTagName) + .collect(Collectors.toSet()); } catch (TskCoreException | IllegalStateException ex) { - LOGGER.log(Level.WARNING, "couldn't access case", ex); + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); } return Collections.emptySet(); } @@ -184,7 +166,7 @@ public class DrawableTagsManager { throw new TskCoreException("tagame exists but wasn't found", ex); } } catch (IllegalStateException ex) { - LOGGER.log(Level.SEVERE, "Case was closed out from underneath", ex); + Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); throw new TskCoreException("Case was closed out from underneath", ex); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index c0f0c27725..6ecf5a5dca 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -50,7 +50,6 @@ import javax.annotation.concurrent.GuardedBy; import javax.swing.SortOrder; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; @@ -647,8 +646,6 @@ public class GroupManager { */ @Subscribe synchronized public void handleFileUpdate(Collection updatedFileIDs) { - Validate.isTrue(evt.getUpdateType() == FileUpdateEvent.UpdateType.UPDATE); - Collection fileIDs = evt.getFileIDs(); /** * TODO: is there a way to optimize this to avoid quering to db * so much. the problem is that as a new files are analyzed they @@ -670,7 +667,6 @@ public class GroupManager { //we fire this event for all files so that the category counts get updated during initial db population controller.getCategoryManager().fireChange(updatedFileIDs, null); } - private DrawableGroup popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { if (Objects.nonNull(task) && (task.isCancelled())) { From ed2fcdf80eceb4c01b26126bb83edb324b8ca0a3 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 22 Jun 2015 16:42:44 -0400 Subject: [PATCH 174/198] better handling of exceptions in event bus eventhandlers --- .../datamodel/CategoryManager.java | 2 -- .../datamodel/DrawableTagsManager.java | 18 +++++++++++++----- .../datamodel/grouping/GroupManager.java | 19 +++++++++++-------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index 2c7c558997..d77d9583ce 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -35,8 +35,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index 57d7152967..af5a0ebced 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -18,19 +18,20 @@ */ package org.sleuthkit.autopsy.imagegallery.datamodel; +import com.google.common.eventbus.AsyncEventBus; import com.google.common.eventbus.EventBus; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -42,13 +43,20 @@ import org.sleuthkit.datamodel.TskCoreException; */ public class DrawableTagsManager { + private static final Logger LOGGER = Logger.getLogger(DrawableTagsManager.class.getName()); + private static final String FOLLOW_UP = "Follow Up"; final private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; /** Used to distribute {@link TagsChangeEvent}s */ - private final EventBus tagsEventBus = new EventBus("Tags Event Bus"); + private final EventBus tagsEventBus = new AsyncEventBus( + Executors.newSingleThreadExecutor( + new BasicThreadFactory.Builder().namingPattern("Tags Event Bus").uncaughtExceptionHandler((Thread t, Throwable e) -> { + LOGGER.log(Level.SEVERE, "uncaught exception in event bus handler", e); + }).build() + )); /** The tag name corresponding to the "built-in" tag "Follow Up" */ private TagName followUpTagName; @@ -130,7 +138,7 @@ public class DrawableTagsManager { .filter(CategoryManager::isCategoryTagName) .collect(Collectors.toSet()); } catch (TskCoreException | IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.WARNING, "couldn't access case", ex); + LOGGER.log(Level.WARNING, "couldn't access case", ex); } return Collections.emptySet(); } @@ -166,7 +174,7 @@ public class DrawableTagsManager { throw new TskCoreException("tagame exists but wasn't found", ex); } } catch (IllegalStateException ex) { - Logger.getLogger(DrawableTagsManager.class.getName()).log(Level.SEVERE, "Case was closed out from underneath", ex); + LOGGER.log(Level.SEVERE, "Case was closed out from underneath", ex); throw new TskCoreException("Case was closed out from underneath", ex); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index 6ecf5a5dca..623d0e7363 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -551,15 +551,16 @@ public class GroupManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { GroupKey groupKey = null; - if (groupBy == DrawableAttribute.TAGS) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); - } else if (groupBy == DrawableAttribute.CATEGORY) { + if (groupBy == DrawableAttribute.CATEGORY && CategoryManager.isCategoryTagName(evt.getTag().getName())) { groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { + groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); + } + if (groupKey != null) { + final long fileID = evt.getTag().getContent().getId(); + DrawableGroup g = getGroupForKey(groupKey); + addFileToGroup(g, groupKey, fileID); } - final long fileID = evt.getTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); - } @SuppressWarnings("AssignmentToMethodParameter") @@ -618,9 +619,11 @@ public class GroupManager { } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } + if (groupKey != null) { final long fileID = evt.getTag().getContent().getId(); - DrawableGroup g = removeFromGroup(groupKey, fileID); + DrawableGroup g = removeFromGroup(groupKey, fileID); + } } } } From e157a5b53b9cd152b2656cf5074aa235132aa1fe Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 15:46:12 -0400 Subject: [PATCH 175/198] only add new cat tag if there is no existing cat tag. put adding and removing fileids to/from group on jfx thread; remove file from groups when adding to new catagory based on new tag --- .../imagegallery/ImageGalleryController.java | 1 - .../actions/CategorizeAction.java | 13 +++++++-- .../datamodel/grouping/GroupManager.java | 28 ++++++++++++------- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index b47bafe5a9..6752b3a44f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.imagegallery; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import java.beans.PropertyChangeEvent; import java.util.ArrayList; import java.util.List; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index cfe1f3ac42..b9b9cee59f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; @@ -29,13 +30,13 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.Tag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -151,8 +152,6 @@ public class CategorizeAction extends AddTagAction { .collect(Collectors.toList()).isEmpty()) { tagsManager.addContentTag(file, tagName, comment); } - } else { - tagsManager.getContentTagsByContent(file).stream() .filter(tag -> CategoryManager.isCategoryTagName(tag.getName())) .forEach((ct) -> { try { @@ -161,6 +160,14 @@ public class CategorizeAction extends AddTagAction { LOGGER.log(Level.SEVERE, "Error removing old categories result", ex); } }); + } else { + //add cat tag if no existing cat tag for that cat + if (fileTags.stream() + .map(Tag::getName) + .filter(tagName::equals) + .collect(Collectors.toList()).isEmpty()) { + tagsManager.addContentTag(file, tagName, comment); + } } } catch (TskCoreException ex) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index 623d0e7363..0fbf76a64e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -550,16 +550,21 @@ public class GroupManager { @Subscribe public void handleTagAdded(ContentTagAddedEvent evt) { - GroupKey groupKey = null; + GroupKey newGroupKey = null; + final long fileID = evt.getTag().getContent().getId(); if (groupBy == DrawableAttribute.CATEGORY && CategoryManager.isCategoryTagName(evt.getTag().getName())) { - groupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + newGroupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); + for (GroupKey oldGroupKey : groupMap.keySet()) { + if (oldGroupKey.equals(newGroupKey) == false) { + removeFromGroup(oldGroupKey, fileID); + } + } } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { - groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); + newGroupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } - if (groupKey != null) { - final long fileID = evt.getTag().getContent().getId(); - DrawableGroup g = getGroupForKey(groupKey); - addFileToGroup(g, groupKey, fileID); + if (newGroupKey != null) { + DrawableGroup g = getGroupForKey(newGroupKey); + addFileToGroup(g, newGroupKey, fileID); } } @@ -569,9 +574,13 @@ public class GroupManager { //if there wasn't already a group check if there should be one now g = popuplateIfAnalyzed(groupKey, null); } - if (g != null) { + DrawableGroup group = g; + if (group != null) { //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. - g.addFile(fileID); + Platform.runLater(() -> { + group.addFile(fileID); + }); + } } @@ -619,7 +628,6 @@ public class GroupManager { } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { groupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); } - if (groupKey != null) { final long fileID = evt.getTag().getContent().getId(); DrawableGroup g = removeFromGroup(groupKey, fileID); From 257ebc64da55e7180aa4d70434cc2fd3177e4215 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 16:12:55 -0400 Subject: [PATCH 176/198] clean up add tag action, use invokeLater not invokeAndWait; getNonCategoryTagNames returns TagNames in alphabetical order by displayname --- .../autopsy/imagegallery/actions/AddTagAction.java | 1 - .../datamodel/DrawableTagsManager.java | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index bcf4e18555..44bb02f0e0 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -26,7 +26,6 @@ import javafx.scene.control.MenuItem; import javax.swing.SwingUtilities; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index af5a0ebced..547ab7a858 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -27,6 +27,7 @@ import java.util.Objects; import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.stream.Collectors; +import javax.annotation.Nonnull; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; @@ -131,12 +132,21 @@ public class DrawableTagsManager { } } + /** + * get all the TagNames that are not categories + * + * @return all the TagNames that are not categories, in alphabetical order + * by displayName, or, an empty set if there was an exception looking them + * up from the db. + */ + @Nonnull public Collection getNonCategoryTagNames() { synchronized (autopsyTagsManagerLock) { try { return autopsyTagsManager.getAllTagNames().stream() - .filter(CategoryManager::isCategoryTagName) - .collect(Collectors.toSet()); + .filter(CategoryManager::isNotCategoryTagName) + .distinct().sorted() + .collect(Collectors.toList()); } catch (TskCoreException | IllegalStateException ex) { LOGGER.log(Level.WARNING, "couldn't access case", ex); } From bb85f3feda300aa8b9932dc0f10eb0861a875cab Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 16:23:59 -0400 Subject: [PATCH 177/198] SlideShow toggle is disabled initialy; fix relative paths to images in fxml --- .../gui/drawableviews/DrawableTile.fxml | 112 +++++++++--------- .../gui/drawableviews/GroupPane.fxml | 2 +- 2 files changed, 58 insertions(+), 56 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml index 4d34061c77..acfcdc1336 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml @@ -7,60 +7,62 @@ - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+
+
-
-
- -
-
-
-
-
- - - + + + +
diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml index 6dfe0d02ed..4760d1f0cf 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml @@ -113,7 +113,7 @@ - + From 773e4293c54b6cc5378de857e9eca09502f8cdbc Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 23 Jun 2015 16:27:03 -0400 Subject: [PATCH 178/198] SlideShow toggle is disabled when there is no group selected; fix relative paths to images in fxml --- .../autopsy/imagegallery/gui/drawableviews/GroupPane.fxml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml index 4760d1f0cf..6dfe0d02ed 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.fxml @@ -113,7 +113,7 @@ - + From 622da1c8de70b3aaeaa94954abb1c5c224d7ee9a Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 24 Jun 2015 10:17:51 -0400 Subject: [PATCH 179/198] use private notifyPropertyChangeEvent() method in notifyNewDataSource --- .../sleuthkit/autopsy/casemodule/Case.java | 203 +++++++++--------- 1 file changed, 97 insertions(+), 106 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index e7086cf3b0..d26210177e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -521,6 +521,103 @@ public class Case implements SleuthkitCase.ErrorObserver { notifyPropertyChangeEvent(new BlackBoardArtifactTagAddedEvent(newTag)); } + /** + * Notifies the UI that a BlackboardArtifactTag has been. + * + * @param deletedTag BlackboardArtifactTag deleted + */ + public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { + notifyPropertyChangeEvent(new BlackBoardArtifactTagDeletedEvent(deletedTag)); + } + /** + * Notifies the UI about a Case level event. + * + * @param propertyChangeEvent the event to distribute + */ + private void notifyPropertyChangeEvent(final PropertyChangeEvent propertyChangeEvent) { + pcs.firePropertyChange(propertyChangeEvent); + } catch (Exception e) { + logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS + MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), + NbBundle.getMessage(this.getClass(), + "Case.changeCase.errListenToCaseUpdates.msg"), + MessageNotifyUtil.MessageType.ERROR); + } + } + + /** + * Notifies the UI that a new ContentTag has been added. + * + * @param newTag new ContentTag added + */ + public void notifyContentTagAdded(ContentTag newTag) { + notify(new ContentTagAddedEvent(newTag)); + } + + /** + * Notifies the UI that a ContentTag has been deleted. + * + * @param deletedTag ContentTag deleted + */ + public void notifyContentTagDeleted(ContentTag deletedTag) { + notify(new ContentTagDeletedEvent(deletedTag)); + } + + /** + * Notifies the UI that a new BlackboardArtifactTag has been added. + * + * @param newTag new BlackboardArtifactTag added + */ + public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) { + notify(new BlackBoardArtifactTagAddedEvent(newTag)); + } + + /** + * Notifies the UI that a BlackboardArtifactTag has been. + * + * @param deletedTag BlackboardArtifactTag deleted + */ + public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { + notify(new BlackBoardArtifactTagDeletedEvent(deletedTag)); + } + + /** + * Notifies the UI about a Case level event. + * + * @param propertyChangeEvent the event to distribute + */ + private void notify(final PropertyChangeEvent propertyChangeEvent) { + try { + pcs.firePropertyChange(propertyChangeEvent); + } + + /** + * Notifies the UI that a new ContentTag has been added. + * + * @param newTag new ContentTag added + */ + public void notifyContentTagAdded(ContentTag newTag) { + notifyPropertyChangeEvent(new ContentTagAddedEvent(newTag)); + } + + /** + * Notifies the UI that a ContentTag has been deleted. + * + * @param deletedTag ContentTag deleted + */ + public void notifyContentTagDeleted(ContentTag deletedTag) { + notifyPropertyChangeEvent(new ContentTagDeletedEvent(deletedTag)); + } + + /** + * Notifies the UI that a new BlackboardArtifactTag has been added. + * + * @param newTag new BlackboardArtifactTag added + */ + public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) { + notifyPropertyChangeEvent(new BlackBoardArtifactTagAddedEvent(newTag)); + } + /** * Notifies the UI that a BlackboardArtifactTag has been. * @@ -547,112 +644,6 @@ public class Case implements SleuthkitCase.ErrorObserver { } } - /** - * Notifies the UI that a new ContentTag has been added. - * - * @param newTag new ContentTag added - */ - public void notifyContentTagAdded(ContentTag newTag) { - notify(new ContentTagAddedEvent(newTag)); - } - - /** - * Notifies the UI that a ContentTag has been deleted. - * - * @param deletedTag ContentTag deleted - */ - public void notifyContentTagDeleted(ContentTag deletedTag) { - notify(new ContentTagDeletedEvent(deletedTag)); - } - - /** - * Notifies the UI that a new BlackboardArtifactTag has been added. - * - * @param newTag new BlackboardArtifactTag added - */ - public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) { - notify(new BlackBoardArtifactTagAddedEvent(newTag)); - } - - /** - * Notifies the UI that a BlackboardArtifactTag has been. - * - * @param deletedTag BlackboardArtifactTag deleted - */ - public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { - notify(new BlackBoardArtifactTagDeletedEvent(deletedTag)); - } - - /** - * Notifies the UI about a Case level event. - * - * @param propertyChangeEvent the event to distribute - */ - private void notify(final PropertyChangeEvent propertyChangeEvent) { - try { - pcs.firePropertyChange(propertyChangeEvent); - } catch (Exception e) { - logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), - NbBundle.getMessage(this.getClass(), - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } - } - - /** - * Notifies the UI that a new ContentTag has been added. - * - * @param newTag new ContentTag added - */ - public void notifyContentTagAdded(ContentTag newTag) { - notify(new ContentTagAddedEvent(newTag)); - } - - /** - * Notifies the UI that a ContentTag has been deleted. - * - * @param deletedTag ContentTag deleted - */ - public void notifyContentTagDeleted(ContentTag deletedTag) { - notify(new ContentTagDeletedEvent(deletedTag)); - } - - /** - * Notifies the UI that a new BlackboardArtifactTag has been added. - * - * @param newTag new BlackboardArtifactTag added - */ - public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) { - notify(new BlackBoardArtifactTagAddedEvent(newTag)); - } - - /** - * Notifies the UI that a BlackboardArtifactTag has been. - * - * @param deletedTag BlackboardArtifactTag deleted - */ - public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { - notify(new BlackBoardArtifactTagDeletedEvent(deletedTag)); - } - - /** - * Notifies the UI about a Case level event. - * - * @param propertyChangeEvent the event to distribute - */ - private void notify(final PropertyChangeEvent propertyChangeEvent) { - try { - pcs.firePropertyChange(propertyChangeEvent); - } catch (Exception e) { - logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), - NbBundle.getMessage(this.getClass(), - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } - } - /** * @return The Services object for this case. */ From 5b904edba673bf1251ed6c2f568527b955240616 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 25 Jun 2015 11:07:45 -0400 Subject: [PATCH 180/198] fix merge mistakes --- .../sleuthkit/autopsy/casemodule/Case.java | 97 --------------- .../casemodule/services/TagsManager.java | 2 +- .../imagegallery/ImageGalleryController.java | 17 +-- .../actions/CategorizeAction.java | 18 +-- .../imagegallery/datamodel/Category.java | 4 +- .../datamodel/CategoryManager.java | 4 +- .../datamodel/grouping/GroupManager.java | 117 +++--------------- .../gui/drawableviews/DrawableView.java | 2 +- .../gui/drawableviews/MetaDataPane.java | 30 ++--- 9 files changed, 33 insertions(+), 258 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index d26210177e..b4c61305b2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -521,103 +521,6 @@ public class Case implements SleuthkitCase.ErrorObserver { notifyPropertyChangeEvent(new BlackBoardArtifactTagAddedEvent(newTag)); } - /** - * Notifies the UI that a BlackboardArtifactTag has been. - * - * @param deletedTag BlackboardArtifactTag deleted - */ - public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { - notifyPropertyChangeEvent(new BlackBoardArtifactTagDeletedEvent(deletedTag)); - } - /** - * Notifies the UI about a Case level event. - * - * @param propertyChangeEvent the event to distribute - */ - private void notifyPropertyChangeEvent(final PropertyChangeEvent propertyChangeEvent) { - pcs.firePropertyChange(propertyChangeEvent); - } catch (Exception e) { - logger.log(Level.SEVERE, "Case threw exception", e); //NON-NLS - MessageNotifyUtil.Notify.show(NbBundle.getMessage(this.getClass(), "Case.moduleErr"), - NbBundle.getMessage(this.getClass(), - "Case.changeCase.errListenToCaseUpdates.msg"), - MessageNotifyUtil.MessageType.ERROR); - } - } - - /** - * Notifies the UI that a new ContentTag has been added. - * - * @param newTag new ContentTag added - */ - public void notifyContentTagAdded(ContentTag newTag) { - notify(new ContentTagAddedEvent(newTag)); - } - - /** - * Notifies the UI that a ContentTag has been deleted. - * - * @param deletedTag ContentTag deleted - */ - public void notifyContentTagDeleted(ContentTag deletedTag) { - notify(new ContentTagDeletedEvent(deletedTag)); - } - - /** - * Notifies the UI that a new BlackboardArtifactTag has been added. - * - * @param newTag new BlackboardArtifactTag added - */ - public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) { - notify(new BlackBoardArtifactTagAddedEvent(newTag)); - } - - /** - * Notifies the UI that a BlackboardArtifactTag has been. - * - * @param deletedTag BlackboardArtifactTag deleted - */ - public void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag) { - notify(new BlackBoardArtifactTagDeletedEvent(deletedTag)); - } - - /** - * Notifies the UI about a Case level event. - * - * @param propertyChangeEvent the event to distribute - */ - private void notify(final PropertyChangeEvent propertyChangeEvent) { - try { - pcs.firePropertyChange(propertyChangeEvent); - } - - /** - * Notifies the UI that a new ContentTag has been added. - * - * @param newTag new ContentTag added - */ - public void notifyContentTagAdded(ContentTag newTag) { - notifyPropertyChangeEvent(new ContentTagAddedEvent(newTag)); - } - - /** - * Notifies the UI that a ContentTag has been deleted. - * - * @param deletedTag ContentTag deleted - */ - public void notifyContentTagDeleted(ContentTag deletedTag) { - notifyPropertyChangeEvent(new ContentTagDeletedEvent(deletedTag)); - } - - /** - * Notifies the UI that a new BlackboardArtifactTag has been added. - * - * @param newTag new BlackboardArtifactTag added - */ - public void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag) { - notifyPropertyChangeEvent(new BlackBoardArtifactTagAddedEvent(newTag)); - } - /** * Notifies the UI that a BlackboardArtifactTag has been. * diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index d5ec4fc7c2..01daae9fba 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -253,6 +253,7 @@ public class TagsManager implements Closeable { } catch (IllegalArgumentException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.addContentTag.noCaseWarning")); } + return newContentTag; } /** @@ -403,7 +404,6 @@ public class TagsManager implements Closeable { getExistingTagNames(); } - Case.getPropertyChangeSupport().firePropertyChange(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString(), tag, null); tskCase.deleteBlackboardArtifactTag(tag); try { Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 6752b3a44f..84fe4bef36 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -502,18 +502,7 @@ public final class ImageGalleryController { getTagsManager().fireTagDeletedEvent(tagDeletedEvent); } break; - case CONTENT_TAG_ADDED: - final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt; - if (getDatabase().isInDB((tagAddedEvent).getTag().getContent().getId())) { - getTagsManager().fireTagAddedEvent(tagAddedEvent); - } - break; - case CONTENT_TAG_DELETED: - final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) evt; - if (getDatabase().isInDB((tagDeletedEvent).getTag().getContent().getId())) { - getTagsManager().fireTagDeletedEvent(tagDeletedEvent); - } - break; + } }); } @@ -530,9 +519,7 @@ public final class ImageGalleryController { return tagsManager; } - public DrawableTagsManager getTagsManager() { - return tagsManager; - } + // @@@ REVIEW IF THIS SHOLD BE STATIC... //TODO: concept seems like the controller deal with how much work to do at a given time diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index b9b9cee59f..463ab3a1be 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -144,23 +144,7 @@ public class CategorizeAction extends AddTagAction { LOGGER.log(Level.SEVERE, "Error removing old categories result", ex); } }); - } else { - //add cat tag if no existing cat tag for that cat - if (fileTags.stream() - .map(Tag::getName) - .filter(tagName::equals) - .collect(Collectors.toList()).isEmpty()) { - tagsManager.addContentTag(file, tagName, comment); - } - .filter(tag -> CategoryManager.isCategoryTagName(tag.getName())) - .forEach((ct) -> { - try { - tagsManager.deleteContentTag(ct); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error removing old categories result", ex); - } - }); - } else { + } else { //add cat tag if no existing cat tag for that cat if (fileTags.stream() .map(Tag::getName) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java index 3fd1a6c92c..8999fff2f1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java @@ -48,11 +48,9 @@ public enum Category { public static Category fromDisplayName(String displayName) { return nameMap.get(displayName); } + public static boolean isCategoryName(String tName) { return nameMap.containsKey(tName); - - public static boolean isNotCategoryName(String tName) { - return nameMap.containsKey(tName) == false; } public static boolean isNotCategoryName(String tName) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index d77d9583ce..f6ab66fa04 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -25,7 +25,6 @@ import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import java.util.Collection; import java.util.Collections; -import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.atomic.LongAdder; import java.util.logging.Level; @@ -57,7 +56,7 @@ public class CategoryManager { private final ImageGalleryController controller; - private final ImageGalleryController controller; + /** * the DrawableDB that backs the category counts cache. The counts are @@ -262,7 +261,6 @@ public class CategoryManager { } } - @Subscribe @Subscribe public void handleTagDeleted(ContentTagDeletedEvent event) { ContentTag deleted = event.getTag(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index 0fbf76a64e..ec63a51740 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -36,6 +36,7 @@ import java.util.TreeSet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; import javafx.application.Platform; @@ -44,6 +45,12 @@ import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.transformation.SortedList; +import static javafx.concurrent.Worker.State.CANCELLED; +import static javafx.concurrent.Worker.State.FAILED; +import static javafx.concurrent.Worker.State.READY; +import static javafx.concurrent.Worker.State.RUNNING; +import static javafx.concurrent.Worker.State.SCHEDULED; +import static javafx.concurrent.Worker.State.SUCCEEDED; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; @@ -56,7 +63,6 @@ import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.LoggedTask; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; @@ -244,10 +250,11 @@ public class GroupManager { * 'mark' the given group as seen. This removes it from the queue of * groups * files. - public DrawableGroup makeGroup(GroupKey groupKey, Set files) { - - Set newFiles = ObjectUtils.defaultIfNull(files, new HashSet()); - } + * public DrawableGroup makeGroup(GroupKey groupKey, Set files) { + * + * Set newFiles = ObjectUtils.defaultIfNull(files, new + * HashSet()); + * } * groups * to review, and is persisted in the drawable db. * @@ -255,8 +262,7 @@ public class GroupManager { */ @ThreadConfined(type = ThreadType.JFX) public void markGroupSeen(DrawableGroup group, boolean seen) { - public void markGroupSeen(DrawableGroup group, boolean seen - ) { + db.markGroupSeen(group.getGroupKey(), seen); group.setSeen(seen); if (seen) { @@ -292,19 +298,15 @@ public class GroupManager { if (unSeenGroups.contains(group)) { unSeenGroups.remove(group); } - } + }); } - } else { //group == null - // It may be that this was the last unanalyzed file in the group, so test - // whether the group is now fully analyzed. - popuplateIfAnalyzed(groupKey, null); + } else { //group == null + // It may be that this was the last unanalyzed file in the group, so test + // whether the group is now fully analyzed. + popuplateIfAnalyzed(groupKey, null); } - } else { //group == null - // It may be that this was the last unanalyzed file in the group, so test - // whether the group is now fully analyzed. - popuplateIfAnalyzed(groupKey, null); - + } return group; } @@ -584,42 +586,6 @@ public class GroupManager { } } - @Subscribe - public void handleTagAdded(ContentTagAddedEvent evt) { - GroupKey newGroupKey = null; - final long fileID = evt.getTag().getContent().getId(); - if (groupBy == DrawableAttribute.CATEGORY && CategoryManager.isCategoryTagName(evt.getTag().getName())) { - newGroupKey = new GroupKey(DrawableAttribute.CATEGORY, CategoryManager.categoryFromTagName(evt.getTag().getName())); - for (GroupKey oldGroupKey : groupMap.keySet()) { - if (oldGroupKey.equals(newGroupKey) == false) { - removeFromGroup(oldGroupKey, fileID); - } - } - } else if (groupBy == DrawableAttribute.TAGS && CategoryManager.isNotCategoryTagName(evt.getTag().getName())) { - newGroupKey = new GroupKey(DrawableAttribute.TAGS, evt.getTag().getName()); - } - if (newGroupKey != null) { - DrawableGroup g = getGroupForKey(newGroupKey); - addFileToGroup(g, newGroupKey, fileID); - } - } - - @SuppressWarnings("AssignmentToMethodParameter") - private void addFileToGroup(DrawableGroup g, final GroupKey groupKey, final long fileID) { - if (g == null) { - //if there wasn't already a group check if there should be one now - g = popuplateIfAnalyzed(groupKey, null); - } - DrawableGroup group = g; - if (group != null) { - //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. - Platform.runLater(() -> { - group.addFile(fileID); - }); - - } - } - @Subscribe public void handleTagDeleted(ContentTagDeletedEvent evt) { GroupKey groupKey = null; @@ -633,8 +599,6 @@ public class GroupManager { DrawableGroup g = removeFromGroup(groupKey, fileID); } } - } - } @Subscribe synchronized public void handleFileRemoved(Collection removedFileIDs) { @@ -678,49 +642,6 @@ public class GroupManager { //we fire this event for all files so that the category counts get updated during initial db population controller.getCategoryManager().fireChange(updatedFileIDs, null); } - private DrawableGroup popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { - - if (Objects.nonNull(task) && (task.isCancelled())) { - /* if this method call is part of a ReGroupTask and that task is - * cancelled, no-op - * - * this allows us to stop if a regroup task has been cancelled (e.g. - * the user picked a different group by attribute, while the - * current task was still running) */ - - } else { // no task or un-cancelled task - if ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey)) { - /* for attributes other than path we can't be sure a group is - * fully analyzed because we don't know all the files that - * will be a part of that group,. just show them no matter what. */ - - try { - Set fileIDs = getFileIDsInGroup(groupKey); - if (Objects.nonNull(fileIDs)) { - DrawableGroup group; - final boolean groupSeen = db.isGroupSeen(groupKey); - synchronized (groupMap) { - if (groupMap.containsKey(groupKey)) { - group = groupMap.get(groupKey); - group.setFiles(ObjectUtils.defaultIfNull(fileIDs, Collections.emptySet())); - } else { - group = new DrawableGroup(groupKey, fileIDs, groupSeen); - group.seenProperty().addListener((o, oldSeen, newSeen) -> { - markGroupSeen(group, newSeen); - }); - groupMap.put(groupKey, group); - } - Platform.runLater(() -> { - if (analyzedGroups.contains(group) == false) { - analyzedGroups.add(group); - } - markGroupSeen(group, groupSeen); - }); - return group; - } - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); - } private DrawableGroup popuplateIfAnalyzed(GroupKey groupKey, ReGroupTask task) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java index 37737675e5..4d7f31a52a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java @@ -1,7 +1,7 @@ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.eventbus.Subscribe; -import java.util.Optional; +import java.util.Collection; import java.util.Optional; import java.util.logging.Level; import javafx.application.Platform; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index 095ec88495..3e8a228c64 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -18,13 +18,14 @@ */ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; + import com.google.common.eventbus.Subscribe; import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.Objects; import java.util.Optional; -import java.util.Optional; +import java.util.logging.Logger; import java.util.stream.Collectors; import javafx.application.Platform; import javafx.beans.property.SimpleObjectProperty; @@ -40,18 +41,16 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Region; -import static javafx.scene.layout.Region.USE_COMPUTED_SIZE; import javafx.scene.text.Text; import javafx.util.Pair; import org.apache.commons.lang3.StringUtils; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.events.TagEvent; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.Category; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -87,7 +86,7 @@ public class MetaDataPane extends DrawableUIBase { fxmlLoader.load(); } catch (IOException exception) { throw new RuntimeException(exception); - } + } } @@ -151,9 +150,9 @@ public class MetaDataPane extends DrawableUIBase { }); } +@Override protected synchronized void setFileHelper(Long newFileID) { setFileIDOpt(Optional.ofNullable(newFileID)); - if (newFileID == null) { if (newFileID == null) { Platform.runLater(() -> { imageView.setImage(null); @@ -221,22 +220,7 @@ public class MetaDataPane extends DrawableUIBase { }); } - @Subscribe - @Override - public void handleTagDeleted(ContentTagDeletedEvent evt) { - handleTagEvent(evt, this::updateUI); - } + - /** - * - * @param tagFileID the value of tagEvent - * @param runnable the value of runnable - */ - void handleTagEvent(TagEvent tagEvent, final Runnable runnable) { - getFileID().ifPresent(fileID -> { - if (Objects.equals(tagEvent.getTag().getContent().getId(), fileID)) { - runnable.run(); - } - }); - } + } From 9a385b6d7bda53d3aefb5c1baf368a5576e3e6ab Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 25 Jun 2015 21:34:01 -0400 Subject: [PATCH 181/198] Added full path to error and warning messages for ZIP extraction --- .../embeddedfileextractor/Bundle.properties | 4 +- .../Bundle_ja.properties | 58 +++++++++---------- .../SevenZipExtractor.java | 57 ++++++++++-------- 3 files changed, 64 insertions(+), 55 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties index 177f651867..c8904ee1aa 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle.properties @@ -17,9 +17,9 @@ EmbeddedFileExtractorIngestModule.ArchiveExtractor.init.errInitModule.msg=Error EmbeddedFileExtractorIngestModule.ArchiveExtractor.init.errInitModule.details=Error initializing output dir\: {0}\: {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.init.errCantInitLib=Could not initialize 7-ZIP library\: {0} EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg=Possible ZIP bomb detected in archive\: {0}, item\: {1} -EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnDetails=The archive item compression ratio is {0}, skipping processing of this archive item. +EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnDetails=Compression ratio is {0}, skipping item in {1}. EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnMsg.zipBomb=Possible ZIP bomb detected\: {0} -EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnDetails.zipBomb=The archive is {0} levels deep, skipping processing of this archive and its contents +EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnDetails.zipBomb=The archive is {0} levels deep, skipping processing of {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.unknownPath.msg=Unknown item path in archive\: {0}, will use\: {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.msg=Not enough disk space to unpack archive item\: {0}, {1} EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.details=The archive item is too large to unpack, skipping unpacking this item. diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle_ja.properties index 67303202ff..9f25567758 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/Bundle_ja.properties @@ -1,31 +1,31 @@ -OpenIDE-Module-Display-Category=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB +OpenIDE-Module-Display-Category=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb OpenIDE-Module-Long-Description=\ - 7Zip\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\n\n7Zip\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\u306F\u30A2\u30FC\u30AB\u30A4\u30D6\u30D5\u30A1\u30A4\u30EB\u3092\u51E6\u7406\u3057\u307E\u3059\uFF08zip\u30847zip\u30A8\u30AF\u30B9\u30C8\u30E9\u30AF\u30BF\u30FC\u306B\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u308B\u305D\u306E\u4ED6\u306E\u30A2\u30FC\u30AB\u30A4\u30D6\u30BF\u30A4\u30D7\u306A\u3069\uFF09\u3002\n\ - \u30A2\u30FC\u30AB\u30A4\u30D6\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u306F\u62BD\u51FA\u3055\u308C\u3001\u6D3E\u751F\u30D5\u30A1\u30A4\u30EB\u306F\u8A2D\u5B9A\u3055\u308C\u305F\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB\u306B\u51E6\u7406\u3055\u308C\u308B\u305F\u3081\u3001\u73FE\u5728\u306E\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u306B\u8FFD\u52A0\u3055\u308C\u307E\u3059\u3002\n\ - \u3082\u3057\u6D3E\u751F\u30D5\u30A1\u30A4\u30EB\u304C\u30A2\u30FC\u30AB\u30A4\u30D6\u30D5\u30A1\u30A4\u30EB\u3067\u3042\u308C\u3070\u30017Zip\u30A8\u30AF\u30B9\u30C8\u30E9\u30AF\u30BF\u30FC\u306B\u3088\u308A\u3001\u518D\u5EA6\u51E6\u7406\u3055\u308C\u307E\u3059 - \u30A8\u30AF\u30B9\u30C8\u30E9\u30AF\u30BF\u30FC\u306F\u30A2\u30FC\u30AB\u30A4\u30D6\u30D5\u30A1\u30A4\u30EB\u3092N-\u30EC\u30D9\u30EB\u306E\u6DF1\u3055\u3067\u51E6\u7406\u3057\u307E\u3059\u3002\n\n\ - \u62BD\u51FA\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB\u306F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u30C4\u30EA\u30FC\u3067\u30CA\u30D3\u30B2\u30FC\u30C8\u3067\u304D\u307E\u3059\u3002\n\n\ - \u3053\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u306FWindows\u3001Linux\u3001Mac\u306E\u30AA\u30DA\u30EC\u30FC\u30C6\u30A3\u30F3\u30B0\u30B7\u30B9\u30C6\u30E0\u74B0\u5883\u3092\u30B5\u30DD\u30FC\u30C8\u3057\u3066\u3044\u307E\u3059\u3002 + 7Zip\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\n\n7Zip\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u306f\u30a2\u30fc\u30ab\u30a4\u30d6\u30d5\u30a1\u30a4\u30eb\u3092\u51e6\u7406\u3057\u307e\u3059\uff08zip\u30847zip\u30a8\u30af\u30b9\u30c8\u30e9\u30af\u30bf\u30fc\u306b\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u308b\u305d\u306e\u4ed6\u306e\u30a2\u30fc\u30ab\u30a4\u30d6\u30bf\u30a4\u30d7\u306a\u3069\uff09\u3002\n\ + \u30a2\u30fc\u30ab\u30a4\u30d6\u306e\u30b3\u30f3\u30c6\u30f3\u30c4\u306f\u62bd\u51fa\u3055\u308c\u3001\u6d3e\u751f\u30d5\u30a1\u30a4\u30eb\u306f\u8a2d\u5b9a\u3055\u308c\u305f\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u306b\u51e6\u7406\u3055\u308c\u308b\u305f\u3081\u3001\u73fe\u5728\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u306b\u8ffd\u52a0\u3055\u308c\u307e\u3059\u3002\n\ + \u3082\u3057\u6d3e\u751f\u30d5\u30a1\u30a4\u30eb\u304c\u30a2\u30fc\u30ab\u30a4\u30d6\u30d5\u30a1\u30a4\u30eb\u3067\u3042\u308c\u3070\u30017Zip\u30a8\u30af\u30b9\u30c8\u30e9\u30af\u30bf\u30fc\u306b\u3088\u308a\u3001\u518d\u5ea6\u51e6\u7406\u3055\u308c\u307e\u3059 - \u30a8\u30af\u30b9\u30c8\u30e9\u30af\u30bf\u30fc\u306f\u30a2\u30fc\u30ab\u30a4\u30d6\u30d5\u30a1\u30a4\u30eb\u3092N-\u30ec\u30d9\u30eb\u306e\u6df1\u3055\u3067\u51e6\u7406\u3057\u307e\u3059\u3002\n\n\ + \u62bd\u51fa\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb\u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30c4\u30ea\u30fc\u3067\u30ca\u30d3\u30b2\u30fc\u30c8\u3067\u304d\u307e\u3059\u3002\n\n\ + \u3053\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u306fWindows\u3001Linux\u3001Mac\u306e\u30aa\u30da\u30ec\u30fc\u30c6\u30a3\u30f3\u30b0\u30b7\u30b9\u30c6\u30e0\u74b0\u5883\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u3059\u3002 OpenIDE-Module-Name=7Zip -OpenIDE-Module-Short-Description=7Zip\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30E2\u30B8\u30E5\u30FC\u30EB -SevenZipContentReadStream.seek.exception.invalidOrigin=\u7121\u52B9\u306A\u30B7\u30FC\u30AF\u30AA\u30EA\u30B8\u30F3\uFF1A {0} -SevenZipContentReadStream.read.exception.errReadStream=\u30B3\u30F3\u30C6\u30F3\u30C4\u30B9\u30C8\u30EA\u30FC\u30E0\u306E\u8AAD\u307F\u53D6\u308A\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002 -SevenZipIngestModule.moduleName=\u30A2\u30FC\u30AB\u30A4\u30D6\u30A8\u30AF\u30B9\u30C8\u30E9\u30AF\u30BF\u30FC -SevenZipIngestModule.moduleDesc.text=\u30A2\u30FC\u30AB\u30A4\u30D6\u30D5\u30A1\u30A4\u30EB(zip, rar, arj, 7z, gzip, bzip2, tar)\u3092\u62BD\u51FA\u3057\u3001\u73FE\u5728\u306E\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u306B\u30EA\u30B9\u30B1\u3057\u3001\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u30C4\u30EA\u30FC\u306B\u65B0\u898F\u30D5\u30A1\u30A4\u30EB\u3092\u6295\u5165\u3057\u307E\u3059\u3002 -SevenZipIngestModule.encryptionFileLevel=\u30D5\u30A1\u30A4\u30EB\u30EC\u30D9\u30EB\u6697\u53F7\u5316 -SevenZipIngestModule.encryptionFull=\u5168\u4F53\u6697\u53F7\u5316 -SevenZipIngestModule.init.errInitModule.msg={0}\u306E\u521D\u671F\u5316\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F -SevenZipIngestModule.init.errInitModule.details=\u30A2\u30A6\u30C8\u30D7\u30C3\u30C8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\: {0}\: {1}\u306E\u521D\u671F\u5316\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F -SevenZipIngestModule.init.errCantInitLib=7-Zip\u30E9\u30A4\u30D6\u30E9\u30EA\: {0}\u3092\u521D\u671F\u5316\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F -SevenZipIngestModule.isZipBombCheck.warnMsg=Zip\u7206\u5F3E\u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u3082\u306E\u304C\u30A2\u30FC\u30AB\u30A4\u30D6\: {0}, item\: {1}\u306B\u691C\u51FA\u3055\u308C\u307E\u3057\u305F -SevenZipIngestModule.isZipBombCheck.warnDetails=\u30A2\u30FC\u30AB\u30A4\u30D6\u30A2\u30A4\u30C6\u30E0\u306E\u5727\u7E2E\u7387\u306F{0}\u3001\u3053\u306E\u30A2\u30FC\u30AB\u30A4\u30D6\u30A2\u30A4\u30C6\u30E0\u306E\u51E6\u7406\u3092\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3059\u3002 -SevenZipIngestModule.unpack.warnMsg.zipBomb=Zip\u7206\u5F3E\u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u3082\u306E\u304C\u691C\u51FA\u3055\u308C\u307E\u3057\u305F\uFF1A {0} -SevenZipIngestModule.unpack.warnDetails.zipBomb=\u30A2\u30FC\u30AB\u30A4\u30D6\u306F {0}\u30EC\u30D9\u30EB\u306E\u6DF1\u3055\u3067\u3059\u3001\u3053\u306E\u30A2\u30FC\u30AB\u30A4\u30D6\u3068\u305D\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u306E\u51E6\u7406\u3092\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3059 -SevenZipIngestModule.unpack.unknownPath.msg=\u30A2\u30FC\u30AB\u30A4\u30D6\: {0}\u306B\u4E0D\u660E\u306E\u30A2\u30A4\u30C6\u30E0\u30D1\u30B9\u304C\u5B58\u5728\u3057\u307E\u3059\u3001{1}\u3092\u4F7F\u7528\u3057\u307E\u3059 -SevenZipIngestModule.unpack.notEnoughDiskSpace.msg=\u30A2\u30FC\u30AB\u30A4\u30D6\u30A2\u30A4\u30C6\u30E0\: {0}, {1}\u3092\u89E3\u51CD\u3059\u308B\u306E\u306B\u5341\u5206\u306A\u30C7\u30A3\u30B9\u30AF\u30B9\u30DA\u30FC\u30B9\u304C\u3042\u308A\u307E\u305B\u3093 -SevenZipIngestModule.unpack.notEnoughDiskSpace.details=\u30A2\u30FC\u30AB\u30A4\u30D6\u30A2\u30A4\u30C6\u30E0\u306F\u89E3\u51CD\u3059\u308B\u306E\u306B\u5927\u304D\u3059\u304E\u307E\u3059\u3001\u3053\u306E\u30A2\u30A4\u30C6\u30E0\u306E\u89E3\u51CD\u3092\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3059\u3002 -SevenZipIngestModule.unpack.errUnpacking.msg={0}\u89E3\u51CD\u30A8\u30E9\u30FC -SevenZipIngestModule.unpack.errUnpacking.details={0}. {1}\u306E\u89E3\u51CD\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F -SevenZipIngestModule.unpack.encrFileDetected.msg=\u30A2\u30FC\u30AB\u30A4\u30D6\u306B\u6697\u53F7\u5316\u30D5\u30A1\u30A4\u30EB\u304C\u691C\u51FA\u3055\u308C\u307E\u3057\u305F\u3002 -SevenZipIngestModule.unpack.encrFileDetected.details=\u30A2\u30FC\u30AB\u30A4\u30D6\: {0}\u306E\u4E00\u90E8\u306E\u30D5\u30A1\u30A4\u30EB\u304C\u6697\u53F7\u5316\u3055\u308C\u3066\u3044\u307E\u3059\u3002{1}\u30A8\u30AF\u30B9\u30C8\u30E9\u30AF\u30BF\u30FC\u306F\u3053\u306E\u30A2\u30FC\u30AB\u30A4\u30D6\u304B\u3089\u5168\u3066\u306E\u30D5\u30A1\u30A4\u30EB\u306F\u62BD\u51FA\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -SevenZipIngestModule.UnpackStream.write.exception.msg=\u89E3\u51CD\u3057\u305F\u30D5\u30A1\u30A4\u30EB\u306E\u4E0B\u8A18\u3078\u306E\u66F8\u304D\u8FBC\u307F\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\: {0} -SevenZipIngestModule.UnpackedTree.exception.msg=\u6D3E\u751F\u30D5\u30A1\u30A4\u30EB\u3092\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\:{0}\u306B\u8FFD\u52A0\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F \ No newline at end of file +OpenIDE-Module-Short-Description=7Zip\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb +SevenZipContentReadStream.seek.exception.invalidOrigin=\u7121\u52b9\u306a\u30b7\u30fc\u30af\u30aa\u30ea\u30b8\u30f3\uff1a {0} +SevenZipContentReadStream.read.exception.errReadStream=\u30b3\u30f3\u30c6\u30f3\u30c4\u30b9\u30c8\u30ea\u30fc\u30e0\u306e\u8aad\u307f\u53d6\u308a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +SevenZipIngestModule.moduleName=\u30a2\u30fc\u30ab\u30a4\u30d6\u30a8\u30af\u30b9\u30c8\u30e9\u30af\u30bf\u30fc +SevenZipIngestModule.moduleDesc.text=\u30a2\u30fc\u30ab\u30a4\u30d6\u30d5\u30a1\u30a4\u30eb(zip, rar, arj, 7z, gzip, bzip2, tar)\u3092\u62bd\u51fa\u3057\u3001\u73fe\u5728\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u306b\u30ea\u30b9\u30b1\u3057\u3001\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30c4\u30ea\u30fc\u306b\u65b0\u898f\u30d5\u30a1\u30a4\u30eb\u3092\u6295\u5165\u3057\u307e\u3059\u3002 +SevenZipIngestModule.encryptionFileLevel=\u30d5\u30a1\u30a4\u30eb\u30ec\u30d9\u30eb\u6697\u53f7\u5316 +SevenZipIngestModule.encryptionFull=\u5168\u4f53\u6697\u53f7\u5316 +SevenZipIngestModule.init.errInitModule.msg={0}\u306e\u521d\u671f\u5316\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +SevenZipIngestModule.init.errInitModule.details=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\: {0}\: {1}\u306e\u521d\u671f\u5316\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +SevenZipIngestModule.init.errCantInitLib=7-Zip\u30e9\u30a4\u30d6\u30e9\u30ea\: {0}\u3092\u521d\u671f\u5316\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f +SevenZipIngestModule.isZipBombCheck.warnMsg=Zip\u7206\u5f3e\u306e\u53ef\u80fd\u6027\u304c\u3042\u308b\u3082\u306e\u304c\u30a2\u30fc\u30ab\u30a4\u30d6\: {0}, item\: {1}\u306b\u691c\u51fa\u3055\u308c\u307e\u3057\u305f +SevenZipIngestModule.isZipBombCheck.warnDetails=\u30a2\u30fc\u30ab\u30a4\u30d6\u30a2\u30a4\u30c6\u30e0\u306e\u5727\u7e2e\u7387\u306f{0}\u3001\u3053\u306e\u30a2\u30fc\u30ab\u30a4\u30d6\u30a2\u30a4\u30c6\u30e0\u306e\u51e6\u7406\u3092\u30b9\u30ad\u30c3\u30d7\u3057\u307e\u3059\u3002{1} +SevenZipIngestModule.unpack.warnMsg.zipBomb=Zip\u7206\u5f3e\u306e\u53ef\u80fd\u6027\u304c\u3042\u308b\u3082\u306e\u304c\u691c\u51fa\u3055\u308c\u307e\u3057\u305f\uff1a {0} +SevenZipIngestModule.unpack.warnDetails.zipBomb=\u30a2\u30fc\u30ab\u30a4\u30d6\u306f {0}\u30ec\u30d9\u30eb\u306e\u6df1\u3055\u3067\u3059\u3001\u3053\u306e\u30a2\u30fc\u30ab\u30a4\u30d6\u3068\u305d\u306e\u30b3\u30f3\u30c6\u30f3\u30c4\u306e\u51e6\u7406\u3092\u30b9\u30ad\u30c3\u30d7\u3057\u307e\u3059 {1} +SevenZipIngestModule.unpack.unknownPath.msg=\u30a2\u30fc\u30ab\u30a4\u30d6\: {0}\u306b\u4e0d\u660e\u306e\u30a2\u30a4\u30c6\u30e0\u30d1\u30b9\u304c\u5b58\u5728\u3057\u307e\u3059\u3001{1}\u3092\u4f7f\u7528\u3057\u307e\u3059 +SevenZipIngestModule.unpack.notEnoughDiskSpace.msg=\u30a2\u30fc\u30ab\u30a4\u30d6\u30a2\u30a4\u30c6\u30e0\: {0}, {1}\u3092\u89e3\u51cd\u3059\u308b\u306e\u306b\u5341\u5206\u306a\u30c7\u30a3\u30b9\u30af\u30b9\u30da\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093 +SevenZipIngestModule.unpack.notEnoughDiskSpace.details=\u30a2\u30fc\u30ab\u30a4\u30d6\u30a2\u30a4\u30c6\u30e0\u306f\u89e3\u51cd\u3059\u308b\u306e\u306b\u5927\u304d\u3059\u304e\u307e\u3059\u3001\u3053\u306e\u30a2\u30a4\u30c6\u30e0\u306e\u89e3\u51cd\u3092\u30b9\u30ad\u30c3\u30d7\u3057\u307e\u3059\u3002 +SevenZipIngestModule.unpack.errUnpacking.msg={0}\u89e3\u51cd\u30a8\u30e9\u30fc +SevenZipIngestModule.unpack.errUnpacking.details={0}. {1}\u306e\u89e3\u51cd\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +SevenZipIngestModule.unpack.encrFileDetected.msg=\u30a2\u30fc\u30ab\u30a4\u30d6\u306b\u6697\u53f7\u5316\u30d5\u30a1\u30a4\u30eb\u304c\u691c\u51fa\u3055\u308c\u307e\u3057\u305f\u3002 +SevenZipIngestModule.unpack.encrFileDetected.details=\u30a2\u30fc\u30ab\u30a4\u30d6\: {0}\u306e\u4e00\u90e8\u306e\u30d5\u30a1\u30a4\u30eb\u304c\u6697\u53f7\u5316\u3055\u308c\u3066\u3044\u307e\u3059\u3002{1}\u30a8\u30af\u30b9\u30c8\u30e9\u30af\u30bf\u30fc\u306f\u3053\u306e\u30a2\u30fc\u30ab\u30a4\u30d6\u304b\u3089\u5168\u3066\u306e\u30d5\u30a1\u30a4\u30eb\u306f\u62bd\u51fa\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 +SevenZipIngestModule.UnpackStream.write.exception.msg=\u89e3\u51cd\u3057\u305f\u30d5\u30a1\u30a4\u30eb\u306e\u4e0b\u8a18\u3078\u306e\u66f8\u304d\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\: {0} +SevenZipIngestModule.UnpackedTree.exception.msg=\u6d3e\u751f\u30d5\u30a1\u30a4\u30eb\u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\:{0}\u306b\u8ffd\u52a0\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index 953d138fb7..ad34ef2611 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -40,6 +40,7 @@ import net.sf.sevenzipjbinding.simple.ISimpleInArchive; import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.FileManager; @@ -178,7 +179,7 @@ class SevenZipExtractor { * @param archiveFileItem the archive item * @return true if potential zip bomb, false otherwise */ - private boolean isZipBombArchiveItemCheck(String archiveName, ISimpleInArchiveItem archiveFileItem) { + private boolean isZipBombArchiveItemCheck(AbstractFile archiveFile, ISimpleInArchiveItem archiveFileItem) { try { final Long archiveItemSize = archiveFileItem.getSize(); @@ -190,19 +191,25 @@ class SevenZipExtractor { final Long archiveItemPackedSize = archiveFileItem.getPackedSize(); if (archiveItemPackedSize == null || archiveItemPackedSize <= 0) { - logger.log(Level.WARNING, "Cannot getting compression ratio, cannot detect if zipbomb: {0}, item: {1}", new Object[]{archiveName, archiveFileItem.getPath()}); //NON-NLS + logger.log(Level.WARNING, "Cannot getting compression ratio, cannot detect if zipbomb: {0}, item: {1}", new Object[]{archiveFile.getName(), archiveFileItem.getPath()}); //NON-NLS return false; } - + int cRatio = (int) (archiveItemSize / archiveItemPackedSize); if (cRatio >= MAX_COMPRESSION_RATIO) { String itemName = archiveFileItem.getPath(); logger.log(Level.INFO, "Possible zip bomb detected, compression ration: {0} for in archive item: {1}", new Object[]{cRatio, itemName}); //NON-NLS String msg = NbBundle.getMessage(this.getClass(), - "EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg", archiveName, itemName); + "EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg", archiveFile.getName(), itemName); + String path; + try { + path = archiveFile.getUniquePath(); + } catch (TskCoreException ex) { + path = archiveFile.getParentPath() + archiveFile.getName(); + } String details = NbBundle.getMessage(this.getClass(), - "EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnDetails", cRatio); + "EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnDetails", cRatio, path); //MessageNotifyUtil.Notify.error(msg, details); services.postMessage(IngestMessage.createWarningMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details)); return true; @@ -269,20 +276,28 @@ class SevenZipExtractor { * @return list of unpacked derived files */ void unpack(AbstractFile archiveFile) { + String archiveFilePath; + try { + archiveFilePath = archiveFile.getUniquePath(); + } catch (TskCoreException ex) { + archiveFilePath = archiveFile.getParentPath() + archiveFile.getName(); + } + //check if already has derived files, skip try { if (archiveFile.hasChildren()) { //check if local unpacked dir exists if (new File(EmbeddedFileExtractorIngestModule.getUniqueName(archiveFile)).exists()) { - logger.log(Level.INFO, "File already has been processed as it has children and local unpacked file, skipping: {0}", archiveFile.getName()); //NON-NLS + logger.log(Level.INFO, "File already has been processed as it has children and local unpacked file, skipping: {0}", archiveFilePath); //NON-NLS return; } } } catch (TskCoreException e) { - logger.log(Level.INFO, "Error checking if file already has been processed, skipping: {0}", archiveFile.getName()); //NON-NLS + logger.log(Level.INFO, "Error checking if file already has been processed, skipping: {0}", archiveFilePath); //NON-NLS return; } - + + List unpackedFiles = Collections.emptyList(); //recursion depth check for zip bomb @@ -295,7 +310,7 @@ class SevenZipExtractor { "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnMsg.zipBomb", archiveFile.getName()); String details = NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnDetails.zipBomb", - parentAr.getDepth()); + parentAr.getDepth(), archiveFilePath); //MessageNotifyUtil.Notify.error(msg, details); services.postMessage(IngestMessage.createWarningMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details)); return; @@ -322,7 +337,7 @@ class SevenZipExtractor { inArchive = SevenZip.openInArchive(options, stream); int numItems = inArchive.getNumberOfItems(); - logger.log(Level.INFO, "Count of items in archive: {0}: {1}", new Object[]{archiveFile.getName(), numItems}); //NON-NLS + logger.log(Level.INFO, "Count of items in archive: {0}: {1}", new Object[]{archiveFilePath, numItems}); //NON-NLS progress.start(numItems); progressStarted = true; @@ -381,7 +396,7 @@ class SevenZipExtractor { } String msg = NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.unknownPath.msg", - archiveFile.getName(), pathInArchive); + archiveFilePath, pathInArchive); logger.log(Level.WARNING, msg); } @@ -389,7 +404,7 @@ class SevenZipExtractor { logger.log(Level.INFO, "Extracted item path: {0}", pathInArchive); //NON-NLS //check if possible zip bomb - if (isZipBombArchiveItemCheck(archiveFile.getName(), item)) { + if (isZipBombArchiveItemCheck(archiveFile, item)) { continue; //skip the item } @@ -428,12 +443,12 @@ class SevenZipExtractor { if (newDiskSpace < MIN_FREE_DISK_SPACE) { String msg = NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.msg", - archiveFile.getName(), fileName); + archiveFilePath, fileName); String details = NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.details"); //MessageNotifyUtil.Notify.error(msg, details); services.postMessage(IngestMessage.createErrorMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details)); - logger.log(Level.INFO, "Skipping archive item due to insufficient disk space: {0}, {1}", new Object[]{archiveFile.getUniquePath(), fileName}); //NON-NLS + logger.log(Level.INFO, "Skipping archive item due to insufficient disk space: {0}, {1}", new Object[]{archiveFilePath, fileName}); //NON-NLS logger.log(Level.INFO, "Available disk space: {0}", new Object[]{freeDiskSpace}); //NON-NLS continue; //skip this file } else { @@ -523,23 +538,17 @@ class SevenZipExtractor { //TODO decide if anything to cleanup, for now bailing } - } catch (SevenZipException | TskCoreException ex) { + } catch (SevenZipException ex) { logger.log(Level.SEVERE, "Error unpacking file: " + archiveFile, ex); //NON-NLS //inbox message - String fullName; - try { - fullName = archiveFile.getUniquePath(); - } catch (TskCoreException ex1) { - fullName = archiveFile.getName(); - } - + // print a message if the file is allocated if (archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) { String msg = NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.msg", archiveFile.getName()); String details = NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.details", - fullName, ex.getMessage()); + archiveFilePath, ex.getMessage()); services.postMessage(IngestMessage.createErrorMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details)); } } finally { @@ -573,7 +582,7 @@ class SevenZipExtractor { artifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), EmbeddedFileExtractorModuleFactory.getModuleName(), encryptionType)); services.fireModuleDataEvent(new ModuleDataEvent(EmbeddedFileExtractorModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED)); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error creating blackboard artifact for encryption detected for file: " + archiveFile, ex); //NON-NLS + logger.log(Level.SEVERE, "Error creating blackboard artifact for encryption detected for file: " + archiveFilePath, ex); //NON-NLS } String msg = NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.encrFileDetected.msg"); From 53fac9b8a4363f0b3b69f979306b00762b9c99c7 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 25 Jun 2015 22:55:23 -0400 Subject: [PATCH 182/198] Added event firing after creating aftifact into sample and made multi-line --- pythonExamples/fileIngestModule.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/pythonExamples/fileIngestModule.py b/pythonExamples/fileIngestModule.py index a8194803a8..ae814653b4 100755 --- a/pythonExamples/fileIngestModule.py +++ b/pythonExamples/fileIngestModule.py @@ -48,6 +48,7 @@ from org.sleuthkit.autopsy.ingest import FileIngestModule from org.sleuthkit.autopsy.ingest import IngestModuleFactoryAdapter from org.sleuthkit.autopsy.ingest import IngestMessage from org.sleuthkit.autopsy.ingest import IngestServices +from org.sleuthkit.autopsy.ingest import ModuleDataEvent from org.sleuthkit.autopsy.coreutils import Logger from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.casemodule.services import Services @@ -107,7 +108,9 @@ class SampleJythonFileIngestModule(FileIngestModule): # TODO: Add your analysis code in here. def process(self, file): # Skip non-files - if ((file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) or (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) or (file.isFile() == False)): + if ((file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) or + (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) or + (file.isFile() == False)): return IngestModule.ProcessResult.OK # For an example, we will flag files with .txt in the name and make a blackboard artifact. @@ -117,10 +120,16 @@ class SampleJythonFileIngestModule(FileIngestModule): self.filesFound+=1 # Make an artifact on the blackboard. TSK_INTERESTING_FILE_HIT is a generic type of - # artfiact. Refer to the developer docs for other examples. + # artifact. Refer to the developer docs for other examples. art = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT) - att = BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), SampleJythonFileIngestModuleFactory.moduleName, "Text Files") + att = BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), + SampleJythonFileIngestModuleFactory.moduleName, "Text Files") art.addAttribute(att) + + # Fire an event to notify the UI and others that there is a new artifact + IngestServices.getInstance().fireModuleDataEvent( + ModuleDataEvent(SampleJythonFileIngestModuleFactory.moduleName, + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, None)); # For the example (this wouldn't be needed normally), we'll query the blackboard for data that was added # by other modules. We then iterate over its attributes. We'll just print them, but you would probably @@ -146,5 +155,7 @@ class SampleJythonFileIngestModule(FileIngestModule): # TODO: Add any shutdown code that you need here. def shutDown(self): # As a final part of this example, we'll send a message to the ingest inbox with the number of files found (in this thread) - message = IngestMessage.createMessage(IngestMessage.MessageType.DATA, SampleJythonFileIngestModuleFactory.moduleName, str(self.filesFound) + " files found") + message = IngestMessage.createMessage( + IngestMessage.MessageType.DATA, SampleJythonFileIngestModuleFactory.moduleName, + str(self.filesFound) + " files found") ingestServices = IngestServices.getInstance().postMessage(message) From 72ba0cad26d209fd379e9eca2d42c99fb8a09bb0 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 26 Jun 2015 12:03:10 -0400 Subject: [PATCH 183/198] Add timestamps to notifications --- .../autopsy/coreutils/MessageNotifyUtil.java | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java index 558167c2bb..498115f310 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2015 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,8 +20,10 @@ package org.sleuthkit.autopsy.coreutils; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.List; import java.util.logging.Level; import javax.swing.Icon; @@ -52,8 +54,8 @@ public class MessageNotifyUtil { INFO(NotifyDescriptor.INFORMATION_MESSAGE, "info-icon-16.png"), //NON-NLS ERROR(NotifyDescriptor.ERROR_MESSAGE, "error-icon-16.png"), //NON-NLS WARNING(NotifyDescriptor.WARNING_MESSAGE, "warning-icon-16.png"); //NON-NLS - private int notifyDescriptorType; - private Icon icon; + private final int notifyDescriptorType; + private final Icon icon; private MessageType(int notifyDescriptorType, String resourceName) { this.notifyDescriptorType = notifyDescriptorType; @@ -138,24 +140,25 @@ public class MessageNotifyUtil { } /** - * Utility to display notifications with baloons + * Utility to display notifications with balloons */ public static class Notify { + private static final SimpleDateFormat TIME_STAMP_FORMAT = new SimpleDateFormat("MM/dd/yy HH:mm:ss z"); + //notifications to keep track of and to reset when case is closed private static final List notifications = Collections.synchronizedList(new ArrayList()); private Notify() { } - + /** - * Clear pending notifications - * Should really only be used by Case + * Clear pending notifications Should really only be used by Case */ public static void clear() { - for (Notification n : notifications) { + notifications.stream().forEach((n) -> { n.clear(); - } + }); notifications.clear(); } @@ -163,8 +166,8 @@ public class MessageNotifyUtil { * Show message with the specified type and action listener */ public static void show(String title, String message, MessageType type, ActionListener actionListener) { - Notification newNotification = - NotificationDisplayer.getDefault().notify(title, type.getIcon(), message, actionListener); + Notification newNotification + = NotificationDisplayer.getDefault().notify(addTimeStampToTitle(title), type.getIcon(), message, actionListener); notifications.add(newNotification); } @@ -178,11 +181,8 @@ public class MessageNotifyUtil { * @param type type of the message */ public static void show(String title, final String message, final MessageType type) { - ActionListener actionListener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - MessageNotifyUtil.Message.show(message, type); - } + ActionListener actionListener = (ActionEvent e) -> { + MessageNotifyUtil.Message.show(message, type); }; show(title, message, type, actionListener); @@ -217,5 +217,17 @@ public class MessageNotifyUtil { public static void warn(String title, String message) { show(title, message, MessageType.WARNING); } + + /** + * Adds a time stamp prefix to the title of notifications so that they + * will be in order (they are sorted alphabetically) in the + * notifications area. + * + * @param title A notification title without a time stamp prefix. + * @return The notification title with a time stamp prefix. + */ + private static String addTimeStampToTitle(String title) { + return TIME_STAMP_FORMAT.format(new Date()) + " " + title; + } } } From 1592f4c814ce2b29e4fe60d104feb0855ec6ecf1 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Fri, 26 Jun 2015 17:14:24 -0400 Subject: [PATCH 184/198] updated sample to do name comparison lowercase and restrict to end --- pythonExamples/fileIngestModule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pythonExamples/fileIngestModule.py b/pythonExamples/fileIngestModule.py index ae814653b4..0fa774a69a 100755 --- a/pythonExamples/fileIngestModule.py +++ b/pythonExamples/fileIngestModule.py @@ -114,7 +114,7 @@ class SampleJythonFileIngestModule(FileIngestModule): return IngestModule.ProcessResult.OK # For an example, we will flag files with .txt in the name and make a blackboard artifact. - if file.getName().find(".txt") != -1: + if file.getName().lower().endswith(".txt"): self.log(Level.INFO, "Found a text file: " + file.getName()) self.filesFound+=1 From 9b182d18fabd4350e4d1475156bac470dd05cae3 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Fri, 26 Jun 2015 20:50:10 -0400 Subject: [PATCH 185/198] added to python docs --- docs/doxygen/modDevPython.dox | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/doxygen/modDevPython.dox b/docs/doxygen/modDevPython.dox index 7ec3d3112c..19d522e570 100755 --- a/docs/doxygen/modDevPython.dox +++ b/docs/doxygen/modDevPython.dox @@ -7,9 +7,9 @@ go into the page for that module type. --> This page describes the basic concepts and setup that are needed for all types of Python modules. It is not needed for Java module development. Autopsy uses Jython (http://www.jython.org) to enable Python scripting. Jython looks like Python and gets converted into Java byte code and run on the JVM. Its biggest limitations are: -- Limited to Python 2.5 +- Limited to Python 2.7 (as of Autopsy 3.1.3) - Can't use Python libraries that have native code -- You can't make any UIs. This means that you can't make content viewer modules or have configuration settings for your ingest modules. +- You can't easily make UIs. This means that you can't make content viewer modules or easily have configuration settings for your ingest modules. We have done it, but it is tedious compared to using a Java tool to place UI widgets in various places. Using it is very easy though in Autopsy and it allows you to access all of the Java services and classes that you need. @@ -29,10 +29,11 @@ Autopsy requires that you have a self-contained folder for each Python module. You will need to copy this folder into Autopsy's Python script folder. It will scan this folder each time it looks for modules. You can find the location of this folder from the "Tools -> Python Scripts" menu item. + \subsection mod_dev_py_create_create Module Creation -# Create a folder --# Add a .py file to it (see later sections for details on its contents) +-# Copy one of the sample modules from the github repository (listed below) or make one from scratch -# Copy the folder to the previously mentioned folder to make updates during development. That's it. Autopsy will find the module each time it needs it and you can make updates without having to restart Autopsy each time. @@ -52,6 +53,11 @@ from neededLib.mylib import neededClass Jython will look in the module's folder to resolve these libraries. +\subsection mod_dev_py_misc Minor Gotchas +This section lists some helpful tips that we have found. These are all now in the sample modules, so refer to those for examples and a place to copy and paste from. +- We haven't found a good way to debug while running inside of Autopsy. So, logging becomes critical. You need to go through a bunch of steps to get the logger to display your module name. See the sample module for a log() method that does all of this for you. +- When you name the file with your Python module in it, restrict its name to letters, numbers, and underscore (_). + \section mod_dev_py_distribute Distribution To distribute and share your Python module, ZIP up the folder and send it around. Other users of the module should expand the ZIP file and drop the folder into their Autopsy Python folder. @@ -63,5 +69,7 @@ There are only two types of modules that you can make with Python. Those (along - Ingest Modules (both file-level and data source-level): https://github.com/sleuthkit/autopsy/blob/develop/pythonExamples/ - Report Modules: https://github.com/sleuthkit/autopsy/blob/develop/pythonExamples/reportmodule.py + + */ From 0854d5bd412f4d0483b6caa0763869eb76148d59 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 29 Jun 2015 10:54:38 -0400 Subject: [PATCH 186/198] Merge branch 'develop' into hash_set_display Conflicts: ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java --- .../sleuthkit/autopsy/casemodule/Case.java | 11 ++++- .../sleuthkit/autopsy/coreutils/Logger.java | 2 +- .../autopsy/coreutils/MessageNotifyUtil.java | 44 ++++++++++++------- .../autopsy/report/FileReportText.java | 7 +++ .../datamodel/grouping/GroupManager.java | 19 +++++--- docs/doxygen/modDevPython.dox | 14 ++++-- 6 files changed, 70 insertions(+), 27 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 9b7c010bec..b4c61305b2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -26,6 +26,8 @@ import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.nio.file.InvalidPathException; +import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.GregorianCalendar; @@ -1235,7 +1237,14 @@ public class Case implements SleuthkitCase.ErrorObserver { * @throws TskCoreException */ public void addReport(String localPath, String srcModuleName, String reportName) throws TskCoreException { - Report report = this.db.addReport(localPath, srcModuleName, reportName); + String normalizedLocalPath; + try { + normalizedLocalPath = Paths.get(localPath).normalize().toString(); + } catch (InvalidPathException ex) { + String errorMsg = "Invalid local path provided: " + localPath; // NON-NLS + throw new TskCoreException(errorMsg, ex); + } + Report report = this.db.addReport(normalizedLocalPath, srcModuleName, reportName); try { Case.pcs.firePropertyChange(Events.REPORT_ADDED.toString(), null, report); } catch (Exception ex) { diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java b/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java index 494c86cf7f..8ae2480883 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java @@ -79,7 +79,7 @@ public final class Logger extends java.util.logging.Logger { + record.getSourceMethodName() + "\n" + record.getLevel() + ": " + this.formatMessage(record) + "\n" - + record.getThrown().toString() + ": " + + record.getThrown().toString() + ":\n" + StackTrace + "\n"; } else { diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java b/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java index 558167c2bb..498115f310 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/MessageNotifyUtil.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013-2015 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,8 +20,10 @@ package org.sleuthkit.autopsy.coreutils; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.List; import java.util.logging.Level; import javax.swing.Icon; @@ -52,8 +54,8 @@ public class MessageNotifyUtil { INFO(NotifyDescriptor.INFORMATION_MESSAGE, "info-icon-16.png"), //NON-NLS ERROR(NotifyDescriptor.ERROR_MESSAGE, "error-icon-16.png"), //NON-NLS WARNING(NotifyDescriptor.WARNING_MESSAGE, "warning-icon-16.png"); //NON-NLS - private int notifyDescriptorType; - private Icon icon; + private final int notifyDescriptorType; + private final Icon icon; private MessageType(int notifyDescriptorType, String resourceName) { this.notifyDescriptorType = notifyDescriptorType; @@ -138,24 +140,25 @@ public class MessageNotifyUtil { } /** - * Utility to display notifications with baloons + * Utility to display notifications with balloons */ public static class Notify { + private static final SimpleDateFormat TIME_STAMP_FORMAT = new SimpleDateFormat("MM/dd/yy HH:mm:ss z"); + //notifications to keep track of and to reset when case is closed private static final List notifications = Collections.synchronizedList(new ArrayList()); private Notify() { } - + /** - * Clear pending notifications - * Should really only be used by Case + * Clear pending notifications Should really only be used by Case */ public static void clear() { - for (Notification n : notifications) { + notifications.stream().forEach((n) -> { n.clear(); - } + }); notifications.clear(); } @@ -163,8 +166,8 @@ public class MessageNotifyUtil { * Show message with the specified type and action listener */ public static void show(String title, String message, MessageType type, ActionListener actionListener) { - Notification newNotification = - NotificationDisplayer.getDefault().notify(title, type.getIcon(), message, actionListener); + Notification newNotification + = NotificationDisplayer.getDefault().notify(addTimeStampToTitle(title), type.getIcon(), message, actionListener); notifications.add(newNotification); } @@ -178,11 +181,8 @@ public class MessageNotifyUtil { * @param type type of the message */ public static void show(String title, final String message, final MessageType type) { - ActionListener actionListener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - MessageNotifyUtil.Message.show(message, type); - } + ActionListener actionListener = (ActionEvent e) -> { + MessageNotifyUtil.Message.show(message, type); }; show(title, message, type, actionListener); @@ -217,5 +217,17 @@ public class MessageNotifyUtil { public static void warn(String title, String message) { show(title, message, MessageType.WARNING); } + + /** + * Adds a time stamp prefix to the title of notifications so that they + * will be in order (they are sorted alphabetically) in the + * notifications area. + * + * @param title A notification title without a time stamp prefix. + * @return The notification title with a time stamp prefix. + */ + private static String addTimeStampToTitle(String title) { + return TIME_STAMP_FORMAT.format(new Date()) + " " + title; + } } } diff --git a/Core/src/org/sleuthkit/autopsy/report/FileReportText.java b/Core/src/org/sleuthkit/autopsy/report/FileReportText.java index 2dd7e8b676..d7eac93477 100755 --- a/Core/src/org/sleuthkit/autopsy/report/FileReportText.java +++ b/Core/src/org/sleuthkit/autopsy/report/FileReportText.java @@ -30,7 +30,9 @@ import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; /** * A Tab-delimited text report of the files in the case. @@ -68,8 +70,13 @@ import org.sleuthkit.datamodel.AbstractFile; if (out != null) { try { out.close(); + Case.getCurrentCase().addReport(reportPath, NbBundle.getMessage(this.getClass(), + "FileReportText.getName.text"), ""); } catch (IOException ex) { logger.log(Level.WARNING, "Could not close output writer when ending report.", ex); //NON-NLS + } catch (TskCoreException ex) { + String errorMessage = String.format("Error adding %s to case as a report", reportPath); //NON-NLS + logger.log(Level.SEVERE, errorMessage, ex); } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index 8b7844d9c4..804727dc30 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -36,6 +36,7 @@ import java.util.TreeSet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; import javafx.application.Platform; @@ -44,6 +45,12 @@ import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.transformation.SortedList; +import static javafx.concurrent.Worker.State.CANCELLED; +import static javafx.concurrent.Worker.State.FAILED; +import static javafx.concurrent.Worker.State.READY; +import static javafx.concurrent.Worker.State.RUNNING; +import static javafx.concurrent.Worker.State.SCHEDULED; +import static javafx.concurrent.Worker.State.SUCCEEDED; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; @@ -56,7 +63,6 @@ import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.LoggedTask; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.events.ContentTagAddedEvent; @@ -249,6 +255,7 @@ public class GroupManager { */ @ThreadConfined(type = ThreadType.JFX) public void markGroupSeen(DrawableGroup group, boolean seen) { + db.markGroupSeen(group.getGroupKey(), seen); group.setSeen(seen); if (seen) { @@ -284,15 +291,15 @@ public class GroupManager { if (unSeenGroups.contains(group)) { unSeenGroups.remove(group); } + }); } + } else { //group == null + // It may be that this was the last unanalyzed file in the group, so test + // whether the group is now fully analyzed. + popuplateIfAnalyzed(groupKey, null); } - } else { //group == null - // It may be that this was the last unanalyzed file in the group, so test - // whether the group is now fully analyzed. - popuplateIfAnalyzed(groupKey, null); } - return group; } diff --git a/docs/doxygen/modDevPython.dox b/docs/doxygen/modDevPython.dox index 7ec3d3112c..19d522e570 100755 --- a/docs/doxygen/modDevPython.dox +++ b/docs/doxygen/modDevPython.dox @@ -7,9 +7,9 @@ go into the page for that module type. --> This page describes the basic concepts and setup that are needed for all types of Python modules. It is not needed for Java module development. Autopsy uses Jython (http://www.jython.org) to enable Python scripting. Jython looks like Python and gets converted into Java byte code and run on the JVM. Its biggest limitations are: -- Limited to Python 2.5 +- Limited to Python 2.7 (as of Autopsy 3.1.3) - Can't use Python libraries that have native code -- You can't make any UIs. This means that you can't make content viewer modules or have configuration settings for your ingest modules. +- You can't easily make UIs. This means that you can't make content viewer modules or easily have configuration settings for your ingest modules. We have done it, but it is tedious compared to using a Java tool to place UI widgets in various places. Using it is very easy though in Autopsy and it allows you to access all of the Java services and classes that you need. @@ -29,10 +29,11 @@ Autopsy requires that you have a self-contained folder for each Python module. You will need to copy this folder into Autopsy's Python script folder. It will scan this folder each time it looks for modules. You can find the location of this folder from the "Tools -> Python Scripts" menu item. + \subsection mod_dev_py_create_create Module Creation -# Create a folder --# Add a .py file to it (see later sections for details on its contents) +-# Copy one of the sample modules from the github repository (listed below) or make one from scratch -# Copy the folder to the previously mentioned folder to make updates during development. That's it. Autopsy will find the module each time it needs it and you can make updates without having to restart Autopsy each time. @@ -52,6 +53,11 @@ from neededLib.mylib import neededClass Jython will look in the module's folder to resolve these libraries. +\subsection mod_dev_py_misc Minor Gotchas +This section lists some helpful tips that we have found. These are all now in the sample modules, so refer to those for examples and a place to copy and paste from. +- We haven't found a good way to debug while running inside of Autopsy. So, logging becomes critical. You need to go through a bunch of steps to get the logger to display your module name. See the sample module for a log() method that does all of this for you. +- When you name the file with your Python module in it, restrict its name to letters, numbers, and underscore (_). + \section mod_dev_py_distribute Distribution To distribute and share your Python module, ZIP up the folder and send it around. Other users of the module should expand the ZIP file and drop the folder into their Autopsy Python folder. @@ -63,5 +69,7 @@ There are only two types of modules that you can make with Python. Those (along - Ingest Modules (both file-level and data source-level): https://github.com/sleuthkit/autopsy/blob/develop/pythonExamples/ - Report Modules: https://github.com/sleuthkit/autopsy/blob/develop/pythonExamples/reportmodule.py + + */ From a234f9647d1e0002e5a1772152c1a2106ded07a9 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 29 Jun 2015 11:07:15 -0400 Subject: [PATCH 187/198] Merge branch 'develop' into hash_set_display Conflicts: ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java --- .../autopsy/imagegallery/datamodel/grouping/GroupManager.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index 804727dc30..be2b6d886a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -248,8 +248,7 @@ public class GroupManager { /** * 'mark' the given group as seen. This removes it from the queue of - * groups - * to review, and is persisted in the drawable db. + * groups to review, and is persisted in the drawable db. * * @param group the {@link DrawableGroup} to mark as seen */ From 3a37fe0ef1ad0003a008c9ebee5ab50318d8269b Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 29 Jun 2015 11:13:51 -0400 Subject: [PATCH 188/198] fixup! Merge branch 'develop' into hash_set_display --- .../autopsy/casemodule/services/TagsManager.java | 1 - .../imagegallery/datamodel/grouping/GroupManager.java | 10 +--------- .../imagegallery/gui/drawableviews/MetaDataPane.java | 1 - 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index f94976b572..01daae9fba 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -404,7 +404,6 @@ public class TagsManager implements Closeable { getExistingTagNames(); } - Case.getPropertyChangeSupport().firePropertyChange(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString(), tag, null); tskCase.deleteBlackboardArtifactTag(tag); try { Case.getCurrentCase().notifyBlackBoardArtifactTagDeleted(tag); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index ec63a51740..be2b6d886a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -248,15 +248,7 @@ public class GroupManager { /** * 'mark' the given group as seen. This removes it from the queue of - * groups - * files. - * public DrawableGroup makeGroup(GroupKey groupKey, Set files) { - * - * Set newFiles = ObjectUtils.defaultIfNull(files, new - * HashSet()); - * } - * groups - * to review, and is persisted in the drawable db. + * groups to review, and is persisted in the drawable db. * * @param group the {@link DrawableGroup} to mark as seen */ diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index af0891e523..0f3f2c5b62 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -150,7 +150,6 @@ public class MetaDataPane extends DrawableUIBase { } @Override - protected synchronized void setFileHelper(Long newFileID) { setFileIDOpt(Optional.ofNullable(newFileID)); if (newFileID == null) { From 27dab95e5a9040c1a50ae28d88f57047cb2d7904 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 29 Jun 2015 14:40:29 -0400 Subject: [PATCH 189/198] fix catch block around Case.getCurrentCase to catch IllegalStateException --- .../org/sleuthkit/autopsy/casemodule/services/TagsManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 01daae9fba..aa79469d4e 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -250,7 +250,7 @@ public class TagsManager implements Closeable { final ContentTag newContentTag = tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); try { Case.getCurrentCase().notifyContentTagAdded(newContentTag); - } catch (IllegalArgumentException ex) { + } catch (IllegalStateException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, NbBundle.getMessage(TagsManager.class, "TagsManager.addContentTag.noCaseWarning")); } return newContentTag; From d883992685962aa686c4e4ba5ca3e8bc471f8a6f Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 29 Jun 2015 14:42:39 -0400 Subject: [PATCH 190/198] remove dependency on openjfx-dialogs since we are building on java 8u40 --- CoreLibs/ivy.xml | 1 - CoreLibs/nbproject/project.xml | 13 ++++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/CoreLibs/ivy.xml b/CoreLibs/ivy.xml index a4cc0075e7..cc7b7312ec 100644 --- a/CoreLibs/ivy.xml +++ b/CoreLibs/ivy.xml @@ -38,7 +38,6 @@ - diff --git a/CoreLibs/nbproject/project.xml b/CoreLibs/nbproject/project.xml index a76fed8a8f..9d02b18dc2 100644 --- a/CoreLibs/nbproject/project.xml +++ b/CoreLibs/nbproject/project.xml @@ -64,7 +64,6 @@ com.sun.mail.smtp com.sun.mail.util com.sun.mail.util.logging - javafx.scene.control javassist javassist.bytecode javassist.bytecode.analysis @@ -616,10 +615,6 @@ ext/logkit-1.0.1.jar release/modules/ext/logkit-1.0.1.jar - - ext/openjfx-dialogs-1.0.3.jar - release/modules/ext/openjfx-dialogs-1.0.3.jar - ext/imgscalr-lib-4.2-javadoc.jar release/modules/ext/imgscalr-lib-4.2-javadoc.jar @@ -768,14 +763,14 @@ ext/slf4j-simple-1.6.1.jar release/modules/ext/slf4j-simple-1.6.1.jar - - ext/controlsfx-8.40.9.jar - release/modules/ext/controlsfx-8.40.9.jar - ext/commons-lang3-3.0-javadoc.jar release/modules/ext/commons-lang3-3.0-javadoc.jar + + ext/controlsfx-8.40.9.jar + release/modules/ext/controlsfx-8.40.9.jar + ext/platform-3.4.0.jar release/modules/ext/platform-3.4.0.jar From 8b30d1bb7b7038079d598a4b3c5ce6d39e8e2e59 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 29 Jun 2015 14:43:18 -0400 Subject: [PATCH 191/198] check for duplicate tags in ImageGallery like we do in Autopsy. --- .../actions/AddDrawableTagAction.java | 40 +++++++++++++++---- .../imagegallery/actions/AddTagAction.java | 1 - .../actions/DeleteFollowUpTagAction.java | 4 +- .../datamodel/DrawableTagsManager.java | 2 +- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java index 3c115d9134..4399a05706 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddDrawableTagAction.java @@ -19,18 +19,24 @@ package org.sleuthkit.autopsy.imagegallery.actions; import java.util.HashSet; +import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.logging.Level; +import javafx.application.Platform; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; import javafx.scene.control.Menu; -import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.openide.util.Utilities; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -73,14 +79,32 @@ public class AddDrawableTagAction extends AddTagAction { protected Void doInBackground() throws Exception { for (Long fileID : selectedFiles) { try { - DrawableFile file = controller.getFileFromId(fileID); + final DrawableFile file = controller.getFileFromId(fileID); LOGGER.log(Level.INFO, "tagging {0} with {1} and comment {2}", new Object[]{file.getName(), tagName.getDisplayName(), comment}); - controller.getTagsManager().addContentTag(file, tagName, comment); - } catch (IllegalStateException ex) { - LOGGER.log(Level.SEVERE, "Case was closed out from underneath Updatefile task", ex); - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error tagging result", ex); - JOptionPane.showMessageDialog(null, "Unable to tag " + fileID + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); + + // check if the same tag is being added for the same abstract file. + DrawableTagsManager tagsManager = controller.getTagsManager(); + List contentTags = tagsManager.getContentTagsByContent(file); + Optional duplicateTagName = contentTags.stream() + .map(ContentTag::getName) + .filter(tagName::equals) + .findAny(); + + if (duplicateTagName.isPresent()) { + Platform.runLater(() -> { + Alert alert = new Alert(Alert.AlertType.WARNING, "Unable to tag " + file.getName() + ". It has already been tagged as \"" + tagName.getDisplayName() + ". Cannot reapply the same tag.", ButtonType.OK); + alert.setHeaderText("Tag Error"); + alert.show(); + }); + } else { + controller.getTagsManager().addContentTag(file, tagName, comment); + } + + } catch (TskCoreException tskCoreException) { + LOGGER.log(Level.SEVERE, "Error tagging result", tskCoreException); + Platform.runLater(() -> { + new Alert(Alert.AlertType.ERROR, "Unable to file " + fileID + ".").show(); + }); } } return null; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java index 44bb02f0e0..6e45f9bbdc 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java @@ -28,7 +28,6 @@ import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; -import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.datamodel.TagName; /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java index fb729807c0..27ab1cd8b1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteFollowUpTagAction.java @@ -24,9 +24,9 @@ import javafx.event.ActionEvent; import javax.swing.SwingWorker; import org.controlsfx.control.action.Action; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -49,7 +49,7 @@ public class DeleteFollowUpTagAction extends Action { try { final TagName followUpTagName = tagsManager.getFollowUpTagName(); - + List contentTagsByContent = tagsManager.getContentTagsByContent(file); for (ContentTag ct : contentTagsByContent) { if (ct.getName().getDisplayName().equals(followUpTagName.getDisplayName())) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index 547ab7a858..2c29f44d85 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -200,7 +200,7 @@ public class DrawableTagsManager { public ContentTag addContentTag(DrawableFile file, TagName tagName, String comment) throws TskCoreException { synchronized (autopsyTagsManagerLock) { - return autopsyTagsManager.addContentTag(file, tagName, comment); + return autopsyTagsManager.addContentTag(file.getAbstractFile(), tagName, comment); } } From 019e0b9584c286e4764f8ba73b1e38bf16839b55 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 29 Jun 2015 15:38:07 -0400 Subject: [PATCH 192/198] fix tag group menu bug --- .../autopsy/imagegallery/gui/drawableviews/GroupPane.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index ab011fc493..c33793ce4d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -115,7 +115,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewMode; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; -import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils; import org.sleuthkit.autopsy.imagegallery.gui.Toolbar; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -360,7 +359,7 @@ public class GroupPane extends BorderPane { if (t1) { ArrayList selTagMenues = new ArrayList<>(); for (final TagName tn : getController().getTagsManager().getNonCategoryTagNames()) { - MenuItem menuItem = GuiUtils.createSelTagMenuItem(tn, grpTagSplitMenu, controller); + MenuItem menuItem = createGrpTagMenuItem(tn); selTagMenues.add(menuItem); } grpTagSplitMenu.getItems().setAll(selTagMenues); From 3e3a48e184492050ecdcc7378db97146a98c6667 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 29 Jun 2015 16:05:23 -0400 Subject: [PATCH 193/198] replace buggy JavaFX SortedLists with explicit sorting --- .../datamodel/grouping/GroupManager.java | 23 +++++++++---------- .../autopsy/imagegallery/gui/Toolbar.java | 1 - 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index ec63a51740..c5c3479a46 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -25,7 +25,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -44,7 +43,6 @@ import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import javafx.collections.transformation.SortedList; import static javafx.concurrent.Worker.State.CANCELLED; import static javafx.concurrent.Worker.State.FAILED; import static javafx.concurrent.Worker.State.READY; @@ -108,12 +106,12 @@ public class GroupManager { */ @ThreadConfined(type = ThreadType.JFX) private final ObservableList analyzedGroups = FXCollections.observableArrayList(); - private final SortedList unmodifiableAnalyzedGroups = new SortedList<>(analyzedGroups); + private final ObservableList unmodifiableAnalyzedGroups = FXCollections.unmodifiableObservableList(analyzedGroups); /** list of unseen groups */ @ThreadConfined(type = ThreadType.JFX) private final ObservableList unSeenGroups = FXCollections.observableArrayList(); - private final SortedList unmodifiableUnSeenGroups = new SortedList<>(unSeenGroups); + private final ObservableList unmodifiableUnSeenGroups = FXCollections.unmodifiableObservableList(unSeenGroups); private ReGroupTask groupByTask; @@ -270,6 +268,7 @@ public class GroupManager { } else if (unSeenGroups.contains(group) == false) { unSeenGroups.add(group); } + FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); } /** @@ -294,11 +293,12 @@ public class GroupManager { Platform.runLater(() -> { if (analyzedGroups.contains(group)) { analyzedGroups.remove(group); + FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder)); } if (unSeenGroups.contains(group)) { unSeenGroups.remove(group); + FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); } - }); } } else { //group == null @@ -535,8 +535,8 @@ public class GroupManager { setSortBy(sortBy); setSortOrder(sortOrder); Platform.runLater(() -> { - unmodifiableAnalyzedGroups.setComparator(sortBy.getGrpComparator(sortOrder)); - unmodifiableUnSeenGroups.setComparator(sortBy.getGrpComparator(sortOrder)); + FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder)); + FXCollections.sort(unSeenGroups, sortBy.getGrpComparator(sortOrder)); }); } } @@ -679,6 +679,9 @@ public class GroupManager { Platform.runLater(() -> { if (analyzedGroups.contains(group) == false) { analyzedGroups.add(group); + if (Objects.isNull(task)) { + FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder)); + } } markGroupSeen(group, groupSeen); }); @@ -731,10 +734,6 @@ public class GroupManager { Platform.runLater(() -> { analyzedGroups.clear(); unSeenGroups.clear(); - - final Comparator grpComparator = sortBy.getGrpComparator(sortOrder); - unmodifiableAnalyzedGroups.setComparator(grpComparator); - unmodifiableUnSeenGroups.setComparator(grpComparator); }); // Get the list of group keys @@ -754,7 +753,7 @@ public class GroupManager { groupProgress.progress("regrouping files by " + groupBy.attrName.toString() + " : " + val, p); popuplateIfAnalyzed(new GroupKey
(groupBy, val), this); } - + FXCollections.sort(analyzedGroups, sortBy.getGrpComparator(sortOrder)); updateProgress(1, 1); return null; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index 33083c45b4..ea8cb26b00 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -41,7 +41,6 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javax.swing.SortOrder; import org.openide.util.Exceptions; -import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; From fd6c748e511cb899479a37e06b613cb354c37963 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Mon, 29 Jun 2015 19:07:07 -0400 Subject: [PATCH 194/198] Updated to develop flag --- nbproject/project.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nbproject/project.properties b/nbproject/project.properties index 502bbab27d..d46c65d75a 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -7,8 +7,8 @@ app.name=${branding.token} app.version=3.1.3 ### Build type isn't used at this point, but it may be useful ### Must be one of: DEVELOPMENT, RELEASE -build.type=RELEASE -#build.type=DEVELOPMENT +#build.type=RELEASE +build.type=DEVELOPMENT update_versions=false #custom JVM options From 5866b88a353634ee8f87af3c44f4e402b8ffe8ad Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 1 Jul 2015 15:52:12 -0400 Subject: [PATCH 195/198] improve synchronization and guard the videoFileMap from null keys to eliminate NPE --- .../imagegallery/datamodel/DrawableDB.java | 19 +++++++++++++++++-- .../gui/drawableviews/DrawableTileBase.java | 3 +-- .../gui/drawableviews/DrawableUIBase.java | 14 ++++++-------- .../gui/drawableviews/MetaDataPane.java | 2 +- .../gui/drawableviews/SlideShowView.java | 3 +-- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index c330fa6865..ecd5a6a451 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -34,6 +34,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.Lock; @@ -1196,10 +1197,24 @@ public final class DrawableDB { /** * For performance reasons, keep the file type in memory */ - private final Map videoFileMap = new ConcurrentHashMap<>(); + private final Map videoFileMap = new ConcurrentHashMap<>(); + /** + * is this File a video file? + * + * @param f check if this file is a video. will return false for null file. + * + * @return returns true if this file is a video as determined by {@link ImageGalleryModule#isVideoFile(org.sleuthkit.datamodel.AbstractFile) + * } but caches the result. + * returns false if passed a null AbstractFile + */ public boolean isVideoFile(AbstractFile f) { - return videoFileMap.computeIfAbsent(f, ImageGalleryModule::isVideoFile); + + if (Objects.isNull(f)) { + return false; + } else { + return videoFileMap.computeIfAbsent(f.getId(), (id) -> ImageGalleryModule.isVideoFile(f)); + } } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index ed12891589..631e43aea6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -284,7 +284,7 @@ public abstract class DrawableTileBase extends DrawableUIBase { } @Override - protected void setFileHelper(final Long newFileID) { + synchronized protected void setFileHelper(final Long newFileID) { setFileIDOpt(Optional.ofNullable(newFileID)); disposeContent(); @@ -351,7 +351,6 @@ public abstract class DrawableTileBase extends DrawableUIBase { @Subscribe @Override public void handleTagAdded(ContentTagAddedEvent evt) { - handleTagEvent(evt, () -> { Platform.runLater(() -> { followUpImageView.setImage(followUpIcon); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java index 0657385aff..267632ed85 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java @@ -35,9 +35,9 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView private final ImageGalleryController controller; - volatile private Optional> fileOpt = Optional.empty(); + private Optional> fileOpt = Optional.empty(); - volatile private Optional fileIDOpt = Optional.empty(); + private Optional fileIDOpt = Optional.empty(); public DrawableUIBase(ImageGalleryController controller) { this.controller = controller; @@ -53,16 +53,16 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView return fileIDOpt; } - void setFileIDOpt(Optional fileIDOpt) { + synchronized void setFileIDOpt(Optional fileIDOpt) { this.fileIDOpt = fileIDOpt; } - void setFileOpt(Optional> fileOpt) { + synchronized void setFileOpt(Optional> fileOpt) { this.fileOpt = fileOpt; } @Override - public Optional> getFile() { + synchronized public Optional> getFile() { if (fileIDOpt.isPresent()) { if (fileOpt.isPresent() && fileOpt.get().getId() == fileIDOpt.get()) { return fileOpt; @@ -83,7 +83,7 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView protected abstract void setFileHelper(Long newFileID); @Override - public void setFile(Long newFileID) { + synchronized public void setFile(Long newFileID) { if (getFileID().isPresent()) { if (Objects.equals(newFileID, getFileID().get()) == false) { setFileHelper(newFileID); @@ -92,6 +92,4 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView setFileHelper(newFileID); } } - - } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index 0f3f2c5b62..9e544c031c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -150,7 +150,7 @@ public class MetaDataPane extends DrawableUIBase { } @Override - protected synchronized void setFileHelper(Long newFileID) { + synchronized protected void setFileHelper(Long newFileID) { setFileIDOpt(Optional.ofNullable(newFileID)); if (newFileID == null) { Platform.runLater(() -> { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java index 2b29e57d39..412c641ad4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java @@ -290,7 +290,7 @@ public class SlideShowView extends DrawableTileBase { * 1 => right / forward */ @ThreadConfined(type = ThreadType.JFX) - private void cycleSlideShowImage(int direction) { + synchronized private void cycleSlideShowImage(int direction) { stopVideo(); final int groupSize = getGroupPane().getGrouping().fileIds().size(); final Integer nextIndex = getFileID().map(fileID -> { @@ -363,7 +363,6 @@ public class SlideShowView extends DrawableTileBase { new CategorizeAction(getController()).addTag(getController().getTagsManager().getTagName(cat), ""); } }); - } } } From 924d01252778687304afc8e99e48ed43692d95db Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 1 Jul 2015 15:54:07 -0400 Subject: [PATCH 196/198] fix rebuilding the contents tree when switching grouping --- .../gui/navpanel/GroupTreeCell.java | 3 +-- .../imagegallery/gui/navpanel/NavPanel.java | 26 +++++-------------- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java index 8103a55cf6..8618634aab 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java @@ -107,7 +107,6 @@ class GroupTreeCell extends TreeCell { setStyle(""); }); } else { - if (isNull(treeNode.getGroup())) { final String groupName = getGroupName(); //"dummy" group in file system tree <=> a folder with no drawables @@ -141,7 +140,7 @@ class GroupTreeCell extends TreeCell { private String getGroupName() { return Optional.ofNullable(getItem()) - .map((TreeNode t) -> StringUtils.defaultIfBlank(t.getPath(), DrawableGroup.getBlankGroupName())) + .map(treeNode -> StringUtils.defaultIfBlank(treeNode.getPath(), DrawableGroup.getBlankGroupName())) .orElse(""); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java index 64aa5a681e..d00f28cea8 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java @@ -28,7 +28,6 @@ import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.ComboBox; import javafx.scene.control.ListView; @@ -151,13 +150,15 @@ public class NavPanel extends TabPane { } }); - initHashTree(); - initNavTree(); - controller.getGroupManager().getAnalyzedGroups().addListener((ListChangeListener.Change change) -> { TreeItem selectedItem = activeTreeProperty.get().getSelectionModel().getSelectedItem(); boolean wasPermuted = false; while (change.next()) { + if (change.wasPermutated()) { + // Handle this afterward + wasPermuted = true; + break; + } for (DrawableGroup g : change.getAddedSubList()) { insertIntoNavTree(g); if (g.getHashSetHitsCount() > 0) { @@ -168,11 +169,6 @@ public class NavPanel extends TabPane { removeFromNavTree(g); removeFromHashTree(g); } - if (change.wasPermutated()) { - // Handle this afterward - wasPermuted = true; - break; - } } if (wasPermuted) { @@ -182,16 +178,10 @@ public class NavPanel extends TabPane { Platform.runLater(() -> { setFocusedGroup(selectedItem.getValue().getGroup()); }); - } }); - for (DrawableGroup g : controller.getGroupManager().getAnalyzedGroups()) { - insertIntoNavTree(g); - if (g.getHashSetHitsCount() > 0) { - insertIntoHashTree(g); - } - } + rebuildTrees(); controller.viewState().addListener((ObservableValue observable, GroupViewState oldValue, GroupViewState newValue) -> { if (newValue != null && newValue.getGroup() != null) { @@ -204,9 +194,7 @@ public class NavPanel extends TabPane { navTreeRoot = new GroupTreeItem("", null, sortByBox.getSelectionModel().selectedItemProperty().get()); hashTreeRoot = new GroupTreeItem("", null, sortByBox.getSelectionModel().selectedItemProperty().get()); - ObservableList groups = controller.getGroupManager().getAnalyzedGroups(); - - for (DrawableGroup g : groups) { + for (DrawableGroup g : controller.getGroupManager().getAnalyzedGroups()) { insertIntoNavTree(g); if (g.getHashSetHitsCount() > 0) { insertIntoHashTree(g); From cb346a00fe51afb0493f7a7ec8a872204bb307d2 Mon Sep 17 00:00:00 2001 From: sidheshenator Date: Wed, 1 Jul 2015 17:33:32 -0400 Subject: [PATCH 197/198] jython moduleName getting regex fixed --- Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java b/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java index c0c1e970b8..fe2e9d66f2 100755 --- a/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java +++ b/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java @@ -120,7 +120,7 @@ public final class JythonModuleLoader { interpreter.exec("import sys"); //NON-NLS String path = Matcher.quoteReplacement(script.getParent()); interpreter.exec("sys.path.append('" + path + "')"); //NON-NLS - String moduleName = script.getName().replaceAll(".py", ""); //NON-NLS + String moduleName = script.getName().replaceAll("\\.py$", ""); //NON-NLS // reload the module so that the changes made to it can be loaded. interpreter.exec("import " + moduleName); //NON-NLS From 7ff99f03d8b7448bfa2769a0e1e4b181195cc94b Mon Sep 17 00:00:00 2001 From: Ketil Froyn Date: Sat, 4 Jul 2015 02:05:15 +0200 Subject: [PATCH 198/198] Use os.path.join() for path manipulation in reportmodule.py, rather than hardcoding backslash --- pythonExamples/reportmodule.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pythonExamples/reportmodule.py b/pythonExamples/reportmodule.py index fc1c017905..3dce311a7c 100755 --- a/pythonExamples/reportmodule.py +++ b/pythonExamples/reportmodule.py @@ -36,6 +36,7 @@ from java.lang import System from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.report import GeneralReportModuleAdapter +import os # TODO: Rename this to something more specific class SampleGeneralReportModule(GeneralReportModuleAdapter): @@ -73,10 +74,10 @@ class SampleGeneralReportModule(GeneralReportModuleAdapter): progressBar.increment() # Write the result to the report file. - report = open(baseReportDir + '\\' + self.getRelativeFilePath(), 'w') + report = open(os.path.join(baseReportDir, self.getRelativeFilePath()), 'w') report.write("file count = %d" % fileCount) Case.getCurrentCase().addReport(report.name, "SampleGeneralReportModule", "Sample Python Report"); report.close() progressBar.increment() - progressBar.complete() \ No newline at end of file + progressBar.complete()