mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 02:07:42 +00:00
details view node / tree clean up and bugfixes
reinstate wrongly removed layout constraints; bind subnodepane children to subnodes list; keep tree and main visualization in sync better
This commit is contained in:
parent
c534d1dc51
commit
883e48b043
@ -180,6 +180,4 @@ public final class EventStripe implements EventBundle<EventCluster> {
|
||||
public String toString() {
|
||||
return "EventStripe{" + "description=" + description + ", eventIDs=" + eventIDs.size() + '}';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.timeline.ui.detailview;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -32,7 +31,10 @@ import javafx.animation.KeyFrame;
|
||||
import javafx.animation.KeyValue;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Insets;
|
||||
@ -120,7 +122,7 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
|
||||
final Background defaultBackground;
|
||||
final Color evtColor;
|
||||
|
||||
final List<ParentNodeType> subNodes = new ArrayList<>();
|
||||
final ObservableList<ParentNodeType> subNodes = FXCollections.observableArrayList();
|
||||
final Pane subNodePane = new Pane();
|
||||
final Label descrLabel = new Label();
|
||||
final Label countLabel = new Label();
|
||||
@ -152,7 +154,11 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
|
||||
|
||||
setBackground(defaultBackground);
|
||||
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
|
||||
* interesect with another node, forcing it down.
|
||||
@ -185,6 +191,8 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
|
||||
setOnMouseClicked(new ClickHandler());
|
||||
descVisibility.addListener(observable -> setDescriptionVisibiltiyImpl(descVisibility.get()));
|
||||
descVisibility.set(DescriptionVisibility.SHOWN); //trigger listener for initial value
|
||||
|
||||
Bindings.bindContent(subNodePane.getChildren(), subNodes);
|
||||
}
|
||||
|
||||
final DescriptionLoD getDescriptionLoD() {
|
||||
@ -342,6 +350,8 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
|
||||
super.layoutChildren();
|
||||
}
|
||||
|
||||
abstract ParentNodeType createChildNode(ParentType rawChild);
|
||||
|
||||
/**
|
||||
* @param w the maximum width the description label should have
|
||||
*/
|
||||
|
@ -25,7 +25,10 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import static java.util.Objects.nonNull;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.event.EventHandler;
|
||||
@ -45,7 +48,9 @@ import org.controlsfx.control.action.ActionUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Interval;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.LoggedTask;
|
||||
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.EventStripe;
|
||||
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> {
|
||||
|
||||
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 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
|
||||
@ -89,6 +113,7 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
|
||||
subNodePane.setBorder(clusterBorder);
|
||||
subNodePane.setBackground(defaultBackground);
|
||||
subNodePane.setMinWidth(1);
|
||||
subNodePane.setMaxWidth(USE_PREF_SIZE);
|
||||
setMinHeight(24);
|
||||
setAlignment(Pos.CENTER_LEFT);
|
||||
|
||||
@ -142,10 +167,10 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
|
||||
* @param expand
|
||||
*/
|
||||
@NbBundle.Messages(value = "EventStripeNode.loggedTask.name=Load sub clusters")
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
private synchronized void loadSubBundles(DescriptionLoD.RelativeDetail relativeDetail) {
|
||||
chart.setCursor(Cursor.WAIT);
|
||||
chart.getEventStripes().removeAll(Lists.transform(subNodes, EventStripeNode::getEventStripe));
|
||||
subNodes.clear();
|
||||
|
||||
|
||||
/*
|
||||
* 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 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);
|
||||
|
||||
{
|
||||
updateTitle(Bundle.EventStripeNode_loggedTask_name());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<EventStripe> call() throws Exception {
|
||||
List<EventStripe> bundles;
|
||||
@ -182,7 +203,9 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
|
||||
} while (bundles.size() == 1 && nonNull(next));
|
||||
|
||||
// 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
|
||||
@ -190,14 +213,16 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
|
||||
try {
|
||||
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()) {
|
||||
subNodePane.getChildren().clear();
|
||||
getChildren().setAll(subNodePane, infoHBox);
|
||||
descLOD.set(getEventBundle().getDescriptionLoD());
|
||||
} else {
|
||||
chart.getEventStripes().addAll(bundles);
|
||||
subNodes.addAll(Lists.transform(bundles, EventClusterNode.this::createStripeNode));
|
||||
subNodePane.getChildren().setAll(subNodes);
|
||||
subNodes.addAll(Lists.transform(bundles, EventClusterNode.this::createChildNode));
|
||||
getChildren().setAll(new VBox(infoHBox, subNodePane));
|
||||
descLOD.set(loadedDescriptionLoD);
|
||||
}
|
||||
@ -214,7 +239,8 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
|
||||
chart.getController().monitorTask(loggedTask);
|
||||
}
|
||||
|
||||
private EventStripeNode createStripeNode(EventStripe stripe) {
|
||||
@Override
|
||||
EventStripeNode createChildNode(EventStripe stripe) {
|
||||
return new EventStripeNode(chart, stripe, this);
|
||||
}
|
||||
|
||||
|
@ -388,7 +388,7 @@ public final class EventDetailsChart extends XYChart<DateTime, EventStripe> impl
|
||||
* @return all the nodes that pass the given predicate
|
||||
*/
|
||||
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 =
|
||||
new Function<EventBundleNodeBase<?, ?, ?>, Stream<EventBundleNodeBase<?, ?, ?>>>() {
|
||||
@Override
|
||||
|
@ -73,17 +73,20 @@ final public class EventStripeNode extends EventBundleNodeBase<EventStripe, Even
|
||||
eventTypeImageView.setImage(getEventType().getFXImage());
|
||||
descrLabel.setTextOverrun(OverrunStyle.CENTER_ELLIPSIS);
|
||||
descrLabel.setGraphic(eventTypeImageView);
|
||||
|
||||
descrLabel.setPrefWidth(USE_COMPUTED_SIZE);
|
||||
setAlignment(subNodePane, Pos.BOTTOM_LEFT);
|
||||
for (EventCluster cluster : eventStripe.getClusters()) {
|
||||
EventClusterNode clusterNode = new EventClusterNode(chart, cluster, this);
|
||||
subNodes.add(clusterNode);
|
||||
subNodePane.getChildren().addAll(clusterNode);
|
||||
subNodes.add(createChildNode(cluster));
|
||||
}
|
||||
|
||||
getChildren().addAll(new VBox(infoHBox, subNodePane));
|
||||
}
|
||||
|
||||
@Override
|
||||
EventClusterNode createChildNode(EventCluster cluster) {
|
||||
return new EventClusterNode(chart, cluster, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
void showHoverControls(final boolean showControls) {
|
||||
super.showHoverControls(showControls);
|
||||
|
@ -64,16 +64,15 @@ class EventTypeTreeItem extends NavTreeItem {
|
||||
}
|
||||
|
||||
void remove(Deque<EventBundle<?>> path) {
|
||||
|
||||
EventBundle<?> head = path.removeFirst();
|
||||
EventDescriptionTreeItem descTreeItem = childMap.get(head.getDescription());
|
||||
if (descTreeItem != null) {
|
||||
if (path.isEmpty() == false) {
|
||||
descTreeItem.remove(path);
|
||||
} else if (descTreeItem.getChildren().isEmpty()) {
|
||||
}
|
||||
if (descTreeItem.getChildren().isEmpty()) {
|
||||
childMap.remove(head.getDescription());
|
||||
getChildren().remove(descTreeItem);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user