From ce206e1e70f0e1bff8cc0ed882ec9fe00a984f14 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Fri, 22 Jan 2016 15:35:45 -0500 Subject: [PATCH] improve grouping by mime type. --- .../datamodel/grouping/DrawableGroup.java | 48 +++++++++---------- .../datamodel/grouping/GroupManager.java | 25 ++++++++-- .../gui/navpanel/GroupTreeCell.java | 2 + 3 files changed, 44 insertions(+), 31 deletions(-) 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 85d9a9c80a..40467d9f3c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java @@ -23,6 +23,9 @@ import com.google.common.eventbus.Subscribe; import java.util.Objects; import java.util.Set; import java.util.logging.Level; +import javafx.beans.Observable; +import javafx.beans.binding.Bindings; +import javafx.beans.binding.IntegerBinding; import javafx.beans.property.ReadOnlyBooleanWrapper; import javafx.beans.property.ReadOnlyLongProperty; import javafx.beans.property.ReadOnlyLongWrapper; @@ -50,8 +53,11 @@ public class DrawableGroup implements Comparable { private final ObservableList unmodifiableFileIDS = FXCollections.unmodifiableObservableList(fileIDs); //cache the number of files in this groups with hashset hits - private long hashSetHitsCount = -1; + private final ReadOnlyLongWrapper hashSetHitsCount = new ReadOnlyLongWrapper(-1); + public ReadOnlyLongProperty hashSetHitsCountProperty() { + return hashSetHitsCount.getReadOnlyProperty(); + } private final ReadOnlyBooleanWrapper seen = new ReadOnlyBooleanWrapper(false); private final ReadOnlyLongWrapper uncatCount = new ReadOnlyLongWrapper(-1); @@ -81,6 +87,10 @@ public class DrawableGroup implements Comparable { DrawableGroup(GroupKey groupKey, Set filesInGroup, boolean seen) { this.groupKey = groupKey; this.fileIDs.setAll(filesInGroup); + fileIDs.addListener((Observable observable) -> { + hashSetHitsCount.set(-1); + DrawableGroup.this.seen.set(false); + }); this.seen.set(seen); getUncategorizedCount(); } @@ -89,16 +99,12 @@ public class DrawableGroup implements Comparable { return fileIDs.size(); } - public double getHashHitDensity() { - return 100d * getHashSetHitsCount() / (double) getSize(); + public IntegerBinding sizeProperty() { + return Bindings.size(fileIDs); } - /** - * Call to indicate that an file has been added or removed from the group, - * so the hash counts may no longer be accurate. - */ - synchronized private void invalidateHashSetHitsCount() { - hashSetHitsCount = -1; + public double getHashHitDensity() { + return hashSetHitsCountProperty().divide((double) getSize()).get(); } synchronized private void invalidateUncatCount() { @@ -109,18 +115,18 @@ public class DrawableGroup implements Comparable { * @return the number of files in this group that have hash set hits */ synchronized public long getHashSetHitsCount() { - if (hashSetHitsCount < 0) { + if (hashSetHitsCount.get() < 0) { try { - hashSetHitsCount = fileIDs.stream() + hashSetHitsCount.set(fileIDs.stream() .map(fileID -> ImageGalleryController.getDefault().getHashSetManager().isInAnyHashSet(fileID)) .filter(Boolean::booleanValue) - .count(); + .count()); } catch (IllegalStateException | NullPointerException ex) { LOGGER.log(Level.WARNING, "could not access case during getFilesWithHashSetHitsCount()"); } } - return hashSetHitsCount; + return hashSetHitsCount.get(); } final synchronized public long getUncategorizedCount() { @@ -165,21 +171,15 @@ public class DrawableGroup implements Comparable { } synchronized void addFile(Long f) { - invalidateHashSetHitsCount(); invalidateUncatCount(); if (fileIDs.contains(f) == false) { fileIDs.add(f); - seen.set(false); } } synchronized void setFiles(Set newFileIds) { - invalidateHashSetHitsCount(); - invalidateUncatCount(); - boolean filesRemoved = fileIDs.removeIf((Long t) -> newFileIds.contains(t) == false); - if (filesRemoved) { - seen.set(false); - } + fileIDs.removeIf((Long t) -> newFileIds.contains(t) == false); + for (Long f : newFileIds) { if (fileIDs.contains(f) == false) { fileIDs.add(f); @@ -189,11 +189,8 @@ public class DrawableGroup implements Comparable { } synchronized void removeFile(Long f) { - invalidateHashSetHitsCount(); + fileIDs.removeAll(f); invalidateUncatCount(); - if (fileIDs.removeAll(f)) { - seen.set(false); - } } // By default, sort by group key name @@ -213,7 +210,6 @@ public class DrawableGroup implements Comparable { public boolean isSeen() { return seen.get(); } - @Subscribe synchronized public void handleCatChange(CategoryManager.CategoryChangeEvent event) { if (Iterables.any(event.getFileIDs(), fileIDs::contains)) { 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 16869bc2a9..d97d41a3e3 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -35,7 +35,9 @@ import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.function.Consumer; import java.util.logging.Level; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import javafx.application.Platform; @@ -346,12 +348,21 @@ public class GroupManager { break; case MIME_TYPE: HashSet types = new HashSet<>(); - try (SleuthkitCase.CaseDbQuery executeQuery = controller.getSleuthKitCase().executeQuery("select obj_id, mime_type from tsk_files"); + try (SleuthkitCase.CaseDbQuery executeQuery = controller.getSleuthKitCase().executeQuery("select group_concat(obj_id), mime_type from tsk_files group by mime_type "); ResultSet resultSet = executeQuery.getResultSet();) { while (resultSet.next()) { - if (db.isInDB(resultSet.getLong("obj_id"))) { - types.add(resultSet.getString("mime_type")); - } + final String mimeType = resultSet.getString("mime_type"); + String objIds = resultSet.getString("group_concat(obj_id)"); + + Pattern.compile(",").splitAsStream(objIds) + .map(Long::valueOf) + .filter(db::isInDB) + .findAny().ifPresent(new Consumer() { + + public void accept(Long obj_id) { + types.add(mimeType); + } + }); } } catch (SQLException | TskCoreException ex) { Exceptions.printStackTrace(ex); @@ -687,7 +698,11 @@ public class GroupManager { public Set getFileIDsWithMimeType(String mimeType) throws TskCoreException { HashSet hashSet = new HashSet<>(); - try (SleuthkitCase.CaseDbQuery executeQuery = controller.getSleuthKitCase().executeQuery("select obj_id from tsk_files where mime_type = '" + mimeType + "'");) { + String query = (null == mimeType) + ? "SELECT obj_id FROM tsk_files WHERE mime_type IS NULL" + : "SELECT obj_id FROM tsk_files WHERE mime_type = '" + mimeType + "'"; + + try (SleuthkitCase.CaseDbQuery executeQuery = controller.getSleuthKitCase().executeQuery(query);) { ResultSet resultSet = executeQuery.getResultSet(); while (resultSet.next()) { final long fileID = resultSet.getLong("obj_id"); 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 bf7425ec57..d061477b9f 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/GroupTreeCell.java @@ -97,6 +97,7 @@ class GroupTreeCell extends TreeCell { .ifPresent(group -> { sortOrder.addListener(fileCountListener); group.fileIds().removeListener(fileCountListener); + group.hashSetHitsCountProperty().removeListener(fileCountListener); group.seenProperty().removeListener(seenListener); group.uncatCountProperty().removeListener(fileCountListener); }); @@ -125,6 +126,7 @@ class GroupTreeCell extends TreeCell { //if number of files in this group changes (eg a file is recategorized), update counts via listener treeNode.getGroup().fileIds().addListener(fileCountListener); treeNode.getGroup().uncatCountProperty().addListener(fileCountListener); + treeNode.getGroup().hashSetHitsCountProperty().addListener(fileCountListener); sortOrder.addListener(fileCountListener); //if the seen state of this group changes update its style treeNode.getGroup().seenProperty().addListener(seenListener);