Merge branch 'develop' of https://github.com/sleuthkit/autopsy into develop

This commit is contained in:
U-Mhmdfy-PC\Mhmdfy 2015-11-25 12:36:00 -05:00
commit 2da9cf8c73
17 changed files with 170 additions and 103 deletions

View File

@ -47,7 +47,7 @@ public interface EventBundle<ParentType extends EventBundle<?>> {
Optional<ParentType> getParentBundle(); Optional<ParentType> getParentBundle();
default long getCount() { default int getCount() {
return getEventIDs().size(); return getEventIDs().size();
} }

View File

@ -18,9 +18,9 @@
*/ */
package org.sleuthkit.autopsy.timeline.datamodel; package org.sleuthkit.autopsy.timeline.datamodel;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
@ -89,28 +89,28 @@ public class EventCluster implements EventBundle<EventStripe> {
/** /**
* the set of ids of the clustered events * the set of ids of the clustered events
*/ */
final private Set<Long> eventIDs; final private ImmutableSet<Long> eventIDs;
/** /**
* the ids of the subset of clustered events that have at least one tag * the ids of the subset of clustered events that have at least one tag
* applied to them * applied to them
*/ */
private final Set<Long> tagged; private final ImmutableSet<Long> tagged;
/** /**
* the ids of the subset of clustered events that have at least one hash set * the ids of the subset of clustered events that have at least one hash set
* hit * hit
*/ */
private final Set<Long> hashHits; private final ImmutableSet<Long> hashHits;
private EventCluster(Interval spanningInterval, EventType type, Set<Long> eventIDs, Set<Long> hashHits, Set<Long> tagged, String description, DescriptionLoD lod, EventStripe parent) { private EventCluster(Interval spanningInterval, EventType type, Set<Long> eventIDs, Set<Long> hashHits, Set<Long> tagged, String description, DescriptionLoD lod, EventStripe parent) {
this.span = spanningInterval; this.span = spanningInterval;
this.type = type; this.type = type;
this.hashHits = hashHits; this.hashHits = ImmutableSet.copyOf(hashHits);
this.tagged = tagged; this.tagged = ImmutableSet.copyOf(tagged);
this.description = description; this.description = description;
this.eventIDs = eventIDs; this.eventIDs = ImmutableSet.copyOf(eventIDs);
this.lod = lod; this.lod = lod;
this.parent = parent; this.parent = parent;
} }
@ -139,18 +139,21 @@ public class EventCluster implements EventBundle<EventStripe> {
} }
@Override @Override
public Set<Long> getEventIDs() { @SuppressWarnings("ReturnOfCollectionOrArrayField")
return Collections.unmodifiableSet(eventIDs); public ImmutableSet<Long> getEventIDs() {
return eventIDs;
} }
@Override @Override
public Set<Long> getEventIDsWithHashHits() { @SuppressWarnings("ReturnOfCollectionOrArrayField")
return Collections.unmodifiableSet(hashHits); public ImmutableSet<Long> getEventIDsWithHashHits() {
return hashHits;
} }
@Override @Override
public Set<Long> getEventIDsWithTags() { @SuppressWarnings("ReturnOfCollectionOrArrayField")
return Collections.unmodifiableSet(tagged); public ImmutableSet<Long> getEventIDsWithTags() {
return tagged;
} }
@Override @Override

View File

@ -19,13 +19,11 @@
package org.sleuthkit.autopsy.timeline.datamodel; package org.sleuthkit.autopsy.timeline.datamodel;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import java.util.Collections; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeSet;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import org.python.google.common.base.Objects; import org.python.google.common.base.Objects;
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType; import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
@ -50,7 +48,7 @@ public final class EventStripe implements EventBundle<EventCluster> {
private final EventCluster parent; private final EventCluster parent;
private final SortedSet<EventCluster> clusters = new TreeSet<>(Comparator.comparing(EventCluster::getStartMillis)); private final ImmutableSortedSet<EventCluster> clusters;
/** /**
* the type of all the events * the type of all the events
@ -70,59 +68,70 @@ public final class EventStripe implements EventBundle<EventCluster> {
/** /**
* the set of ids of the events * the set of ids of the events
*/ */
private final Set<Long> eventIDs = new HashSet<>(); private final ImmutableSet<Long> eventIDs;
/** /**
* the ids of the subset of events that have at least one tag applied to * the ids of the subset of events that have at least one tag applied to
* them * them
*/ */
private final Set<Long> tagged = new HashSet<>(); private final ImmutableSet<Long> tagged;
/** /**
* the ids of the subset of events that have at least one hash set hit * the ids of the subset of events that have at least one hash set hit
*/ */
private final Set<Long> hashHits = new HashSet<>(); private final ImmutableSet<Long> hashHits;
public EventStripe withParent(EventCluster parent) { public EventStripe withParent(EventCluster parent) {
EventStripe eventStripe = new EventStripe(parent, this.type, this.description, this.lod); EventStripe eventStripe = new EventStripe(parent, this.type, this.description, this.lod, clusters, eventIDs, tagged, hashHits);
eventStripe.clusters.addAll(clusters);
eventStripe.eventIDs.addAll(eventIDs);
eventStripe.tagged.addAll(tagged);
eventStripe.hashHits.addAll(hashHits);
return eventStripe; return eventStripe;
} }
private EventStripe(EventCluster parent, EventType type, String description, DescriptionLoD lod) { private EventStripe(EventCluster parent, EventType type, String description, DescriptionLoD lod, SortedSet<EventCluster> clusters, ImmutableSet<Long> eventIDs, ImmutableSet<Long> tagged, ImmutableSet<Long> hashHits) {
this.parent = parent; this.parent = parent;
this.type = type; this.type = type;
this.description = description; this.description = description;
this.lod = lod; this.lod = lod;
this.clusters = ImmutableSortedSet.copyOf(Comparator.comparing(EventCluster::getStartMillis), clusters);
this.eventIDs = eventIDs;
this.tagged = tagged;
this.hashHits = hashHits;
} }
public EventStripe(EventCluster cluster, EventCluster parent) { public EventStripe(EventCluster cluster, EventCluster parent) {
clusters.add(cluster); this.clusters = ImmutableSortedSet.orderedBy(Comparator.comparing(EventCluster::getStartMillis))
.add(cluster).build();
type = cluster.getEventType(); type = cluster.getEventType();
description = cluster.getDescription(); description = cluster.getDescription();
lod = cluster.getDescriptionLoD(); lod = cluster.getDescriptionLoD();
eventIDs.addAll(cluster.getEventIDs()); eventIDs = cluster.getEventIDs();
tagged.addAll(cluster.getEventIDsWithTags()); tagged = cluster.getEventIDsWithTags();
hashHits.addAll(cluster.getEventIDsWithHashHits()); hashHits = cluster.getEventIDsWithHashHits();
this.parent = parent; this.parent = parent;
} }
private EventStripe(EventStripe u, EventStripe v) { private EventStripe(EventStripe u, EventStripe v) {
clusters.addAll(u.clusters); clusters = ImmutableSortedSet.orderedBy(Comparator.comparing(EventCluster::getStartMillis))
clusters.addAll(v.clusters); .addAll(u.getClusters())
.addAll(v.getClusters())
.build();
type = u.getEventType(); type = u.getEventType();
description = u.getDescription(); description = u.getDescription();
lod = u.getDescriptionLoD(); lod = u.getDescriptionLoD();
eventIDs.addAll(u.getEventIDs()); eventIDs = ImmutableSet.<Long>builder()
eventIDs.addAll(v.getEventIDs()); .addAll(u.getEventIDs())
tagged.addAll(u.getEventIDsWithTags()); .addAll(v.getEventIDs())
tagged.addAll(v.getEventIDsWithTags()); .build();
hashHits.addAll(u.getEventIDsWithHashHits()); tagged = ImmutableSet.<Long>builder()
hashHits.addAll(v.getEventIDsWithHashHits()); .addAll(u.getEventIDsWithTags())
.addAll(v.getEventIDsWithTags())
.build();
hashHits = ImmutableSet.<Long>builder()
.addAll(u.getEventIDsWithHashHits())
.addAll(v.getEventIDsWithHashHits())
.build();
parent = u.getParentBundle().orElse(v.getParentBundle().orElse(null)); parent = u.getParentBundle().orElse(v.getParentBundle().orElse(null));
} }
@ -147,18 +156,21 @@ public final class EventStripe implements EventBundle<EventCluster> {
} }
@Override @Override
public Set<Long> getEventIDs() { @SuppressWarnings("ReturnOfCollectionOrArrayField")
return Collections.unmodifiableSet(eventIDs); public ImmutableSet<Long> getEventIDs() {
return eventIDs;
} }
@Override @Override
public Set<Long> getEventIDsWithHashHits() { @SuppressWarnings("ReturnOfCollectionOrArrayField")
return Collections.unmodifiableSet(hashHits); public ImmutableSet<Long> getEventIDsWithHashHits() {
return hashHits;
} }
@Override @Override
public Set<Long> getEventIDsWithTags() { @SuppressWarnings("ReturnOfCollectionOrArrayField")
return Collections.unmodifiableSet(tagged); public ImmutableSet<Long> getEventIDsWithTags() {
return tagged;
} }
@Override @Override
@ -172,14 +184,13 @@ public final class EventStripe implements EventBundle<EventCluster> {
} }
@Override @Override
public SortedSet< EventCluster> getClusters() { @SuppressWarnings("ReturnOfCollectionOrArrayField")
return Collections.unmodifiableSortedSet(clusters); public ImmutableSortedSet< EventCluster> getClusters() {
return clusters;
} }
@Override @Override
public String toString() { public String toString() {
return "EventStripe{" + "description=" + description + ", eventIDs=" + eventIDs.size() + '}'; return "EventStripe{" + "description=" + description + ", eventIDs=" + eventIDs.size() + '}';
} }
} }

