cleanup FileTypeUtils and ImageGalleryController, and DrawableFile, etc...

This commit is contained in:
jmillman 2016-01-27 15:44:48 -05:00
parent e3aa664520
commit 626f97ff06
17 changed files with 251 additions and 209 deletions

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Copyright 2015-16 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -38,7 +38,7 @@ import org.sleuthkit.datamodel.TskCoreException;
/**
* Enum style singleton to provide utilities related to questions about a files
* type, and wheather it should be supported in Image Gallery.
* type, and whether it should be supported in Image Gallery.
*
* TODO: refactor this to remove code that duplicates
* org.sleuthkit.autopsy.coreutils.ImageUtils
@ -74,6 +74,7 @@ public enum FileTypeUtils {
* videoExtensions sets.
*/
private static final Set<String> supportedExtensions;
/**
* Lazily instantiated FileTypeDetector to use when the mimetype of a file
* is needed
@ -119,6 +120,14 @@ public enum FileTypeUtils {
videoMimeTypes.addAll(Arrays.asList("application/x-shockwave-flash"));
supportedMimeTypes.addAll(videoMimeTypes);
/*
* TODO: windows .cur cursor files get misidentified as
* application/x-123, so we claim to support application/x-123 so we
* don't miss them: ie this is a hack to cover another bug. when this is
* fixed, we should remove application/x-123 from the list of supported
* mime types.
*/
supportedMimeTypes.addAll(Arrays.asList("application/x-123"));
//add list of mimetypes ImageIO claims to support
@ -126,21 +135,13 @@ public enum FileTypeUtils {
.map(String::toLowerCase)
.collect(Collectors.toList()));
supportedMimeTypes.removeIf("application/octet-stream"::equals); //this is rearely usefull
supportedMimeTypes.removeIf("application/octet-stream"::equals); //this is rarely usefull
}
/**
*
* @return
*/
public static Set<String> getAllSupportedMimeTypes() {
return Collections.unmodifiableSet(supportedMimeTypes);
}
/**
*
* @return
*/
static Set<String> getAllSupportedExtensions() {
return Collections.unmodifiableSet(supportedExtensions);
}
@ -167,12 +168,9 @@ public enum FileTypeUtils {
*/
public static boolean isDrawable(AbstractFile file) throws TskCoreException {
return hasDrawableMimeType(file).orElseGet(() -> {
final boolean contains = FileTypeUtils.supportedExtensions.contains(file.getNameExtension());
final boolean jpegFileHeader = ImageUtils.isJpegFileHeader(file);
final boolean pngFileHeader = ImageUtils.isPngFileHeader(file);
return contains
|| jpegFileHeader
|| pngFileHeader;
return FileTypeUtils.supportedExtensions.contains(file.getNameExtension().toLowerCase())
|| ImageUtils.isJpegFileHeader(file)
|| ImageUtils.isPngFileHeader(file);
});
}

View File

@ -64,6 +64,7 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
import org.sleuthkit.autopsy.core.RuntimeProperties;
import org.sleuthkit.autopsy.coreutils.History;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.imagegallery.actions.UndoRedoManager;
import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager;
@ -695,9 +696,8 @@ public final class ImageGalleryController implements Executor {
* Task that runs when image gallery listening is (re) enabled.
*
* Grabs all files with supported image/video mime types or extensions, and
* adds them to the Drawable DB. Uses the presence of TSK_FILE_TYPE_SIG
* attributes as a approximation to 'analyzed'.
*
* adds them to the Drawable DB. Uses the presence of a mimetype as an
* approximation to 'analyzed'.
*/
static private class CopyAnalyzedFiles extends InnerTask {
@ -747,7 +747,7 @@ public final class ImageGalleryController implements Executor {
int units = 0;
for (final AbstractFile f : files) {
if (isCancelled()) {
LOGGER.log(Level.WARNING, "task cancelled: not all contents may be transfered to database");
LOGGER.log(Level.WARNING, "Task cancelled: not all contents may be transfered to drawable database.");
progressHandle.finish();
break;
}
@ -794,6 +794,7 @@ public final class ImageGalleryController implements Executor {
} catch (TskCoreException ex) {
progressHandle.progress("Stopping copy to drawable db task.");
Logger.getLogger(CopyAnalyzedFiles.class.getName()).log(Level.WARNING, "Stopping copy to drawable db task. Failed to transfer all database contents: " + ex.getMessage());
MessageNotifyUtil.Notify.warn("There was an error populating Image Gallery database.", ex.getMessage());
progressHandle.finish();
updateMessage("");
updateProgress(-1.0);
@ -810,7 +811,7 @@ public final class ImageGalleryController implements Executor {
/**
* task that does pre-ingest copy over of files from a new datasource (uses
* fs_obj_id to identify files from new datasource) *
* fs_obj_id to identify files from new datasources)
*
* TODO: create methods to simplify progress value/text updates to both
* netbeans and ImageGallery progress/status

View File

@ -33,7 +33,7 @@ public class CategorizeGroupAction extends Action {
public CategorizeGroupAction(Category cat, ImageGalleryController controller) {
super(cat.getDisplayName(), (javafx.event.ActionEvent actionEvent) -> {
Set<Long> fileIdSet = ImmutableSet.copyOf(controller.viewState().get().getGroup().fileIds());
Set<Long> fileIdSet = ImmutableSet.copyOf(controller.viewState().get().getGroup().getFileIDs());
new CategorizeAction(controller).addTagsToFiles(controller.getTagsManager().getTagName(cat), "", fileIdSet);
});
setGraphic(new ImageView(DrawableAttribute.CATEGORY.getIcon()));

View File

@ -33,7 +33,7 @@ public class TagGroupAction extends Action {
public TagGroupAction(final TagName tagName, ImageGalleryController controller) {
super(tagName.getDisplayName(), (javafx.event.ActionEvent actionEvent) -> {
Set<Long> fileIdSet = ImmutableSet.copyOf(controller.viewState().get().getGroup().fileIds());
Set<Long> fileIdSet = ImmutableSet.copyOf(controller.viewState().get().getGroup().getFileIDs());
new AddDrawableTagAction(controller).addTagsToFiles(tagName, "", fileIdSet);
});
setGraphic(new ImageView(DrawableAttribute.TAGS.getIcon()));

View File

@ -40,13 +40,22 @@ import org.sleuthkit.datamodel.TagName;
public class DrawableAttribute<T extends Comparable<T>> {
public final static DrawableAttribute<String> MD5_HASH =
new DrawableAttribute<>(AttributeName.MD5_HASH, "MD5 Hash", false, "icon-hashtag.png", f -> Collections.singleton(f.getMd5Hash()));
new DrawableAttribute<>(AttributeName.MD5_HASH, "MD5 Hash",
false,
"icon-hashtag.png",
f -> Collections.singleton(f.getMd5Hash()));
public final static DrawableAttribute<String> 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<Boolean> 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
@ -57,40 +66,76 @@ public class DrawableAttribute<T extends Comparable<T>> {
* advantage. move categories into DrawableDB?
*/
public final static DrawableAttribute<Category> 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<TagName> 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<String> PATH =
new DrawableAttribute<>(AttributeName.PATH, "Path", true, "folder_picture.png", f -> Collections.singleton(f.getDrawablePath()));
new DrawableAttribute<>(AttributeName.PATH, "Path",
true,
"folder_picture.png",
f -> Collections.singleton(f.getDrawablePath()));
public final static DrawableAttribute<String> 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<String> 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<String> 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<String> 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<String> HASHSET =
new DrawableAttribute<>(AttributeName.HASHSET, "Hashset", true, "hashset_hits.png", DrawableFile::getHashSetNamesUnchecked);
new DrawableAttribute<>(AttributeName.HASHSET, "Hashset",
true,
"hashset_hits.png",
DrawableFile::getHashSetNamesUnchecked);
public final static DrawableAttribute<Long> 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<Double> WIDTH =
new DrawableAttribute<>(AttributeName.WIDTH, "Width", false, "arrow-resize.png", f -> Collections.singleton(f.getWidth()));
new DrawableAttribute<>(AttributeName.WIDTH, "Width",
false,
"arrow-resize.png",
f -> Collections.singleton(f.getWidth()));
public final static DrawableAttribute<Double> HEIGHT =
new DrawableAttribute<>(AttributeName.HEIGHT, "Height", false, "arrow-resize-090.png", f -> Collections.singleton(f.getHeight()));
new DrawableAttribute<>(AttributeName.HEIGHT, "Height",
false,
"arrow-resize-090.png",
f -> Collections.singleton(f.getHeight()));
public final static DrawableAttribute<String> MIME_TYPE =
new DrawableAttribute<>(AttributeName.MIME_TYPE, "MIME type", false, " ", f -> Collections.singleton(f.getMIMEType()));
new DrawableAttribute<>(AttributeName.MIME_TYPE, "MIME type",
false,
"mime_types.png",
f -> Collections.singleton(f.getMIMEType()));
final private static List< DrawableAttribute<?>> groupables =
Arrays.asList(PATH, HASHSET, CATEGORY, TAGS, MAKE, MODEL, MIME_TYPE);
@ -105,9 +150,10 @@ public class DrawableAttribute<T extends Comparable<T>> {
this.attrName = name;
this.displayName = new ReadOnlyStringWrapper(displayName);
this.isDBColumn = isDBColumn;
this.imageName = imageName;
this.extractor = extractor;
this.imageName = imageName;
}
private final String imageName;
private Image icon;
@ -117,17 +163,26 @@ public class DrawableAttribute<T extends Comparable<T>> {
private final StringProperty displayName;
private final String imageName;
public Image getIcon() {
if (icon == null) {
if (StringUtils.isBlank(imageName) == false) {
/*
* There is some issue with loading this in the constructor which gets
* called at class load time, so instead we load them lazily the first
* time they are needed
*/
if (null == icon && StringUtils.isNotBlank(imageName)) {
this.icon = new Image("org/sleuthkit/autopsy/imagegallery/images/" + imageName, true);
}
}
return icon;
}
/**
* TODO: override this to load per value icons form some attributes like
* mime-type and category
*/
public Image getIconForValue(T val) {
return getIcon();
}
public static List<DrawableAttribute<?>> getGroupableAttrs() {
return Collections.unmodifiableList(groupables);
}
@ -144,6 +199,10 @@ public class DrawableAttribute<T extends Comparable<T>> {
return displayName.get();
}
public Collection<T> getValue(DrawableFile<?> f) {
return extractor.apply(f);
}
public static enum AttributeName {
NAME,
@ -162,8 +221,4 @@ public class DrawableAttribute<T extends Comparable<T>> {
MD5_HASH,
MIME_TYPE;
}
public Collection<T> getValue(DrawableFile<?> f) {
return extractor.apply(f);
}
}

View File

@ -41,7 +41,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import java.util.stream.Collectors;
import javax.annotation.concurrent.GuardedBy;
import javax.swing.SortOrder;
@ -127,7 +126,7 @@ public final class DrawableDB {
*/
private final Map<DrawableAttribute<?>, PreparedStatement> groupStatementMap = new HashMap<>();
private GroupManager groupManager;
private final GroupManager groupManager;
private final Path dbPath;
@ -1200,6 +1199,7 @@ public final class DrawableDB {
LOGGER.log(Level.SEVERE, "Failed to get content tags by tag name.", ex1);
}
return -1;
}
/**

View File

@ -40,7 +40,6 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.imagegallery.FileTypeUtils;
import org.sleuthkit.autopsy.imagegallery.ThumbnailCache;
import org.sleuthkit.autopsy.imagegallery.utils.TaskUtils;
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -79,8 +78,7 @@ public abstract class DrawableFile<T extends AbstractFile> extends AbstractFile
return create(Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(id), analyzed);
}
SoftReference<Image> imageRef;
// SoftReference<Image> thumbref;
private SoftReference<Image> imageRef;
private String drawablePath;
@ -327,14 +325,6 @@ public abstract class DrawableFile<T extends AbstractFile> extends AbstractFile
abstract Double getHeight();
public String getMIMEType() {
try {
return new FileTypeDetector().getFileType(file);
} catch (FileTypeDetector.FileTypeDetectorInitException | TskCoreException ex) {
return null;
}
}
public String getDrawablePath() {
if (drawablePath != null) {
return drawablePath;

View File

@ -23,13 +23,14 @@ 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.DoubleBinding;
import javafx.beans.binding.IntegerBinding;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.ReadOnlyLongProperty;
import javafx.beans.property.ReadOnlyLongWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
@ -49,25 +50,37 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
return "unknown";
}
private final GroupKey<?> groupKey;
private final ObservableList<Long> fileIDs = FXCollections.observableArrayList();
private final ObservableList<Long> unmodifiableFileIDS = FXCollections.unmodifiableObservableList(fileIDs);
//cache the number of files in this groups with hashset hits
private final ReadOnlyLongWrapper hashSetHitsCount = new ReadOnlyLongWrapper(-1);
public ReadOnlyLongProperty hashSetHitsCountProperty() {
return hashSetHitsCount.getReadOnlyProperty();
}
private final ReadOnlyBooleanWrapper seen = new ReadOnlyBooleanWrapper(false);
//cache the number ofuncategorized files in this group
private final ReadOnlyLongWrapper uncatCount = new ReadOnlyLongWrapper(-1);
//cache the hash hit density for this group
private final DoubleBinding hashDensity = hashSetHitsCount.multiply(100d).divide(Bindings.size(fileIDs));
//cache if this group has been seen
private final ReadOnlyBooleanWrapper seen = new ReadOnlyBooleanWrapper(false);
DrawableGroup(GroupKey<?> groupKey, Set<Long> filesInGroup, boolean seen) {
this.groupKey = groupKey;
this.fileIDs.setAll(filesInGroup);
fileIDs.addListener((ListChangeListener.Change<? extends Long> listchange) -> {
boolean seenChanged = false;
while (false == seenChanged && listchange.next()) {
seenChanged |= listchange.wasAdded();
}
invalidateProperties(seenChanged);
});
this.seen.set(seen);
}
@SuppressWarnings("ReturnOfCollectionOrArrayField")
synchronized public ObservableList<Long> fileIds() {
public synchronized ObservableList<Long> getFileIDs() {
return unmodifiableFileIDS;
}
final public GroupKey<?> groupKey;
public GroupKey<?> getGroupKey() {
return groupKey;
}
@ -84,18 +97,7 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
return groupKey.getValueDisplayName();
}
DrawableGroup(GroupKey<?> groupKey, Set<Long> 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();
}
synchronized public int getSize() {
public synchronized int getSize() {
return fileIDs.size();
}
@ -104,17 +106,19 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
}
public double getHashHitDensity() {
return hashSetHitsCountProperty().divide((double) getSize()).get();
getHashSetHitsCount(); //initialize hashSetHitsCount
return hashDensity.get();
}
synchronized private void invalidateUncatCount() {
uncatCount.set(-1);
public DoubleBinding hashHitDensityProperty() {
getHashSetHitsCount(); //initialize hashSetHitsCount
return hashDensity;
}
/**
* @return the number of files in this group that have hash set hits
*/
synchronized public long getHashSetHitsCount() {
public synchronized long getHashSetHitsCount() {
if (hashSetHitsCount.get() < 0) {
try {
hashSetHitsCount.set(fileIDs.stream()
@ -127,9 +131,15 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
}
return hashSetHitsCount.get();
}
final synchronized public long getUncategorizedCount() {
public ReadOnlyLongProperty hashSetHitsCountProperty() {
getHashSetHitsCount(); //initialize hashSetHitsCount
return hashSetHitsCount.getReadOnlyProperty();
}
public final synchronized long getUncategorizedCount() {
if (uncatCount.get() < 0) {
try {
uncatCount.set(ImageGalleryController.getDefault().getDatabase().getCategoryCount(Category.ZERO, fileIDs));
@ -143,7 +153,51 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
}
public ReadOnlyLongProperty uncatCountProperty() {
getUncategorizedCount(); //initialize uncatCount
return uncatCount.getReadOnlyProperty();
}
void setSeen(boolean isSeen) {
this.seen.set(isSeen);
}
public boolean isSeen() {
return seen.get();
}
public ReadOnlyBooleanWrapper seenProperty() {
return seen;
}
@Subscribe
public synchronized void handleCatChange(CategoryManager.CategoryChangeEvent event) {
if (Iterables.any(event.getFileIDs(), fileIDs::contains)) {
uncatCount.set(-1);
}
}
synchronized void addFile(Long f) {
if (fileIDs.contains(f) == false) {
fileIDs.add(f);
}
}
synchronized void setFiles(Set<? extends Long> newFileIds) {
fileIDs.removeIf(fileID -> newFileIds.contains(fileID) == false);
newFileIds.stream().forEach(this::addFile);
}
synchronized void removeFile(Long f) {
fileIDs.removeAll(f);
}
private void invalidateProperties(boolean seenChanged) {
if (seenChanged) {
seen.set(false);
}
uncatCount.set(-1);
hashSetHitsCount.set(-1);
}
@Override
@ -170,50 +224,10 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
((DrawableGroup) obj).groupKey);
}
synchronized void addFile(Long f) {
invalidateUncatCount();
if (fileIDs.contains(f) == false) {
fileIDs.add(f);
}
}
synchronized void setFiles(Set<? extends Long> newFileIds) {
fileIDs.removeIf((Long t) -> newFileIds.contains(t) == false);
for (Long f : newFileIds) {
if (fileIDs.contains(f) == false) {
fileIDs.add(f);
seen.set(false);
}
}
}
synchronized void removeFile(Long f) {
fileIDs.removeAll(f);
invalidateUncatCount();
}
// By default, sort by group key name
@Override
public int compareTo(DrawableGroup other) {
return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName());
}
void setSeen(boolean isSeen) {
this.seen.set(isSeen);
}
public ReadOnlyBooleanWrapper seenProperty() {
return seen;
}
public boolean isSeen() {
return seen.get();
}
@Subscribe
synchronized public void handleCatChange(CategoryManager.CategoryChangeEvent event) {
if (Iterables.any(event.getFileIDs(), fileIDs::contains)) {
invalidateUncatCount();
}
}
}

View File

@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.imagegallery.datamodel.grouping;
import java.util.Map;
import java.util.Objects;
import javafx.scene.image.Image;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
import org.sleuthkit.datamodel.TagName;
@ -88,4 +89,7 @@ public class GroupKey<T extends Comparable<T>> implements Comparable<GroupKey<T>
return val.compareTo(o.val);
}
public Image getIcon() {
return attr.getIconForValue(val);
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-15 Basis Technology Corp.
* Copyright 2013-16 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -35,7 +35,6 @@ 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;
@ -295,7 +294,7 @@ public class GroupManager {
// If we're grouping by category, we don't want to remove empty groups.
if (groupKey.getAttribute() != DrawableAttribute.CATEGORY) {
if (group.fileIds().isEmpty()) {
if (group.getFileIDs().isEmpty()) {
Platform.runLater(() -> {
if (analyzedGroups.contains(group)) {
analyzedGroups.remove(group);
@ -357,12 +356,7 @@ public class GroupManager {
Pattern.compile(",").splitAsStream(objIds)
.map(Long::valueOf)
.filter(db::isInDB)
.findAny().ifPresent(new Consumer<Long>() {
public void accept(Long obj_id) {
types.add(mimeType);
}
});
.findAny().ifPresent(obj_id -> types.add(mimeType));
}
} catch (SQLException | TskCoreException ex) {
Exceptions.printStackTrace(ex);
@ -702,8 +696,8 @@ public class GroupManager {
? "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();
try (SleuthkitCase.CaseDbQuery executeQuery = controller.getSleuthKitCase().executeQuery(query);
ResultSet resultSet = executeQuery.getResultSet();) {
while (resultSet.next()) {
final long fileID = resultSet.getLong("obj_id");
if (db.isInDB(fileID)) {

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-14 Basis Technology Corp.
* Copyright 2013-16 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -59,7 +59,7 @@ public enum GroupSortBy implements ComparatorProvider {
GROUP_BY_VALUE("Group Name", true, "folder-rename.png") {
@Override
public Comparator<DrawableGroup> getGrpComparator(final SortOrder sortOrder) {
return applySortOrder(sortOrder, Comparator.comparing(t -> t.groupKey.getValueDisplayName()));
return applySortOrder(sortOrder, Comparator.comparing(t -> t.getGroupByValueDislpayName()));
}
@Override
@ -71,10 +71,6 @@ public enum GroupSortBy implements ComparatorProvider {
* don't sort the groups just use what ever order they come in (ingest
* order)
*/
/**
* don't sort the groups just use what ever order they come in (ingest
* order)
*/
NONE("None", false, "prohibition.png") {
@Override
public Comparator<DrawableGroup> getGrpComparator(SortOrder sortOrder) {

View File

@ -254,7 +254,7 @@ public class GroupPane extends BorderPane {
private final InvalidationListener filesSyncListener = (observable) -> {
final String header = getHeaderString();
final List<Long> fileIds = getGroup().fileIds();
final List<Long> fileIds = getGroup().getFileIDs();
Platform.runLater(() -> {
slideShowToggle.setDisable(fileIds.isEmpty());
gridView.getItems().setAll(fileIds);
@ -289,8 +289,8 @@ public class GroupPane extends BorderPane {
}
//assign last selected file or if none first file in group
if (slideShowFileID == null || getGroup().fileIds().contains(slideShowFileID) == false) {
slideShowPane.setFile(getGroup().fileIds().get(0));
if (slideShowFileID == null || getGroup().getFileIDs().contains(slideShowFileID) == false) {
slideShowPane.setFile(getGroup().getFileIDs().get(0));
} else {
slideShowPane.setFile(slideShowFileID);
}
@ -324,7 +324,7 @@ public class GroupPane extends BorderPane {
}
private void selectAllFiles() {
selectionModel.clearAndSelectAll(getGroup().fileIds());
selectionModel.clearAndSelectAll(getGroup().getFileIDs());
}
/**
@ -676,7 +676,7 @@ public class GroupPane extends BorderPane {
if (isNull(viewState) || isNull(viewState.getGroup())) {
if (nonNull(getGroup())) {
getGroup().fileIds().removeListener(filesSyncListener);
getGroup().getFileIDs().removeListener(filesSyncListener);
}
this.grouping.set(null);
@ -695,16 +695,16 @@ public class GroupPane extends BorderPane {
} else {
if (getGroup() != viewState.getGroup()) {
if (nonNull(getGroup())) {
getGroup().fileIds().removeListener(filesSyncListener);
getGroup().getFileIDs().removeListener(filesSyncListener);
}
this.grouping.set(viewState.getGroup());
getGroup().fileIds().addListener(filesSyncListener);
getGroup().getFileIDs().addListener(filesSyncListener);
final String header = getHeaderString();
Platform.runLater(() -> {
gridView.getItems().setAll(getGroup().fileIds());
gridView.getItems().setAll(getGroup().getFileIDs());
slideShowToggle.setDisable(gridView.getItems().isEmpty());
groupLabel.setText(header);
resetScrollBar();
@ -737,10 +737,10 @@ public class GroupPane extends BorderPane {
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();
int endIndex = grouping.get().getFileIDs().indexOf(newFileID);
int startIndex = IntStream.of(grouping.get().getFileIDs().size(), selectionAnchorIndex, endIndex).min().getAsInt();
endIndex = IntStream.of(0, selectionAnchorIndex, endIndex).max().getAsInt();
List<Long> subList = grouping.get().fileIds().subList(Math.max(0, startIndex), Math.min(endIndex, grouping.get().fileIds().size()) + 1);
List<Long> subList = grouping.get().getFileIDs().subList(Math.max(0, startIndex), Math.min(endIndex, grouping.get().getFileIDs().size()) + 1);
selectionModel.clearAndSelectAll(subList.toArray(new Long[subList.size()]));
selectionModel.select(newFileID);
@ -802,7 +802,7 @@ public class GroupPane extends BorderPane {
switch (t.getCode()) {
case SHIFT:
if (selectionAnchorIndex == null) {
selectionAnchorIndex = grouping.get().fileIds().indexOf(selectionModel.lastSelectedProperty().get());
selectionAnchorIndex = grouping.get().getFileIDs().indexOf(selectionModel.lastSelectedProperty().get());
}
t.consume();
break;
@ -880,7 +880,7 @@ public class GroupPane extends BorderPane {
Long lastSelectFileId = selectionModel.lastSelectedProperty().get();
int lastSelectedIndex = lastSelectFileId != null
? grouping.get().fileIds().indexOf(lastSelectFileId)
? grouping.get().getFileIDs().indexOf(lastSelectFileId)
: Optional.ofNullable(selectionAnchorIndex).orElse(0);
final int columns = Math.max((int) Math.floor((gridView.getWidth() - 18) / (gridView.getCellWidth() + gridView.getHorizontalCellSpacing() * 2)), 1);
@ -889,15 +889,15 @@ public class GroupPane extends BorderPane {
// implement proper keyboard based multiselect
int indexOfToBeSelectedTile = lastSelectedIndex + tileIndexMap.get(t.getCode());
final int size = grouping.get().fileIds().size();
final int size = grouping.get().getFileIDs().size();
if (0 > indexOfToBeSelectedTile) {
//don't select past begining of group
} else if (0 <= indexOfToBeSelectedTile && indexOfToBeSelectedTile < size) {
//normal selection within group
makeSelection(t.isShiftDown(), grouping.get().fileIds().get(indexOfToBeSelectedTile));
makeSelection(t.isShiftDown(), grouping.get().getFileIDs().get(indexOfToBeSelectedTile));
} else if (indexOfToBeSelectedTile <= size - 1 + columns - (size % columns)) {
//selection last item if selection is empty space at end of group
makeSelection(t.isShiftDown(), grouping.get().fileIds().get(size - 1));
makeSelection(t.isShiftDown(), grouping.get().getFileIDs().get(size - 1));
} else {
//don't select past end of group
}

View File

@ -118,7 +118,7 @@ public class SlideShowView extends DrawableTileBase {
getGroupPane().grouping().addListener((Observable observable) -> {
syncButtonVisibility();
if (getGroupPane().getGroup() != null) {
getGroupPane().getGroup().fileIds().addListener((Observable observable1) -> {
getGroupPane().getGroup().getFileIDs().addListener((Observable observable1) -> {
syncButtonVisibility();
});
}
@ -128,7 +128,7 @@ public class SlideShowView extends DrawableTileBase {
@ThreadConfined(type = ThreadType.ANY)
private void syncButtonVisibility() {
try {
final boolean hasMultipleFiles = getGroupPane().getGroup().fileIds().size() > 1;
final boolean hasMultipleFiles = getGroupPane().getGroup().getFileIDs().size() > 1;
Platform.runLater(() -> {
rightButton.setVisible(hasMultipleFiles);
leftButton.setVisible(hasMultipleFiles);
@ -265,12 +265,12 @@ public class SlideShowView extends DrawableTileBase {
@ThreadConfined(type = ThreadType.JFX)
synchronized private void cycleSlideShowImage(int direction) {
stopVideo();
final int groupSize = getGroupPane().getGroup().fileIds().size();
final int groupSize = getGroupPane().getGroup().getFileIDs().size();
final Integer nextIndex = getFileID().map(fileID -> {
final int currentIndex = getGroupPane().getGroup().fileIds().indexOf(fileID);
final int currentIndex = getGroupPane().getGroup().getFileIDs().indexOf(fileID);
return (currentIndex + direction + groupSize) % groupSize;
}).orElse(0);
setFile(getGroupPane().getGroup().fileIds().get(nextIndex));
setFile(getGroupPane().getGroup().getFileIDs().get(nextIndex));
}
@ -279,7 +279,7 @@ public class SlideShowView extends DrawableTileBase {
* of y"
*/
private String getSupplementalText() {
final ObservableList<Long> fileIds = getGroupPane().getGroup().fileIds();
final ObservableList<Long> fileIds = getGroupPane().getGroup().getFileIDs();
return getFileID().map(fileID -> " ( " + (fileIds.indexOf(fileID) + 1) + " of " + fileIds.size() + " in group )")
.orElse("");

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2015 Basis Technology Corp.
* Copyright 2015-16 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -62,9 +62,7 @@ class GroupListCell extends ListCell<DrawableGroup> {
*/
private final InvalidationListener seenListener = (Observable o) -> {
final String style = getSeenStyleClass();
Platform.runLater(() -> {
setStyle(style);
});
Platform.runLater(() -> setStyle(style));
};
private final ReadOnlyObjectProperty<GroupComparators<?>> sortOrder;
@ -77,24 +75,19 @@ class GroupListCell extends ListCell<DrawableGroup> {
//since end of path is probably more interesting put ellipsis at front
setTextOverrun(OverrunStyle.LEADING_ELLIPSIS);
Platform.runLater(() -> {
prefWidthProperty().bind(getListView().widthProperty().subtract(15));
});
Platform.runLater(() -> prefWidthProperty().bind(getListView().widthProperty().subtract(15)));
}
/**
* {@inheritDoc }
*/
@Override
protected synchronized void updateItem(final DrawableGroup group, boolean empty) {
//if there was a previous group, remove the listeners
Optional.ofNullable(getItem())
.ifPresent(oldGroup -> {
sortOrder.removeListener(fileCountListener);
oldGroup.fileIds().removeListener(fileCountListener);
oldGroup.getFileIDs().removeListener(fileCountListener);
oldGroup.seenProperty().removeListener(seenListener);
oldGroup.uncatCountProperty().removeListener(fileCountListener);
oldGroup.hashSetHitsCountProperty().removeListener(fileCountListener);
});
super.updateItem(group, empty);
@ -107,28 +100,27 @@ class GroupListCell extends ListCell<DrawableGroup> {
setStyle("");
});
} else {
final String text = getGroupName() + getCountsText();
String style;
Image icon;
if (isNull(group)) {
final String text = getGroupName();
//"dummy" group in file system tree <=> a folder with no drawables
Platform.runLater(() -> {
setTooltip(new Tooltip(text));
setText(text);
setGraphic(new ImageView(EMPTY_FOLDER_ICON));
setStyle("");
});
icon = EMPTY_FOLDER_ICON;
style = "";
} else {
//if number of files in this group changes (eg a file is recategorized), update counts via listener
group.fileIds().addListener(fileCountListener);
group.getFileIDs().addListener(fileCountListener);
group.uncatCountProperty().addListener(fileCountListener);
group.hashSetHitsCountProperty().addListener(fileCountListener);
sortOrder.addListener(fileCountListener);
//if the seen state of this group changes update its style
group.seenProperty().addListener(seenListener);
//and use icon corresponding to group type
final Image icon = group.groupKey.getAttribute().getIcon();
final String text = getGroupName() + getCountsText();
final String style = getSeenStyleClass();
icon = group.getGroupKey().getIcon();
style = getSeenStyleClass();
}
Platform.runLater(() -> {
setTooltip(new Tooltip(text));
setGraphic(new ImageView(icon));
@ -137,7 +129,6 @@ class GroupListCell extends ListCell<DrawableGroup> {
});
}
}
}
private String getGroupName() {
return Optional.ofNullable(getItem())
@ -166,7 +157,6 @@ class GroupListCell extends ListCell<DrawableGroup> {
*/
@Nonnull
private String getCountsText() {
return Optional.ofNullable(getItem())
.map(group ->
" (" + (sortOrder.get() == GroupComparators.ALPHABETICAL

View File

@ -137,13 +137,13 @@ final public class GroupTree extends NavPanel<TreeItem<GroupTreeNode>> {
}
private static List<String> groupingToPath(DrawableGroup g) {
String path = g.groupKey.getValueDisplayName();
if (g.groupKey.getAttribute() != DrawableAttribute.PATH) {
String stripStart = StringUtils.strip(path, "/");
return Arrays.asList(stripStart);
} else {
String path = g.getGroupByValueDislpayName();
if (g.getGroupByAttribute() == DrawableAttribute.PATH) {
String[] cleanPathTokens = StringUtils.stripStart(path, "/").split("/");
return Arrays.asList(cleanPathTokens);
} else {
String stripStart = StringUtils.strip(path, "/");
return Arrays.asList(stripStart);
}
}
}

View File

@ -96,7 +96,7 @@ class GroupTreeCell extends TreeCell<GroupTreeNode> {
.map(GroupTreeNode::getGroup)
.ifPresent(group -> {
sortOrder.addListener(fileCountListener);
group.fileIds().removeListener(fileCountListener);
group.getFileIDs().removeListener(fileCountListener);
group.hashSetHitsCountProperty().removeListener(fileCountListener);
group.seenProperty().removeListener(seenListener);
group.uncatCountProperty().removeListener(fileCountListener);
@ -124,7 +124,7 @@ class GroupTreeCell extends TreeCell<GroupTreeNode> {
} else {
//if number of files in this group changes (eg a file is recategorized), update counts via listener
treeNode.getGroup().fileIds().addListener(fileCountListener);
treeNode.getGroup().getFileIDs().addListener(fileCountListener);
treeNode.getGroup().uncatCountProperty().addListener(fileCountListener);
treeNode.getGroup().hashSetHitsCountProperty().addListener(fileCountListener);
sortOrder.addListener(fileCountListener);
@ -132,7 +132,7 @@ class GroupTreeCell extends TreeCell<GroupTreeNode> {
treeNode.getGroup().seenProperty().addListener(seenListener);
//and use icon corresponding to group type
final Image icon = treeNode.getGroup().groupKey.getAttribute().getIcon();
final Image icon = treeNode.getGroup().getGroupKey().getIcon();
final String text = getGroupName() + getCountsText();
final String style = getSeenStyleClass();
Platform.runLater(() -> {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB