diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/ImageAnalyzerController.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/ImageAnalyzerController.java index 44356ea8de..95c5a3a885 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/ImageAnalyzerController.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/ImageAnalyzerController.java @@ -450,11 +450,11 @@ public final class ImageAnalyzerController implements FileUpdateListener { for (GroupKey gk : groupsForFile) { Grouping g = groupManager.getGroupForKey(gk); - //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. 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); - } ////if there wasn't already a group check if there should be one now - else { + } else { + //if there wasn't already a group check if there should be one now //TODO: use method in groupmanager ? List checkAnalyzed = groupManager.checkAnalyzed(gk); if (checkAnalyzed != null) { // => the group is analyzed, so add it to the ui diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/CategorizeAction.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/CategorizeAction.java index 974f9d3fb2..6602ccd95e 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/CategorizeAction.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/actions/CategorizeAction.java @@ -92,7 +92,7 @@ public class CategorizeAction extends AddTagAction { List allContentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(file); for (ContentTag ct : allContentTags) { - //this is bad: treating tags as categories as long as thier names start with prefix + //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)) { LOGGER.log(Level.INFO, "removing old category from {0}", file.getName()); @@ -104,8 +104,7 @@ public class CategorizeAction extends AddTagAction { Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment); } //make sure rest of ui hears category change. - controller.handleFileUpdate( - new FileUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); + controller.handleFileUpdate(new FileUpdateEvent(Collections.singleton(fileID), DrawableAttribute.CATEGORY)); } catch (TskCoreException ex) { LOGGER.log(Level.SEVERE, "Error categorizing result", ex); diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/datamodel/Category.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/datamodel/Category.java index c1426f668e..755bb32bc1 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/datamodel/Category.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/datamodel/Category.java @@ -54,7 +54,7 @@ public enum Category implements Comparable { final static private Map nameMap = new HashMap<>(); - private static List valuesList = Arrays.asList(values()); + private static final List valuesList = Arrays.asList(values()); static { for (Category cat : values()) { diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/grouping/GroupKey.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/grouping/GroupKey.java index d4ddfc30a9..75b993398b 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/grouping/GroupKey.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/grouping/GroupKey.java @@ -63,13 +63,11 @@ public class GroupKey> implements Comparable return false; } final GroupKey other = (GroupKey) obj; - if (!Objects.equals(this.val, other.val)) { - return false; - } if (this.attr != other.attr) { return false; } - return true; + + return Objects.equals(this.val, other.val); } @Override diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/grouping/GroupManager.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/grouping/GroupManager.java index 92016fd11d..e2e141f581 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/grouping/GroupManager.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/grouping/GroupManager.java @@ -30,6 +30,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.logging.Level; +import java.util.stream.Collectors; import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -90,7 +91,7 @@ public class GroupManager { @ThreadConfined(type = ThreadType.JFX) private final ObservableList unSeenGroups = FXCollections.observableArrayList(); - private final SortedList sortedUnSeenGroups = unSeenGroups.sorted(); + private final SortedList sortedUnSeenGroups = new SortedList<>(unSeenGroups); private final ObservableList publicSortedUnseenGroupsWrapper = FXCollections.unmodifiableObservableList(sortedUnSeenGroups); @@ -137,10 +138,16 @@ public class GroupManager { * file is a part of */ @SuppressWarnings({"rawtypes", "unchecked"}) - public Set> getGroupKeysForFile(DrawableFile file) { + synchronized public Set> getGroupKeysForFile(DrawableFile file) { Set> resultSet = new HashSet<>(); for (Comparable val : groupBy.getValue(file)) { - resultSet.add(new GroupKey(groupBy, val)); + if (groupBy == DrawableAttribute.TAGS) { + if (((TagName) val).getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) { + resultSet.add(new GroupKey(groupBy, val)); + } + } else { + resultSet.add(new GroupKey(groupBy, val)); + } } return resultSet; } @@ -154,7 +161,7 @@ public class GroupManager { * @return a a set of {@link GroupKey}s representing the group(s) the given * file is a part of */ - public Set> getGroupKeysForFileID(Long fileID) { + synchronized public Set> getGroupKeysForFileID(Long fileID) { try { DrawableFile file = db.getFileFromID(fileID); return getGroupKeysForFile(file); @@ -185,7 +192,9 @@ public class GroupManager { groupBy = DrawableAttribute.PATH; sortOrder = SortOrder.ASCENDING; Platform.runLater(() -> { - unSeenGroups.clear(); + synchronized (unSeenGroups) { + unSeenGroups.clear(); + } analyzedGroups.clear(); }); synchronized (groupMap) { @@ -236,7 +245,9 @@ public class GroupManager { } public void markGroupSeen(Grouping group) { - unSeenGroups.remove(group); + synchronized (unSeenGroups) { + unSeenGroups.remove(group); + } db.markGroupSeen(group.groupKey); } @@ -255,13 +266,16 @@ public class GroupManager { group.removeFile(fileID); if (group.fileIds().isEmpty()) { synchronized (groupMap) { - groupMap.remove(group.groupKey); + groupMap.remove(groupKey, group); } Platform.runLater(() -> { analyzedGroups.remove(group); - unSeenGroups.remove(group); + synchronized (unSeenGroups) { + unSeenGroups.remove(group); + } }); } + } } @@ -292,9 +306,10 @@ public class GroupManager { if (analyzedGroups.contains(g) == false) { analyzedGroups.add(g); } - - if (groupSeen == false && unSeenGroups.contains(g) == false) { - unSeenGroups.add(g); + synchronized (unSeenGroups) { + if (groupSeen == false && unSeenGroups.contains(g) == false) { + unSeenGroups.add(g); + } } }); } @@ -399,7 +414,9 @@ public class GroupManager { values = (List) Category.valuesList(); break; case TAGS: - values = (List) Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse(); + values = (List) Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse().stream() + .filter(t -> t.getDisplayName().startsWith(Category.CATEGORY_PREFIX) == false) + .collect(Collectors.toList()); break; case ANALYZED: values = (List) Arrays.asList(false, true); @@ -412,7 +429,6 @@ public class GroupManager { //otherwise do straight db query return db.findValuesForAttribute(groupBy, sortBy, sortOrder); } - //sort in memory Collections.sort(values, sortBy.getValueComparator(groupBy, sortOrder)); @@ -600,7 +616,9 @@ public class GroupManager { groupProgress = ProgressHandleFactory.createHandle("regrouping files by " + groupBy.attrName.toString() + " sorted by " + sortBy.name() + " in " + sortOrder.toString() + " order", this); Platform.runLater(() -> { analyzedGroups.clear(); - unSeenGroups.clear(); + synchronized (unSeenGroups) { + unSeenGroups.clear(); + } }); synchronized (groupMap) { groupMap.clear(); diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/grouping/Grouping.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/grouping/Grouping.java index 949cd8958a..91559ad6c8 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/grouping/Grouping.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/grouping/Grouping.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.imageanalyzer.grouping; import java.util.List; import java.util.Objects; import java.util.logging.Level; -import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import org.sleuthkit.autopsy.coreutils.Logger; @@ -42,7 +41,7 @@ public class Grouping { public static final String UNKNOWN = "unknown"; - final private ObservableList fileIDs = FXCollections.observableArrayList(); + private final ObservableList fileIDs = FXCollections.observableArrayList(); //cache the number of files in this groups with hashset hits private int filesWithHashSetHitsCount = -1; @@ -110,17 +109,13 @@ public class Grouping { } synchronized public void addFile(Long f) { - Platform.runLater(() -> { - if (fileIDs.contains(f) == false) { - fileIDs.add(f); - } - }); + if (fileIDs.contains(f) == false) { + fileIDs.add(f); + } } synchronized public void removeFile(Long f) { - Platform.runLater(() -> { - fileIDs.removeAll(f); - }); + fileIDs.removeAll(f); } } diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/GroupPane.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/GroupPane.java index f9d2755b5b..1192b08a42 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/GroupPane.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/GroupPane.java @@ -34,6 +34,7 @@ import javafx.animation.Interpolator; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; +import javafx.application.Platform; import javafx.beans.Observable; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectWrapper; @@ -354,10 +355,13 @@ public class GroupPane extends BorderPane implements GroupView { resetHeaderString(); //and assign fileIDs to gridView if (grouping.get() == null) { - gridView.getItems().clear(); + Platform.runLater(gridView.getItems()::clear); + } else { - gridView.setItems(grouping.get().fileIds()); - grouping.get().fileIds().addListener((Observable p) -> { + Platform.runLater(() -> { + gridView.setItems(grouping.get().fileIds()); + }); + grouping.get().fileIds().addListener((Observable p) -> { resetHeaderString(); }); } diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/MetaDataPane.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/MetaDataPane.java index 292d94c172..cbace3a0b8 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/MetaDataPane.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/MetaDataPane.java @@ -24,6 +24,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.ResourceBundle; import java.util.logging.Level; +import java.util.stream.Collectors; import javafx.application.Platform; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; @@ -52,6 +53,7 @@ import org.sleuthkit.autopsy.imageanalyzer.TagUtils; import org.sleuthkit.autopsy.imageanalyzer.datamodel.Category; import org.sleuthkit.autopsy.imageanalyzer.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imageanalyzer.datamodel.DrawableFile; +import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** @@ -121,9 +123,15 @@ public class MetaDataPane extends AnchorPane implements Category.CategoryListene }); attributeColumn.setPrefWidth(USE_COMPUTED_SIZE); - + valueColumn.setCellValueFactory((p) -> { - return new SimpleStringProperty(StringUtils.join((Collection) p.getValue().getValue(), ";")); + if (p.getValue().getKey() == DrawableAttribute.TAGS) { + return new SimpleStringProperty(((Collection) p.getValue().getValue()).stream() + .map(TagName::getDisplayName) + .collect(Collectors.joining(" ; ", "", ""))); + } else { + return new SimpleStringProperty(StringUtils.join((Collection) p.getValue().getValue(), " ; ")); + } }); valueColumn.setPrefWidth(USE_COMPUTED_SIZE); valueColumn.setCellFactory((p) -> new TableCell, ? extends Object>, String>() { diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/SingleDrawableViewBase.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/SingleDrawableViewBase.java index 53c58e4225..bc73c394ad 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/SingleDrawableViewBase.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/SingleDrawableViewBase.java @@ -75,6 +75,7 @@ import org.sleuthkit.autopsy.imageanalyzer.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imageanalyzer.datamodel.Category; import org.sleuthkit.autopsy.imageanalyzer.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imageanalyzer.datamodel.DrawableFile; +import org.sleuthkit.autopsy.imageanalyzer.grouping.GroupKey; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -250,6 +251,7 @@ public abstract class SingleDrawableViewBase extends AnchorPane implements Drawa protected abstract void clearContent(); protected abstract void disposeContent(); + protected abstract Runnable getContentUpdateRunnable(); protected abstract String getLabelText(); @@ -264,18 +266,21 @@ public abstract class SingleDrawableViewBase extends AnchorPane implements Drawa Exceptions.printStackTrace(ex); } } else { - //TODO: convert this to an action! - List contentTagsByContent; + final ImageAnalyzerController controller = ImageAnalyzerController.getDefault(); try { - contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(getFile()); + // remove file from old category group + controller.getGroupManager().removeFromGroup(new GroupKey(DrawableAttribute.TAGS, TagUtils.getFollowUpTagName()), fileID); + + List contentTagsByContent = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(getFile()); for (ContentTag ct : contentTagsByContent) { if (ct.getName().getDisplayName().equals(TagUtils.getFollowUpTagName().getDisplayName())) { Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(ct); SwingUtilities.invokeLater(() -> DirectoryTreeTopComponent.findInstance().refreshContentTreeSafe()); } } - ImageAnalyzerController.getDefault().handleFileUpdate(new FileUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); + + controller.handleFileUpdate(new FileUpdateEvent(Collections.singleton(fileID), DrawableAttribute.TAGS)); } catch (TskCoreException ex) { Exceptions.printStackTrace(ex); } diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/navpanel/GroupTreeCell.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/navpanel/GroupTreeCell.java index b4fb5c6a3f..606d077fc9 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/navpanel/GroupTreeCell.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/navpanel/GroupTreeCell.java @@ -37,17 +37,26 @@ class GroupTreeCell extends TreeCell { super.updateItem(tNode, empty); prefWidthProperty().bind(getTreeView().widthProperty().subtract(15)); - if (tNode != null) { + if (tNode == null || empty) { + Platform.runLater(() -> { + setTooltip(null); + setText(null); + setGraphic(null); + }); + } else { final String name = StringUtils.defaultIfBlank(tNode.getPath(), Grouping.UNKNOWN); - setTooltip(new Tooltip(name)); + Platform.runLater(() -> { + setTooltip(new Tooltip(name)); + }); + if (tNode.getGroup() == null) { - setText(name); - setGraphic(new ImageView(EMPTY_FOLDER_ICON)); - } else { - //this TreeNode has a group so append counts to name ... - setText(name + " (" + getNumerator() + getDenominator() + ")"); + Platform.runLater(() -> { + setText(name); + setGraphic(new ImageView(EMPTY_FOLDER_ICON)); + }); + } else { //if number of files in this group changes (eg file is recategorized), update counts tNode.getGroup().fileIds().addListener((Observable o) -> { Platform.runLater(() -> { @@ -55,13 +64,14 @@ class GroupTreeCell extends TreeCell { }); }); - //... and use icon corresponding to group type - setGraphic(new ImageView(tNode.getGroup().groupKey.getAttribute().getIcon())); + Platform.runLater(() -> { + //this TreeNode has a group so append counts to name ... + setText(name + " (" + getNumerator() + getDenominator() + ")"); + //... and use icon corresponding to group type + setGraphic(new ImageView(tNode.getGroup().groupKey.getAttribute().getIcon())); + }); + } - } else { - setTooltip(null); - setText(null); - setGraphic(null); } } @@ -70,10 +80,15 @@ class GroupTreeCell extends TreeCell { * of hashset hits + "/" */ synchronized private String getNumerator() { - final String numerator = (getItem().getGroup().groupKey.getAttribute() != DrawableAttribute.HASHSET) - ? getItem().getGroup().getFilesWithHashSetHitsCount() + "/" - : ""; - return numerator; + try { + final String numerator = (getItem().getGroup().groupKey.getAttribute() != DrawableAttribute.HASHSET) + ? getItem().getGroup().getFilesWithHashSetHitsCount() + "/" + : ""; + return numerator; + } catch (NullPointerException e) { + //instead of this try catch block, remove the listener when assigned a null treeitem / group + return ""; + } } /** diff --git a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/navpanel/GroupTreeItem.java b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/navpanel/GroupTreeItem.java index fa2ba33af7..4232e38704 100644 --- a/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/navpanel/GroupTreeItem.java +++ b/ImageAnalyzer/src/org/sleuthkit/autopsy/imageanalyzer/gui/navpanel/GroupTreeItem.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.scene.control.TreeItem; @@ -189,7 +190,7 @@ class GroupTreeItem extends TreeItem implements Comparable