View File

@ -18,7 +18,6 @@
*/ */
package org.sleuthkit.autopsy.timeline.ui.detailview; package org.sleuthkit.autopsy.timeline.ui.detailview;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -32,7 +31,10 @@ import javafx.animation.KeyFrame;
import javafx.animation.KeyValue; import javafx.animation.KeyValue;
import javafx.animation.Timeline; import javafx.animation.Timeline;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task; import javafx.concurrent.Task;
import javafx.event.EventHandler; import javafx.event.EventHandler;
import javafx.geometry.Insets; import javafx.geometry.Insets;
@ -120,7 +122,7 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
final Background defaultBackground; final Background defaultBackground;
final Color evtColor; final Color evtColor;
final List<ParentNodeType> subNodes = new ArrayList<>(); final ObservableList<ParentNodeType> subNodes = FXCollections.observableArrayList();
final Pane subNodePane = new Pane(); final Pane subNodePane = new Pane();
final Label descrLabel = new Label(); final Label descrLabel = new Label();
final Label countLabel = new Label(); final Label countLabel = new Label();
@ -152,7 +154,11 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
setBackground(defaultBackground); setBackground(defaultBackground);
setAlignment(Pos.TOP_LEFT); setAlignment(Pos.TOP_LEFT);
setMaxWidth(USE_PREF_SIZE);
infoHBox.setMaxWidth(USE_PREF_SIZE);
subNodePane.setPrefWidth(USE_COMPUTED_SIZE);
subNodePane.setMinWidth(USE_PREF_SIZE);
subNodePane.setMaxWidth(USE_PREF_SIZE);
/* /*
* This triggers the layout when a mousover causes the action buttons to * This triggers the layout when a mousover causes the action buttons to
* interesect with another node, forcing it down. * interesect with another node, forcing it down.
@ -185,6 +191,8 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
setOnMouseClicked(new ClickHandler()); setOnMouseClicked(new ClickHandler());
descVisibility.addListener(observable -> setDescriptionVisibiltiyImpl(descVisibility.get())); descVisibility.addListener(observable -> setDescriptionVisibiltiyImpl(descVisibility.get()));
descVisibility.set(DescriptionVisibility.SHOWN); //trigger listener for initial value descVisibility.set(DescriptionVisibility.SHOWN); //trigger listener for initial value
Bindings.bindContent(subNodePane.getChildren(), subNodes);
} }
final DescriptionLoD getDescriptionLoD() { final DescriptionLoD getDescriptionLoD() {
@ -342,6 +350,8 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
super.layoutChildren(); super.layoutChildren();
} }
abstract ParentNodeType createChildNode(ParentType rawChild);
/** /**
* @param w the maximum width the description label should have * @param w the maximum width the description label should have
*/ */

