mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-14 17:06:16 +00:00
layout optimization WIP
This commit is contained in:
parent
d6543dd967
commit
31cc6ebb95
@ -87,7 +87,7 @@ public interface ArtifactEventType extends EventType {
|
||||
|
||||
/**
|
||||
* bundles the per event information derived from a BlackBoard Artifact into
|
||||
* one object. Primarily used to have a single return value for {@link SubType#buildEventDescription(org.sleuthkit.datamodel.BlackboardArtifact).
|
||||
* one object. Primarily used to have a single return value for null {@link SubType#buildEventDescription(org.sleuthkit.datamodel.BlackboardArtifact).
|
||||
*/
|
||||
static class AttributeEventDescription {
|
||||
|
||||
@ -187,6 +187,8 @@ public interface ArtifactEventType extends EventType {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class EmptyExtractor implements BiFunction<BlackboardArtifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute>, String> {
|
||||
|
||||
@Override
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.timeline.datamodel.eventtype;
|
||||
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -38,7 +39,7 @@ public enum WebTypes implements EventType, ArtifactEventType {
|
||||
"downloads.png", // NON-NLS
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD,
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN),
|
||||
TopPrivateDomainExtractor.getInstance(),
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH),
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL)) {
|
||||
|
||||
@ -67,7 +68,7 @@ public enum WebTypes implements EventType, ArtifactEventType {
|
||||
"cookies.png", // NON-NLS
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE,
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME,
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN),
|
||||
TopPrivateDomainExtractor.getInstance(),
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME),
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE)),
|
||||
//TODO: review description separators
|
||||
@ -75,7 +76,7 @@ public enum WebTypes implements EventType, ArtifactEventType {
|
||||
"bookmarks.png", // NON-NLS
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK,
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN),
|
||||
TopPrivateDomainExtractor.getInstance(),
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL),
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE)),
|
||||
//TODO: review description separators
|
||||
@ -83,7 +84,7 @@ public enum WebTypes implements EventType, ArtifactEventType {
|
||||
"history.png", // NON-NLS
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY,
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN),
|
||||
TopPrivateDomainExtractor.getInstance(),
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL),
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE)),
|
||||
//TODO: review description separators
|
||||
@ -92,7 +93,7 @@ public enum WebTypes implements EventType, ArtifactEventType {
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY,
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT),
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN),
|
||||
TopPrivateDomainExtractor.getInstance(),
|
||||
new AttributeExtractor(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME));
|
||||
|
||||
private final BlackboardAttribute.ATTRIBUTE_TYPE dateTimeAttributeType;
|
||||
@ -186,4 +187,30 @@ public enum WebTypes implements EventType, ArtifactEventType {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static class TopPrivateDomainExtractor extends AttributeExtractor {
|
||||
|
||||
final private static TopPrivateDomainExtractor instance = new TopPrivateDomainExtractor();
|
||||
|
||||
static TopPrivateDomainExtractor getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(BlackboardArtifact artf, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attrMap) {
|
||||
String domainString = StringUtils.substringBefore(super.apply(artf, attrMap), "/");
|
||||
if (InternetDomainName.isValid(domainString)) {
|
||||
InternetDomainName domain = InternetDomainName.from(domainString);
|
||||
return (domain.isUnderPublicSuffix())
|
||||
? domain.topPrivateDomain().toString()
|
||||
: domain.toString();
|
||||
} else {
|
||||
return domainString;
|
||||
}
|
||||
}
|
||||
|
||||
TopPrivateDomainExtractor() {
|
||||
super(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -332,7 +332,7 @@ public class DetailViewPane extends AbstractVisualizationPane<DateTime, EventClu
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
setCursor(Cursor.NONE);
|
||||
setCursor(Cursor.DEFAULT);
|
||||
layoutDateLabels();
|
||||
updateProgress(1, 1);
|
||||
});
|
||||
|
@ -27,11 +27,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Orientation;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
@ -126,7 +126,6 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
|
||||
this.eventBundle = eventBundle;
|
||||
this.parentNode = parentNode;
|
||||
this.chart = chart;
|
||||
|
||||
this.descLOD.set(eventBundle.getDescriptionLoD());
|
||||
sleuthkitCase = chart.getController().getAutopsyCase().getSleuthkitCase();
|
||||
eventsModel = chart.getController().getEventsModel();
|
||||
@ -145,22 +144,24 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
|
||||
setAlignment(Pos.TOP_LEFT);
|
||||
|
||||
setPrefHeight(USE_COMPUTED_SIZE);
|
||||
heightProperty().addListener((Observable observable) -> {
|
||||
chart.layoutPlotChildren();
|
||||
heightProperty().addListener(heightProp -> {
|
||||
chart.requestChartLayout();
|
||||
});
|
||||
setMaxHeight(USE_PREF_SIZE);
|
||||
setMinWidth(USE_PREF_SIZE);
|
||||
setMaxWidth(USE_PREF_SIZE);
|
||||
setLayoutX(chart.getXAxis().getDisplayPosition(new DateTime(eventBundle.getStartMillis())) - getLayoutXCompensation());
|
||||
|
||||
//initialize info hbox
|
||||
infoHBox.setMinWidth(USE_PREF_SIZE);
|
||||
infoHBox.setMaxWidth(USE_PREF_SIZE);
|
||||
infoHBox.setPadding(new Insets(2, 5, 2, 5));
|
||||
infoHBox.setPadding(new Insets(2, 3, 2, 3));
|
||||
infoHBox.setAlignment(Pos.TOP_LEFT);
|
||||
|
||||
//set up subnode pane sizing contraints
|
||||
subNodePane.setPrefHeight(USE_COMPUTED_SIZE);
|
||||
subNodePane.setMaxHeight(USE_PREF_SIZE);
|
||||
subNodePane.setPrefHeight(USE_COMPUTED_SIZE);
|
||||
subNodePane.setMinHeight(24);
|
||||
subNodePane.setPrefWidth(USE_COMPUTED_SIZE);
|
||||
subNodePane.setMinWidth(USE_PREF_SIZE);
|
||||
subNodePane.setMaxWidth(USE_PREF_SIZE);
|
||||
@ -177,7 +178,6 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
|
||||
Tooltip.uninstall(chart, AbstractVisualizationPane.getDragTooltip());
|
||||
showHoverControls(true);
|
||||
toFront();
|
||||
|
||||
});
|
||||
setOnMouseExited((MouseEvent event) -> {
|
||||
showHoverControls(false);
|
||||
@ -269,7 +269,7 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
new Thread(tooltTipTask).start();
|
||||
chart.getController().monitorTask(tooltTipTask);
|
||||
}
|
||||
}
|
||||
@ -329,6 +329,11 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
|
||||
return getEventBundle().getEventIDs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Orientation getContentBias() {
|
||||
return Orientation.HORIZONTAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void layoutChildren() {
|
||||
chart.layoutEventBundleNodes(subNodes, 0);
|
||||
|
@ -212,11 +212,12 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error loading subnodes", ex);
|
||||
}
|
||||
chart.layoutPlotChildren();
|
||||
chart.requestChartLayout();
|
||||
chart.setCursor(null);
|
||||
}
|
||||
};
|
||||
|
||||
new Thread(loggedTask).start();
|
||||
//start task
|
||||
chart.getController().monitorTask(loggedTask);
|
||||
}
|
||||
@ -233,8 +234,7 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
|
||||
protected void layoutChildren() {
|
||||
double chartX = chart.getXAxis().getDisplayPosition(new DateTime(getStartMillis()));
|
||||
double w = chart.getXAxis().getDisplayPosition(new DateTime(getEndMillis())) - chartX;
|
||||
subNodePane.setPrefWidth(w);
|
||||
subNodePane.setMinWidth(Math.max(1, w));
|
||||
subNodePane.setPrefWidth(Math.max(1, w));
|
||||
super.layoutChildren();
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
@ -103,14 +104,11 @@ public final class EventDetailsChart extends XYChart<DateTime, EventCluster> imp
|
||||
private static final int PROJECTED_LINE_STROKE_WIDTH = 5;
|
||||
private static final int MINIMUM_EVENT_NODE_GAP = 4;
|
||||
|
||||
|
||||
private final TimeLineController controller;
|
||||
private final FilteredEventsModel filteredEvents;
|
||||
|
||||
private ContextMenu chartContextMenu;
|
||||
|
||||
|
||||
|
||||
public ContextMenu getChartContextMenu() {
|
||||
return chartContextMenu;
|
||||
}
|
||||
@ -204,7 +202,6 @@ public final class EventDetailsChart extends XYChart<DateTime, EventCluster> imp
|
||||
});
|
||||
Tooltip.install(this, AbstractVisualizationPane.getDragTooltip());
|
||||
|
||||
|
||||
dateAxis.setAutoRanging(false);
|
||||
|
||||
verticalAxis.setVisible(false);//TODO: why doesn't this hide the vertical axis, instead we have to turn off all parts individually? -jm
|
||||
@ -342,7 +339,6 @@ public final class EventDetailsChart extends XYChart<DateTime, EventCluster> imp
|
||||
stripeNodeMap.put(eventStripe, stripeNode);
|
||||
nodeGroup.getChildren().add(stripeNode);
|
||||
data.setNode(stripeNode);
|
||||
layoutPlotChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -359,7 +355,6 @@ public final class EventDetailsChart extends XYChart<DateTime, EventCluster> imp
|
||||
EventStripeNode removedNode = stripeNodeMap.remove(removedStripe);
|
||||
nodeGroup.getChildren().remove(removedNode);
|
||||
data.setNode(null);
|
||||
layoutPlotChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -463,48 +458,42 @@ public final class EventDetailsChart extends XYChart<DateTime, EventCluster> imp
|
||||
* @param nodes collection of nodes to layout
|
||||
* @param minY the minimum y coordinate to position the nodes at.
|
||||
*/
|
||||
synchronized double layoutEventBundleNodes(final Collection<? extends EventBundleNodeBase<?, ?, ?>> nodes, final double minY) {
|
||||
// map from y value (ranges) to right most occupied x value.
|
||||
double layoutEventBundleNodes(final Collection<? extends EventBundleNodeBase<?, ?, ?>> nodes, final double minY) {
|
||||
|
||||
TreeRangeMap<Double, Double> treeRangeMap = TreeRangeMap.create();
|
||||
// maximum y values occupied by any of the given nodes, updated as nodes are layed out.
|
||||
double localMax = minY;
|
||||
|
||||
//for each node do a recursive layout to size it and then position it in first available slot
|
||||
for (final EventBundleNodeBase<?, ?, ?> bundleNode : nodes) {
|
||||
//is the node hiden by a quick hide filter?
|
||||
boolean quickHide = getController().getQuickHideFilters().stream()
|
||||
Set<String> activeQuickHidefilters = getController().getQuickHideFilters().stream()
|
||||
.filter(AbstractFilter::isActive)
|
||||
.anyMatch(filter -> filter.getDescription().equals(bundleNode.getDescription()));
|
||||
.map(DescriptionFilter::getDescription)
|
||||
.collect(Collectors.toSet());
|
||||
//for each node do a recursive layout to size it and then position it in first available slot
|
||||
for (EventBundleNodeBase<?, ?, ?> bundleNode : nodes) {
|
||||
//is the node hiden by a quick hide filter?
|
||||
boolean quickHide = activeQuickHidefilters.contains(bundleNode.getDescription());
|
||||
if (quickHide) {
|
||||
//hide it and skip layout
|
||||
bundleNode.setVisible(false);
|
||||
bundleNode.setManaged(false);
|
||||
} else {
|
||||
//make sure it is shown
|
||||
bundleNode.setVisible(true);
|
||||
bundleNode.setManaged(true);
|
||||
//apply advanced layout description visibility options
|
||||
bundleNode.setDescriptionVisibility(descrVisibility.get());
|
||||
bundleNode.setDescriptionWidth(truncateAll.get() ? truncateWidth.get() : USE_PREF_SIZE);
|
||||
|
||||
//do recursive layout
|
||||
bundleNode.layout();
|
||||
bundleLayoutHelper(bundleNode);
|
||||
//get computed height and width
|
||||
double h = bundleNode.getBoundsInLocal().getHeight();
|
||||
double w = bundleNode.getBoundsInLocal().getWidth();
|
||||
//get left and right x coords from axis plus computed width
|
||||
double xLeft = getXForEpochMillis(bundleNode.getStartMillis()) - bundleNode.getLayoutXCompensation();
|
||||
double xRight = xLeft + w;
|
||||
double xRight = xLeft + w + MINIMUM_EVENT_NODE_GAP;
|
||||
|
||||
//initial test position
|
||||
double yTop = minY;
|
||||
double yBottom = yTop + h;
|
||||
|
||||
if (oneEventPerRow.get()) {
|
||||
// if onePerRow, just put it at end
|
||||
yTop = (localMax + MINIMUM_EVENT_NODE_GAP);
|
||||
yBottom = yTop + h;
|
||||
} else {
|
||||
double yBottom = yTop + h;
|
||||
|
||||
//until the node is not overlapping any others try moving it down.
|
||||
boolean overlapping = true;
|
||||
while (overlapping) {
|
||||
@ -525,21 +514,42 @@ public final class EventDetailsChart extends XYChart<DateTime, EventCluster> imp
|
||||
treeRangeMap.put(Range.closed(yTop, yBottom), xRight);
|
||||
}
|
||||
|
||||
localMax = Math.max(yBottom, localMax);
|
||||
localMax = Math.max(yTop + h, localMax);
|
||||
|
||||
if ((xLeft != bundleNode.getLayoutX()) || (yTop != bundleNode.getLayoutY())) {
|
||||
|
||||
//animate node to new position
|
||||
Timeline timeline = new Timeline(new KeyFrame(Duration.millis(100),
|
||||
new KeyValue(bundleNode.layoutXProperty(), xLeft),
|
||||
new KeyValue(bundleNode.layoutYProperty(), yTop)));
|
||||
new KeyValue(bundleNode.layoutYProperty(), yTop))
|
||||
);
|
||||
timeline.setOnFinished((ActionEvent event) -> {
|
||||
requestChartLayout();
|
||||
});
|
||||
timeline.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
return localMax; //return new max
|
||||
}
|
||||
|
||||
private void bundleLayoutHelper(final EventBundleNodeBase<?, ?, ?> bundleNode) {
|
||||
//make sure it is shown
|
||||
bundleNode.setVisible(true);
|
||||
bundleNode.setManaged(true);
|
||||
//apply advanced layout description visibility options
|
||||
bundleNode.setDescriptionVisibility(descrVisibility.get());
|
||||
bundleNode.setDescriptionWidth(truncateAll.get() ? truncateWidth.get() : USE_PREF_SIZE);
|
||||
|
||||
//do recursive layout
|
||||
bundleNode.layoutChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestChartLayout() {
|
||||
super.requestChartLayout(); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
private double getXForEpochMillis(Long millis) {
|
||||
DateTime dateTime = new DateTime(millis, TimeLineController.getJodaTimeZone());
|
||||
return getXAxis().getDisplayPosition(new DateTime(dateTime));
|
||||
@ -568,6 +578,7 @@ public final class EventDetailsChart extends XYChart<DateTime, EventCluster> imp
|
||||
*/
|
||||
public FilteredEventsModel getFilteredEvents() {
|
||||
return filteredEvents;
|
||||
|
||||
}
|
||||
|
||||
static private class DetailIntervalSelector extends IntervalSelector<DateTime> {
|
||||
@ -673,7 +684,7 @@ public final class EventDetailsChart extends XYChart<DateTime, EventCluster> imp
|
||||
.filter(testFilter::equals)
|
||||
.findFirst().orElseGet(() -> {
|
||||
testFilter.selectedProperty().addListener((Observable observable) -> {
|
||||
layoutPlotChildren();
|
||||
requestChartLayout();
|
||||
});
|
||||
getController().getQuickHideFilters().add(testFilter);
|
||||
return testFilter;
|
||||
|
@ -98,6 +98,8 @@ final public class EventStripeNode extends EventBundleNodeBase<EventStripe, Even
|
||||
descrLabel.setMaxWidth(w);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* apply the 'effect' to visually indicate highlighted nodes
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
#Updated by build script
|
||||
#Mon, 26 Oct 2015 09:54:05 -0400
|
||||
#Mon, 26 Oct 2015 14:50:57 -0400
|
||||
LBL_splash_window_title=Starting Autopsy
|
||||
SPLASH_HEIGHT=314
|
||||
SPLASH_WIDTH=538
|
||||
|
@ -1,4 +1,4 @@
|
||||
#Updated by build script
|
||||
#Mon, 26 Oct 2015 09:54:05 -0400
|
||||
#Mon, 26 Oct 2015 14:50:57 -0400
|
||||
CTL_MainWindow_Title=Autopsy 4.0.0
|
||||
CTL_MainWindow_Title_No_Project=Autopsy 4.0.0
|
||||
|
Loading…
x
Reference in New Issue
Block a user