View File

@ -25,7 +25,10 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import static java.util.Objects.nonNull; import static java.util.Objects.nonNull;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.concurrent.Task; import javafx.concurrent.Task;
import javafx.event.EventHandler; import javafx.event.EventHandler;
@ -45,7 +48,9 @@ import org.controlsfx.control.action.ActionUtils;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.Interval; import org.joda.time.Interval;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.LoggedTask;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.timeline.datamodel.EventCluster; import org.sleuthkit.autopsy.timeline.datamodel.EventCluster;
import org.sleuthkit.autopsy.timeline.datamodel.EventStripe; import org.sleuthkit.autopsy.timeline.datamodel.EventStripe;
import org.sleuthkit.autopsy.timeline.filters.DescriptionFilter; import org.sleuthkit.autopsy.timeline.filters.DescriptionFilter;
@ -63,6 +68,25 @@ import org.sleuthkit.autopsy.timeline.zooming.ZoomParams;
final public class EventClusterNode extends EventBundleNodeBase<EventCluster, EventStripe, EventStripeNode> { final public class EventClusterNode extends EventBundleNodeBase<EventCluster, EventStripe, EventStripeNode> {
private static final Logger LOGGER = Logger.getLogger(EventClusterNode.class.getName()); private static final Logger LOGGER = Logger.getLogger(EventClusterNode.class.getName());
/**
* Use this recursive function to flatten a tree of nodes into an single
* stream. More specifically it takes an EventStripeNode and produces a
* stream of EventStripes conaiting the stripes for the given node and all
* child eventStripes, ignoring intervening EventCluster nodes.
*
* @see
* #loadSubBundles(org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD.RelativeDetail)
* for usage
*/
private final static Function<EventStripeNode, Stream<EventStripe>> stripeFlattener = new Function<EventStripeNode, Stream<EventStripe>>() {
@Override
public Stream<EventStripe> apply(EventStripeNode node) {
return Stream.concat(
Stream.of(node.getEventStripe()),
node.getSubNodes().stream().flatMap(clusterNode -> clusterNode.getSubNodes().stream().flatMap(this)));
}
};
private static final BorderWidths CLUSTER_BORDER_WIDTHS = new BorderWidths(2, 1, 2, 1); private static final BorderWidths CLUSTER_BORDER_WIDTHS = new BorderWidths(2, 1, 2, 1);
private static final Image PLUS = new Image("/org/sleuthkit/autopsy/timeline/images/plus-button.png"); // NON-NLS //NOI18N private static final Image PLUS = new Image("/org/sleuthkit/autopsy/timeline/images/plus-button.png"); // NON-NLS //NOI18N
private static final Image MINUS = new Image("/org/sleuthkit/autopsy/timeline/images/minus-button.png"); // NON-NLS //NOI18N private static final Image MINUS = new Image("/org/sleuthkit/autopsy/timeline/images/minus-button.png"); // NON-NLS //NOI18N
@ -89,6 +113,7 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
subNodePane.setBorder(clusterBorder); subNodePane.setBorder(clusterBorder);
subNodePane.setBackground(defaultBackground); subNodePane.setBackground(defaultBackground);
subNodePane.setMinWidth(1); subNodePane.setMinWidth(1);
subNodePane.setMaxWidth(USE_PREF_SIZE);
setMinHeight(24); setMinHeight(24);
setAlignment(Pos.CENTER_LEFT); setAlignment(Pos.CENTER_LEFT);
@ -118,7 +143,7 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
@Override @Override
void setDescriptionVisibiltiyImpl(DescriptionVisibility descrVis) { void setDescriptionVisibiltiyImpl(DescriptionVisibility descrVis) {
final int size = getEventBundle().getEventIDs().size(); final int size = getEventCluster().getCount();
switch (descrVis) { switch (descrVis) {
case HIDDEN: case HIDDEN:
countLabel.setText(""); countLabel.setText("");
@ -142,10 +167,10 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
* @param expand * @param expand
*/ */
@NbBundle.Messages(value = "EventStripeNode.loggedTask.name=Load sub clusters") @NbBundle.Messages(value = "EventStripeNode.loggedTask.name=Load sub clusters")
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
private synchronized void loadSubBundles(DescriptionLoD.RelativeDetail relativeDetail) { private synchronized void loadSubBundles(DescriptionLoD.RelativeDetail relativeDetail) {
chart.setCursor(Cursor.WAIT); chart.setCursor(Cursor.WAIT);
chart.getEventStripes().removeAll(Lists.transform(subNodes, EventStripeNode::getEventStripe));
subNodes.clear();
/* /*
* make new ZoomParams to query with * make new ZoomParams to query with
@ -159,14 +184,10 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
final EventTypeZoomLevel eventTypeZoomLevel = eventsModel.eventTypeZoomProperty().get(); final EventTypeZoomLevel eventTypeZoomLevel = eventsModel.eventTypeZoomProperty().get();
final ZoomParams zoomParams = new ZoomParams(subClusterSpan, eventTypeZoomLevel, subClusterFilter, getDescriptionLoD()); final ZoomParams zoomParams = new ZoomParams(subClusterSpan, eventTypeZoomLevel, subClusterFilter, getDescriptionLoD());
Task<List<EventStripe>> loggedTask = new Task<List<EventStripe>>() { Task<List<EventStripe>> loggedTask = new LoggedTask<List<EventStripe>>(Bundle.EventStripeNode_loggedTask_name(), false) {
private volatile DescriptionLoD loadedDescriptionLoD = getDescriptionLoD().withRelativeDetail(relativeDetail); private volatile DescriptionLoD loadedDescriptionLoD = getDescriptionLoD().withRelativeDetail(relativeDetail);
{
updateTitle(Bundle.EventStripeNode_loggedTask_name());
}
@Override @Override
protected List<EventStripe> call() throws Exception { protected List<EventStripe> call() throws Exception {
List<EventStripe> bundles; List<EventStripe> bundles;
@ -182,7 +203,9 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
} while (bundles.size() == 1 && nonNull(next)); } while (bundles.size() == 1 && nonNull(next));
// return list of EventStripes representing sub-bundles // return list of EventStripes representing sub-bundles
return Lists.transform(bundles, eventStripe -> eventStripe.withParent(getEventCluster())); return bundles.stream()
.map(eventStripe -> eventStripe.withParent(getEventCluster()))
.collect(Collectors.toList());
} }
@Override @Override
@ -190,14 +213,16 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
try { try {
List<EventStripe> bundles = get(); List<EventStripe> bundles = get();
//clear the existing subnodes
List<EventStripe> transform = subNodes.stream().flatMap(stripeFlattener).collect(Collectors.toList());
chart.getEventStripes().removeAll(transform);
subNodes.clear();
if (bundles.isEmpty()) { if (bundles.isEmpty()) {
subNodePane.getChildren().clear();
getChildren().setAll(subNodePane, infoHBox); getChildren().setAll(subNodePane, infoHBox);
descLOD.set(getEventBundle().getDescriptionLoD()); descLOD.set(getEventBundle().getDescriptionLoD());
} else { } else {
chart.getEventStripes().addAll(bundles); chart.getEventStripes().addAll(bundles);
subNodes.addAll(Lists.transform(bundles, EventClusterNode.this::createStripeNode)); subNodes.addAll(Lists.transform(bundles, EventClusterNode.this::createChildNode));
subNodePane.getChildren().setAll(subNodes);
getChildren().setAll(new VBox(infoHBox, subNodePane)); getChildren().setAll(new VBox(infoHBox, subNodePane));
descLOD.set(loadedDescriptionLoD); descLOD.set(loadedDescriptionLoD);
} }
@ -214,7 +239,8 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
chart.getController().monitorTask(loggedTask); chart.getController().monitorTask(loggedTask);
} }
private EventStripeNode createStripeNode(EventStripe stripe) { @Override
EventStripeNode createChildNode(EventStripe stripe) {
return new EventStripeNode(chart, stripe, this); return new EventStripeNode(chart, stripe, this);
} }

View File

@ -388,7 +388,7 @@ public final class EventDetailsChart extends XYChart<DateTime, EventStripe> impl
* @return all the nodes that pass the given predicate * @return all the nodes that pass the given predicate
*/ */
synchronized Iterable<EventBundleNodeBase<?, ?, ?>> getNodes(Predicate<EventBundleNodeBase<?, ?, ?>> p) { synchronized Iterable<EventBundleNodeBase<?, ?, ?>> getNodes(Predicate<EventBundleNodeBase<?, ?, ?>> p) {
//use this recursive function to flatten the tree of nodes into an iterable. //use this recursive function to flatten the tree of nodes into an single stream.
Function<EventBundleNodeBase<?, ?, ?>, Stream<EventBundleNodeBase<?, ?, ?>>> stripeFlattener = Function<EventBundleNodeBase<?, ?, ?>, Stream<EventBundleNodeBase<?, ?, ?>>> stripeFlattener =
new Function<EventBundleNodeBase<?, ?, ?>, Stream<EventBundleNodeBase<?, ?, ?>>>() { new Function<EventBundleNodeBase<?, ?, ?>, Stream<EventBundleNodeBase<?, ?, ?>>>() {
@Override @Override

View File

@ -68,22 +68,25 @@ final public class EventStripeNode extends EventBundleNodeBase<EventStripe, Even
super(chart, eventStripe, parentNode); super(chart, eventStripe, parentNode);
setMinHeight(48); setMinHeight(48);
//setup description label //setup description label
eventTypeImageView.setImage(getEventType().getFXImage()); eventTypeImageView.setImage(getEventType().getFXImage());
descrLabel.setTextOverrun(OverrunStyle.CENTER_ELLIPSIS); descrLabel.setTextOverrun(OverrunStyle.CENTER_ELLIPSIS);
descrLabel.setGraphic(eventTypeImageView); descrLabel.setGraphic(eventTypeImageView);
descrLabel.setPrefWidth(USE_COMPUTED_SIZE);
setAlignment(subNodePane, Pos.BOTTOM_LEFT); setAlignment(subNodePane, Pos.BOTTOM_LEFT);
for (EventCluster cluster : eventStripe.getClusters()) { for (EventCluster cluster : eventStripe.getClusters()) {
EventClusterNode clusterNode = new EventClusterNode(chart, cluster, this); subNodes.add(createChildNode(cluster));
subNodes.add(clusterNode);
subNodePane.getChildren().addAll(clusterNode);
} }
getChildren().addAll(new VBox(infoHBox, subNodePane)); getChildren().addAll(new VBox(infoHBox, subNodePane));
} }
@Override
EventClusterNode createChildNode(EventCluster cluster) {
return new EventClusterNode(chart, cluster, this);
}
@Override @Override
void showHoverControls(final boolean showControls) { void showHoverControls(final boolean showControls) {
super.showHoverControls(showControls); super.showHoverControls(showControls);
@ -121,7 +124,7 @@ final public class EventStripeNode extends EventBundleNodeBase<EventStripe, Even
@Override @Override
void setDescriptionVisibiltiyImpl(DescriptionVisibility descrVis) { void setDescriptionVisibiltiyImpl(DescriptionVisibility descrVis) {
final int size = getEventStripe().getEventIDs().size(); final int size = getEventStripe().getCount();
switch (descrVis) { switch (descrVis) {
case HIDDEN: case HIDDEN:

View File

@ -37,13 +37,15 @@ class EventDescriptionTreeItem extends NavTreeItem {
*/ */
private final Map<String, EventDescriptionTreeItem> childMap = new HashMap<>(); private final Map<String, EventDescriptionTreeItem> childMap = new HashMap<>();
private final EventBundle<?> bundle; private final EventBundle<?> bundle;
private Comparator<TreeItem<EventBundle<?>>> comparator = TreeComparator.Description;
public EventBundle<?> getEventBundle() { public EventBundle<?> getEventBundle() {
return bundle; return bundle;
} }
EventDescriptionTreeItem(EventBundle<?> g) { EventDescriptionTreeItem(EventBundle<?> g, Comparator<TreeItem<EventBundle<?>>> comp) {
bundle = g; bundle = g;
comparator = comp;
setValue(g); setValue(g);
} }
@ -56,10 +58,11 @@ class EventDescriptionTreeItem extends NavTreeItem {
public void insert(Deque<EventBundle<?>> path) { public void insert(Deque<EventBundle<?>> path) {
EventBundle<?> head = path.removeFirst(); EventBundle<?> head = path.removeFirst();
EventDescriptionTreeItem treeItem = childMap.computeIfAbsent(head.getDescription(), description -> { EventDescriptionTreeItem treeItem = childMap.computeIfAbsent(head.getDescription(), description -> {
EventDescriptionTreeItem newTreeItem = new EventDescriptionTreeItem(head); EventDescriptionTreeItem newTreeItem = new EventDescriptionTreeItem(head, comparator);
newTreeItem.setExpanded(true); newTreeItem.setExpanded(true);
childMap.put(description, newTreeItem); childMap.put(description, newTreeItem);
getChildren().add(newTreeItem); getChildren().add(newTreeItem);
resort(comparator, false);
return newTreeItem; return newTreeItem;
}); });
@ -81,8 +84,12 @@ class EventDescriptionTreeItem extends NavTreeItem {
} }
@Override @Override
public void resort(Comparator<TreeItem<EventBundle<?>>> comp) { void resort(Comparator<TreeItem<EventBundle<?>>> comp, Boolean recursive) {
this.comparator = comp;
FXCollections.sort(getChildren(), comp); FXCollections.sort(getChildren(), comp);
if (recursive) {
childMap.values().forEach(ti -> ti.resort(comp, true));
}
} }
@Override @Override

View File

@ -34,10 +34,11 @@ class EventTypeTreeItem extends NavTreeItem {
*/ */
private final Map<String, EventDescriptionTreeItem> childMap = new HashMap<>(); private final Map<String, EventDescriptionTreeItem> childMap = new HashMap<>();
private final Comparator<TreeItem<EventBundle<?>>> comparator = TreeComparator.Description; private Comparator<TreeItem<EventBundle<?>>> comparator = TreeComparator.Description;
EventTypeTreeItem(EventBundle<?> g) { EventTypeTreeItem(EventBundle<?> g, Comparator<TreeItem<EventBundle<?>>> comp) {
setValue(g); setValue(g);
comparator = comp;
} }
@Override @Override
@ -49,11 +50,11 @@ class EventTypeTreeItem extends NavTreeItem {
public void insert(Deque<EventBundle<?>> path) { public void insert(Deque<EventBundle<?>> path) {
EventBundle<?> head = path.removeFirst(); EventBundle<?> head = path.removeFirst();
EventDescriptionTreeItem treeItem = childMap.computeIfAbsent(head.getDescription(), description -> { EventDescriptionTreeItem treeItem = childMap.computeIfAbsent(head.getDescription(), description -> {
EventDescriptionTreeItem newTreeItem = new EventDescriptionTreeItem(head); EventDescriptionTreeItem newTreeItem = new EventDescriptionTreeItem(head, comparator);
newTreeItem.setExpanded(true); newTreeItem.setExpanded(true);
childMap.put(head.getDescription(), newTreeItem); childMap.put(head.getDescription(), newTreeItem);
getChildren().add(newTreeItem); getChildren().add(newTreeItem);
resort(comparator, false);
return newTreeItem; return newTreeItem;
}); });
@ -63,16 +64,15 @@ class EventTypeTreeItem extends NavTreeItem {
} }
void remove(Deque<EventBundle<?>> path) { void remove(Deque<EventBundle<?>> path) {
EventBundle<?> head = path.removeFirst(); EventBundle<?> head = path.removeFirst();
EventDescriptionTreeItem descTreeItem = childMap.get(head.getDescription()); EventDescriptionTreeItem descTreeItem = childMap.get(head.getDescription());
if (descTreeItem != null) { if (descTreeItem != null) {
if (path.isEmpty() == false) { if (path.isEmpty() == false) {
descTreeItem.remove(path); descTreeItem.remove(path);
} else if (descTreeItem.getChildren().isEmpty()) { }
if (descTreeItem.getChildren().isEmpty()) {
childMap.remove(head.getDescription()); childMap.remove(head.getDescription());
getChildren().remove(descTreeItem); getChildren().remove(descTreeItem);
} }
} }
} }
@ -92,8 +92,11 @@ class EventTypeTreeItem extends NavTreeItem {
} }
@Override @Override
public void resort(Comparator<TreeItem<EventBundle<?>>> comp void resort(Comparator<TreeItem<EventBundle<?>>> comp, Boolean recursive) {
) { this.comparator = comp;
FXCollections.sort(getChildren(), comp); FXCollections.sort(getChildren(), comp);
if (recursive) {
childMap.values().forEach(ti -> ti.resort(comp, true));
}
} }
} }

View File

@ -94,7 +94,6 @@ final public class EventsTree extends BorderPane {
getRoot().remove(bundle); getRoot().remove(bundle);
} }
} }
getRoot().resort(sortByBox.getSelectionModel().getSelectedItem());
}); });
setRoot(); setRoot();
@ -114,11 +113,10 @@ final public class EventsTree extends BorderPane {
@ThreadConfined(type = ThreadConfined.ThreadType.JFX) @ThreadConfined(type = ThreadConfined.ThreadType.JFX)
private void setRoot() { private void setRoot() {
RootItem root = new RootItem(); RootItem root = new RootItem(TreeComparator.Type.reversed().thenComparing(sortByBox.getSelectionModel().getSelectedItem()));
for (EventBundle<?> bundle : detailViewPane.getEventStripes()) { for (EventBundle<?> bundle : detailViewPane.getEventStripes()) {
root.insert(bundle); root.insert(bundle);
} }
root.resort(TreeComparator.Type.reversed().thenComparing(sortByBox.getSelectionModel().getSelectedItem()));
eventsTree.setRoot(root); eventsTree.setRoot(root);
} }
@ -131,7 +129,7 @@ final public class EventsTree extends BorderPane {
sortByBox.getItems().setAll(Arrays.asList(TreeComparator.Description, TreeComparator.Count)); sortByBox.getItems().setAll(Arrays.asList(TreeComparator.Description, TreeComparator.Count));
sortByBox.getSelectionModel().select(TreeComparator.Description); sortByBox.getSelectionModel().select(TreeComparator.Description);
sortByBox.getSelectionModel().selectedItemProperty().addListener((Observable o) -> { sortByBox.getSelectionModel().selectedItemProperty().addListener((Observable o) -> {
getRoot().resort(TreeComparator.Type.reversed().thenComparing(sortByBox.getSelectionModel().getSelectedItem())); getRoot().resort(TreeComparator.Type.reversed().thenComparing(sortByBox.getSelectionModel().getSelectedItem()), true);
}); });
eventsTree.setShowRoot(false); eventsTree.setShowRoot(false);

View File

@ -32,9 +32,8 @@ abstract class NavTreeItem extends TreeItem<EventBundle<?>> {
abstract long getCount(); abstract long getCount();
abstract void resort(Comparator<TreeItem<EventBundle<?>>> comp); abstract void resort(Comparator<TreeItem<EventBundle<?>>> comp, Boolean recursive);
abstract NavTreeItem findTreeItemForEvent(EventBundle<?> t); abstract NavTreeItem findTreeItemForEvent(EventBundle<?> t);
} }

View File

@ -42,9 +42,10 @@ class RootItem extends NavTreeItem {
/** /**
* the comparator if any used to sort the children of this item * the comparator if any used to sort the children of this item
*/ */
// private TreeNodeComparators comp; private Comparator<TreeItem<EventBundle<?>>> comparator = TreeComparator.Type.reversed();
RootItem() {
RootItem(Comparator<TreeItem<EventBundle<?>>> comp) {
comp = comp;
} }
@Override @Override
@ -62,12 +63,13 @@ class RootItem extends NavTreeItem {
EventTypeTreeItem treeItem = childMap.computeIfAbsent(bundle.getEventType().getBaseType(), EventTypeTreeItem treeItem = childMap.computeIfAbsent(bundle.getEventType().getBaseType(),
baseType -> { baseType -> {
EventTypeTreeItem newTreeItem = new EventTypeTreeItem(bundle); EventTypeTreeItem newTreeItem = new EventTypeTreeItem(bundle, comparator);
newTreeItem.setExpanded(true); newTreeItem.setExpanded(true);
getChildren().add(newTreeItem); getChildren().add(newTreeItem);
return newTreeItem; return newTreeItem;
}); });
treeItem.insert(getTreePath(bundle)); treeItem.insert(getTreePath(bundle));
} }
void remove(EventBundle<?> bundle) { void remove(EventBundle<?> bundle) {
@ -96,8 +98,9 @@ class RootItem extends NavTreeItem {
} }
@Override @Override
public void resort(Comparator<TreeItem<EventBundle<?>>> comp) { void resort(Comparator<TreeItem<EventBundle<?>>> comp, Boolean recursive) {
childMap.values().forEach(ti -> ti.resort(comp)); comparator = comp;
childMap.values().forEach(ti -> ti.resort(comp, true));
} }
@Override @Override

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -55,7 +55,7 @@ The following steps will configure Solr to run using an account that will have a
<br><br> <br><br>
\image html javaproperties.PNG \image html javaproperties.PNG
<br><br> <br><br>
A fully updated _serviceinstall.bat_ is shown below, with the changes marked in yellow. A portion of an updated _serviceinstall.bat_ is shown below, with the changes marked in yellow.
<br><br> <br><br>
\image html updatedServiceInstall.PNG \image html updatedServiceInstall.PNG
<br><br> <br><br>
@ -75,7 +75,11 @@ The added part is highlighted in yellow below. Ensure that it is inside the <i>\
<br><br> <br><br>
\image html dataDir.PNG \image html dataDir.PNG
<br><br> <br><br>
7. Edit <i>"C:\Bitnami\solr-4.10.3-0\apache-solr\resources/log4j.properties"</i> to configure Solr log settings: 7. Edit the file <i>"C:\Bitnami\solr-4.10.3-0\apache-solr\solr\zoo.cfg"</i> to add the lines <i>autopurge.snapRetainCount=3</i> and <i>autopurge.purgeInterval=1</i> as shown in the screenshot below.
<br><br>
\image html autoPurge.PNG
<br><br>
8. Edit <i>"C:\Bitnami\solr-4.10.3-0\apache-solr\resources/log4j.properties"</i> to configure Solr log settings:
- Increase the log rotation size threshold (_log4j\.appender\.file\.MaxFileSize_) from 4MB to 100MB. - Increase the log rotation size threshold (_log4j\.appender\.file\.MaxFileSize_) from 4MB to 100MB.
- Remove the _CONSOLE_ appender from the _log4j\.rootLogger_ line. - Remove the _CONSOLE_ appender from the _log4j\.rootLogger_ line.
<br><br> <br><br>
@ -85,9 +89,9 @@ The log file should end up looking like this (modified lines are highlighted in
<br><br> <br><br>
\image html log4j.PNG \image html log4j.PNG
<br><br> <br><br>
8. From an Autopsy installation, copy the folder <i>"C:\Program Files\Autopsy-4.0\autopsy\solr\solr\configsets"</i> to <i>"C:\Bitnami\solr-4.10.3-0\apache-solr\solr"</i>. 9. From an Autopsy installation, copy the folder <i>"C:\Program Files\Autopsy-4.0\autopsy\solr\solr\configsets"</i> to <i>"C:\Bitnami\solr-4.10.3-0\apache-solr\solr"</i>.
9. From an Autopsy installation, copy the folder <i>"C:\Program Files\Autopsy-4.0\autopsy\solr\solr\lib"</i> to <i>"C:\Bitnami\solr-4.10.3-0\apache-solr\solr"</i>. 10. From an Autopsy installation, copy the folder <i>"C:\Program Files\Autopsy-4.0\autopsy\solr\solr\lib"</i> to <i>"C:\Bitnami\solr-4.10.3-0\apache-solr\solr"</i>.
10. Start a Windows command prompt as administrator by pressing _Start_, typing _command_, right clicking on _Command Prompt_, and clicking on _Run as administrator_. Then run the following command to install the _solrJetty_ service: 11. Start a Windows command prompt as administrator by pressing _Start_, typing _command_, right clicking on _Command Prompt_, and clicking on _Run as administrator_. Then run the following command to install the _solrJetty_ service:
<br><br> <br><br>
<i>cmd /c C:\\Bitnami\\solr-4.10.3-0\\apache-solr\\scripts\\serviceinstall.bat INSTALL</i> <i>cmd /c C:\\Bitnami\\solr-4.10.3-0\\apache-solr\\scripts\\serviceinstall.bat INSTALL</i>
<br><br> <br><br>
@ -95,13 +99,13 @@ The log file should end up looking like this (modified lines are highlighted in
<br><br> <br><br>
\image html solrinstall1.PNG \image html solrinstall1.PNG
<br><br> <br><br>
11. Press _Start_, type _services.msc_, and press _Enter_. Find _solrJetty_. If the service is running, press _Stop the service_, then double click it, and switch to the _Log On_ tab to change the logon credentials to a user who will have access to read and write the primary shared drive. If the machine is on a domain, the Account Name will be in the form of _DOMAINNAME\\username_ as shown in the example below. Note that in the screenshot below, the domain name is _DOMAIN_ and the user name is _username_. These are just examples, not real values. 12. Press _Start_, type _services.msc_, and press _Enter_. Find _solrJetty_. If the service is running, press _Stop the service_, then double click it, and switch to the _Log On_ tab to change the logon credentials to a user who will have access to read and write the primary shared drive. If the machine is on a domain, the Account Name will be in the form of _DOMAINNAME\\username_ as shown in the example below. Note that in the screenshot below, the domain name is _DOMAIN_ and the user name is _username_. These are just examples, not real values.
<br><br> <br><br>
\image html solrinstall2.PNG \image html solrinstall2.PNG
<br> <br>
If the machine is on a domain, **make sure** to select the domain with the mouse by going to the _Log On_ tab, clicking _Browse_, then clicking _Locations_ and selecting the domain of interest. Then enter the user name desired and press _Check Names_. When that completes, press _OK_, type in the password once for each box and press _OK_. You may see "The user has been granted the log on as a service right." If the machine is on a domain, **make sure** to select the domain with the mouse by going to the _Log On_ tab, clicking _Browse_, then clicking _Locations_ and selecting the domain of interest. Then enter the user name desired and press _Check Names_. When that completes, press _OK_, type in the password once for each box and press _OK_. You may see "The user has been granted the log on as a service right."
12. You should be able to see the Solr service in a web browser via the URL <i>http://localhost:8983/solr/#/</i> as shown in the screenshot below. 13. You should be able to see the Solr service in a web browser via the URL <i>http://localhost:8983/solr/#/</i> as shown in the screenshot below.
<br><br> <br><br>
\image html solrinstall3.PNG \image html solrinstall3.PNG
<br><br> <br><br>