mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-15 09:17:42 +00:00
cleanup, comments
This commit is contained in:
parent
67dbaa4cdc
commit
9cd5800ce7
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2014 Basis Technology Corp.
|
* Copyright 2014-15 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -33,6 +33,7 @@ import javafx.beans.property.SimpleBooleanProperty;
|
|||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.concurrent.Service;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Cursor;
|
import javafx.scene.Cursor;
|
||||||
@ -75,7 +76,7 @@ import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent;
|
|||||||
* @param <Y> the type of data plotted along the y axis
|
* @param <Y> the type of data plotted along the y axis
|
||||||
* @param <NodeType> the type of nodes used to represent data items
|
* @param <NodeType> the type of nodes used to represent data items
|
||||||
* @param <ChartType> the type of the {@link XYChart<X,Y>} this class uses to
|
* @param <ChartType> the type of the {@link XYChart<X,Y>} this class uses to
|
||||||
* plot the * data.
|
* plot the data.
|
||||||
*
|
*
|
||||||
* TODO: this is becoming (too?) closely tied to the notion that their is a
|
* TODO: this is becoming (too?) closely tied to the notion that their is a
|
||||||
* {@link XYChart} doing the rendering. Is this a good idea? -jm TODO: pull up
|
* {@link XYChart} doing the rendering. Is this a good idea? -jm TODO: pull up
|
||||||
@ -97,16 +98,13 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
* access to chart data via series
|
* access to chart data via series
|
||||||
*/
|
*/
|
||||||
protected final ObservableList<XYChart.Series<X, Y>> dataSeries = FXCollections.<XYChart.Series<X, Y>>observableArrayList();
|
protected final ObservableList<XYChart.Series<X, Y>> dataSeries = FXCollections.<XYChart.Series<X, Y>>observableArrayList();
|
||||||
|
protected final Map<EventType, XYChart.Series<X, Y>> eventTypeToSeriesMap = new HashMap<>();
|
||||||
abstract protected void resetData();
|
|
||||||
|
|
||||||
protected ChartType chart;
|
protected ChartType chart;
|
||||||
|
|
||||||
//// replacement axis label componenets
|
//// replacement axis label componenets
|
||||||
private final Pane leafPane; // container for the leaf lables in the declutterd axis
|
private final Pane leafPane; // container for the leaf lables in the declutterd axis
|
||||||
|
|
||||||
private final Pane branchPane;// container for the branch lables in the declutterd axis
|
private final Pane branchPane;// container for the branch lables in the declutterd axis
|
||||||
|
|
||||||
protected final Region spacer;
|
protected final Region spacer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -148,7 +146,7 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
* @return true if the tick label for the given value should be bold ( has
|
* @return true if the tick label for the given value should be bold ( has
|
||||||
* relevant data), false* otherwise
|
* relevant data), false* otherwise
|
||||||
*/
|
*/
|
||||||
protected abstract Boolean isTickBold(X value);
|
abstract protected Boolean isTickBold(X value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* apply this visualization's 'selection effect' to the given node
|
* apply this visualization's 'selection effect' to the given node
|
||||||
@ -157,27 +155,27 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
* @param applied true if the effect should be applied, false if the effect
|
* @param applied true if the effect should be applied, false if the effect
|
||||||
* should
|
* should
|
||||||
*/
|
*/
|
||||||
protected abstract void applySelectionEffect(NodeType node, Boolean applied);
|
abstract protected void applySelectionEffect(NodeType node, Boolean applied);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a task to execute on a background thread to reload this
|
* @return a task to execute on a background thread to reload this
|
||||||
* visualization with different data.
|
* visualization with different data.
|
||||||
*/
|
*/
|
||||||
protected abstract Task<Boolean> getUpdateTask();
|
abstract protected Task<Boolean> getUpdateTask();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return return the {@link Effect} applied to 'selected nodes' in this
|
* @return return the {@link Effect} applied to 'selected nodes' in this
|
||||||
* visualization, or null if selection is visualized via another
|
* visualization, or null if selection is visualized via another
|
||||||
* mechanism
|
* mechanism
|
||||||
*/
|
*/
|
||||||
protected abstract Effect getSelectionEffect();
|
abstract protected Effect getSelectionEffect();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param tickValue
|
* @param tickValue
|
||||||
*
|
*
|
||||||
* @return a String to use for a tick mark label given a tick value
|
* @return a String to use for a tick mark label given a tick value
|
||||||
*/
|
*/
|
||||||
protected abstract String getTickMarkLabel(X tickValue);
|
abstract protected String getTickMarkLabel(X tickValue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the spacing (in pixels) between tick marks of the horizontal axis. This
|
* the spacing (in pixels) between tick marks of the horizontal axis. This
|
||||||
@ -185,22 +183,27 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
*
|
*
|
||||||
* @return the spacing in pixels between tick marks of the horizontal axis
|
* @return the spacing in pixels between tick marks of the horizontal axis
|
||||||
*/
|
*/
|
||||||
protected abstract double getTickSpacing();
|
abstract protected double getTickSpacing();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the horizontal axis used by this Visualization's chart
|
* @return the horizontal axis used by this Visualization's chart
|
||||||
*/
|
*/
|
||||||
protected abstract Axis<X> getXAxis();
|
abstract protected Axis<X> getXAxis();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the vertical axis used by this Visualization's chart
|
* @return the vertical axis used by this Visualization's chart
|
||||||
*/
|
*/
|
||||||
protected abstract Axis<Y> getYAxis();
|
abstract protected Axis<Y> getYAxis();
|
||||||
|
|
||||||
|
abstract protected void resetData();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* update this visualization based on current state of zoom / filters.
|
* update this visualization based on current state of zoom / filters.
|
||||||
* Primarily this invokes the background {@link Task} returned by
|
* Primarily this invokes the background {@link VisualizationUpdateTask}
|
||||||
* {@link #getUpdateTask()} which derived classes must implement.
|
* returned by {@link #getUpdateTask()}, which derived classes must
|
||||||
|
* implement.
|
||||||
|
*
|
||||||
|
* TODO: replace this logic with a {@link Service} ? -jm
|
||||||
*/
|
*/
|
||||||
final synchronized public void update() {
|
final synchronized public void update() {
|
||||||
if (updateTask != null) {
|
if (updateTask != null) {
|
||||||
@ -236,8 +239,10 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
invalidationListener = null;
|
invalidationListener = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* make a series for each event type in a consistent order
|
||||||
|
*/
|
||||||
protected final void createSeries() {
|
protected final void createSeries() {
|
||||||
//make all series to ensure they get created in consistent order
|
|
||||||
for (EventType eventType : EventType.allTypes) {
|
for (EventType eventType : EventType.allTypes) {
|
||||||
XYChart.Series<X, Y> series = new XYChart.Series<>();
|
XYChart.Series<X, Y> series = new XYChart.Series<>();
|
||||||
series.setName(eventType.getDisplayName());
|
series.setName(eventType.getDisplayName());
|
||||||
@ -246,9 +251,19 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param et the EventType to get the series for
|
||||||
|
*
|
||||||
|
* @return a Series object to contain all the events with the given
|
||||||
|
* EventType
|
||||||
|
*/
|
||||||
|
protected final XYChart.Series<X, Y> getSeries(final EventType et) {
|
||||||
|
return eventTypeToSeriesMap.get(et);
|
||||||
|
}
|
||||||
|
|
||||||
protected AbstractVisualizationPane(TimeLineController controller, Pane partPane, Pane contextPane, Region spacer) {
|
protected AbstractVisualizationPane(TimeLineController controller, Pane partPane, Pane contextPane, Region spacer) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
|
|
||||||
this.filteredEvents = controller.getEventsModel();
|
this.filteredEvents = controller.getEventsModel();
|
||||||
this.filteredEvents.registerForEvents(this);
|
this.filteredEvents.registerForEvents(this);
|
||||||
this.filteredEvents.zoomParametersProperty().addListener(invalidationListener);
|
this.filteredEvents.zoomParametersProperty().addListener(invalidationListener);
|
||||||
@ -268,18 +283,10 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
TimeLineController.getTimeZone().addListener(invalidationListener);
|
TimeLineController.getTimeZone().addListener(invalidationListener);
|
||||||
|
|
||||||
//show tooltip text in status bar
|
//show tooltip text in status bar
|
||||||
hoverProperty().addListener((observable, oldActivated, newActivated) -> {
|
hoverProperty().addListener(observable -> controller.setStatus(isHover() ? DEFAULT_TOOLTIP.getText() : ""));
|
||||||
if (newActivated) {
|
|
||||||
controller.setStatus(DEFAULT_TOOLTIP.getText());
|
|
||||||
} else {
|
|
||||||
controller.setStatus("");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final Map<EventType, XYChart.Series<X, Y>> eventTypeToSeriesMap = new HashMap<>();
|
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void handleRefreshRequested(RefreshRequestedEvent event) {
|
public void handleRefreshRequested(RefreshRequestedEvent event) {
|
||||||
update();
|
update();
|
||||||
@ -477,17 +484,8 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected Interval getTimeRange() {
|
||||||
* NOTE: Because this method modifies data directly used by the chart, this
|
return filteredEvents.timeRangeProperty().get();
|
||||||
* method should only be called from JavaFX thread!
|
|
||||||
*
|
|
||||||
* @param et the EventType to get the series for
|
|
||||||
*
|
|
||||||
* @return a Series object to contain all the events with the given
|
|
||||||
* EventType
|
|
||||||
*/
|
|
||||||
protected final XYChart.Series<X, Y> getSeries(final EventType et) {
|
|
||||||
return eventTypeToSeriesMap.get(et);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract protected class VisualizationUpdateTask<AxisValuesType> extends LoggedTask<Boolean> {
|
abstract protected class VisualizationUpdateTask<AxisValuesType> extends LoggedTask<Boolean> {
|
||||||
@ -496,30 +494,36 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
super(taskName, logStateChanges);
|
super(taskName, logStateChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void installMaskerPane() {
|
/**
|
||||||
MaskerPane maskerPane = new MaskerPane();
|
* Sets initial progress value and message and shows blocking progress
|
||||||
maskerPane.textProperty().bind(messageProperty());
|
* indicator over the visualization. Derived Tasks should be sure to
|
||||||
maskerPane.progressProperty().bind(progressProperty());
|
* call this as part of their call() implementation.
|
||||||
setCenter(new StackPane(chart, maskerPane));
|
*
|
||||||
}
|
* @return true
|
||||||
|
*
|
||||||
protected Interval getTimeRange() {
|
* @throws Exception
|
||||||
return filteredEvents.timeRangeProperty().get();
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
@NbBundle.Messages({"VisualizationUpdateTask.preparing=Analyzing zoom and filter settings"})
|
@NbBundle.Messages({"VisualizationUpdateTask.preparing=Analyzing zoom and filter settings"})
|
||||||
@Override
|
@Override
|
||||||
protected Boolean call() throws Exception {
|
protected Boolean call() throws Exception {
|
||||||
updateProgress(-1, 1);
|
updateProgress(-1, 1);
|
||||||
updateMessage(Bundle.VisualizationUpdateTask_preparing());
|
updateMessage(Bundle.VisualizationUpdateTask_preparing());
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
installMaskerPane();
|
MaskerPane maskerPane = new MaskerPane();
|
||||||
|
maskerPane.textProperty().bind(messageProperty());
|
||||||
|
maskerPane.progressProperty().bind(progressProperty());
|
||||||
|
setCenter(new StackPane(chart, maskerPane));
|
||||||
setCursor(Cursor.WAIT);
|
setCursor(Cursor.WAIT);
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* updates the horisontal axis and removes the blocking progress
|
||||||
|
* indicator. Derived Tasks should be sure to call this as part of their
|
||||||
|
* succeeded() implementation.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void succeeded() {
|
protected void succeeded() {
|
||||||
super.succeeded();
|
super.succeeded();
|
||||||
@ -532,7 +536,8 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for use within the derived impementation of {@link #call() }
|
* Clears the chart data and sets the horisontal axis range. For use
|
||||||
|
* within the derived impementation of {@link #call() }
|
||||||
*
|
*
|
||||||
* @param axisValues
|
* @param axisValues
|
||||||
*/
|
*/
|
||||||
|
@ -252,20 +252,30 @@ public class CountsViewPane extends AbstractVisualizationPane<String, Number, No
|
|||||||
chart.setRangeInfo(rangeInfo); //do we need this. It seems like a hack.
|
chart.setRangeInfo(rangeInfo); //do we need this. It seems like a hack.
|
||||||
|
|
||||||
List<Interval> intervals = rangeInfo.getIntervals();
|
List<Interval> intervals = rangeInfo.getIntervals();
|
||||||
//clear old data, and reset ranges and series
|
|
||||||
List<String> categories = Lists.transform(intervals, rangeInfo::formatForTick);
|
List<String> categories = Lists.transform(intervals, rangeInfo::formatForTick);
|
||||||
|
|
||||||
|
//clear old data, and reset ranges and series
|
||||||
resetChart(categories);
|
resetChart(categories);
|
||||||
|
|
||||||
updateMessage(Bundle.CountsViewPane_loggedTask_updatingCounts());
|
updateMessage(Bundle.CountsViewPane_loggedTask_updatingCounts());
|
||||||
int chartMax = 0;
|
int chartMax = 0;
|
||||||
int numIntervals = intervals.size();
|
int numIntervals = intervals.size();
|
||||||
|
/*
|
||||||
|
* for each interval query database for event counts and add to
|
||||||
|
* chart.
|
||||||
|
*
|
||||||
|
* Doing this in chunks might seem inefficient but it lets us reuse
|
||||||
|
* more cached results as the user navigates to overlapping viewws
|
||||||
|
*
|
||||||
|
* //TODO: implement similar chunked caching in DetailsView -jm
|
||||||
|
*/
|
||||||
for (int i = 0; i < numIntervals; i++) {
|
for (int i = 0; i < numIntervals; i++) {
|
||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
updateProgress(i, numIntervals);
|
updateProgress(i, numIntervals);
|
||||||
final Interval interval = intervals.get(i);
|
final Interval interval = intervals.get(i);
|
||||||
int maxPerInterval = 0; //used in total max tracking
|
int maxPerInterval = 0;
|
||||||
|
|
||||||
//query for current interval
|
//query for current interval
|
||||||
Map<EventType, Long> eventCounts = filteredEvents.getEventCounts(interval);
|
Map<EventType, Long> eventCounts = filteredEvents.getEventCounts(interval);
|
||||||
@ -290,6 +300,7 @@ public class CountsViewPane extends AbstractVisualizationPane<String, Number, No
|
|||||||
}
|
}
|
||||||
chartMax = Math.max(chartMax, maxPerInterval);
|
chartMax = Math.max(chartMax, maxPerInterval);
|
||||||
}
|
}
|
||||||
|
//adjust vertical axis according to scale type and max counts
|
||||||
double countAxisUpperbound = 1 + chartMax * 1.2;
|
double countAxisUpperbound = 1 + chartMax * 1.2;
|
||||||
double tickUnit = ScaleType.LINEAR.equals(scale.get())
|
double tickUnit = ScaleType.LINEAR.equals(scale.get())
|
||||||
? Math.pow(10, Math.max(0, Math.floor(Math.log10(chartMax)) - 1))
|
? Math.pow(10, Math.max(0, Math.floor(Math.log10(chartMax)) - 1))
|
||||||
@ -298,7 +309,7 @@ public class CountsViewPane extends AbstractVisualizationPane<String, Number, No
|
|||||||
countAxis.setTickUnit(tickUnit);
|
countAxis.setTickUnit(tickUnit);
|
||||||
countAxis.setUpperBound(countAxisUpperbound);
|
countAxis.setUpperBound(countAxisUpperbound);
|
||||||
});
|
});
|
||||||
return chartMax > 0;
|
return chartMax > 0; // are there events
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -173,6 +173,48 @@ final class EventCountsChart extends StackedBarChart<String, Number> implements
|
|||||||
return SELECTED_NODE_EFFECT;
|
return SELECTED_NODE_EFFECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the bar click handler,tooltip, border styling and hover effect to the
|
||||||
|
* node generated by StackedBarChart.
|
||||||
|
*
|
||||||
|
* @param series
|
||||||
|
* @param itemIndex
|
||||||
|
* @param item
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"# {0} - count",
|
||||||
|
"# {1} - event type displayname",
|
||||||
|
"# {2} - start date time",
|
||||||
|
"# {3} - end date time",
|
||||||
|
"CountsViewPane.tooltip.text={0} {1} events\nbetween {2}\nand {3}"})
|
||||||
|
@Override
|
||||||
|
protected void dataItemAdded(Series<String, Number> series, int itemIndex, Data<String, Number> item) {
|
||||||
|
ExtraData extraValue = (ExtraData) item.getExtraValue();
|
||||||
|
EventType eventType = extraValue.getEventType();
|
||||||
|
Interval interval = extraValue.getInterval();
|
||||||
|
long count = extraValue.getRawCount();
|
||||||
|
|
||||||
|
item.nodeProperty().addListener((Observable o) -> {
|
||||||
|
final Node node = item.getNode();
|
||||||
|
if (node != null) {
|
||||||
|
node.setStyle("-fx-border-width: 2; -fx-border-color: " + ColorUtilities.getRGBCode(eventType.getSuperType().getColor()) + "; -fx-bar-fill: " + ColorUtilities.getRGBCode(eventType.getColor())); // NON-NLS
|
||||||
|
node.setCursor(Cursor.HAND);
|
||||||
|
|
||||||
|
final Tooltip tooltip = new Tooltip(Bundle.CountsViewPane_tooltip_text(
|
||||||
|
count, eventType.getDisplayName(),
|
||||||
|
item.getXValue(),
|
||||||
|
interval.getEnd().toString(rangeInfo.getTickFormatter())));
|
||||||
|
tooltip.setGraphic(new ImageView(eventType.getFXImage()));
|
||||||
|
Tooltip.install(node, tooltip);
|
||||||
|
|
||||||
|
node.setOnMouseEntered((mouseEntered) -> node.setEffect(new DropShadow(10, eventType.getColor())));
|
||||||
|
node.setOnMouseExited((MouseEvent mouseExited) -> node.setEffect(selectedNodes.contains(node) ? SELECTED_NODE_EFFECT : null));
|
||||||
|
node.setOnMouseClicked(new BarClickHandler(item));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
super.dataItemAdded(series, itemIndex, item); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StringConvereter used to 'format' vertical axis labels
|
* StringConvereter used to 'format' vertical axis labels
|
||||||
*/
|
*/
|
||||||
@ -228,40 +270,6 @@ final class EventCountsChart extends StackedBarChart<String, Number> implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({
|
|
||||||
"# {0} - count",
|
|
||||||
"# {1} - event type displayname",
|
|
||||||
"# {2} - start date time",
|
|
||||||
"# {3} - end date time",
|
|
||||||
"CountsViewPane.tooltip.text={0} {1} events\nbetween {2}\nand {3}"})
|
|
||||||
@Override
|
|
||||||
protected void dataItemAdded(Series<String, Number> series, int itemIndex, Data<String, Number> item) {
|
|
||||||
ExtraData extraValue = (ExtraData) item.getExtraValue();
|
|
||||||
EventType eventType = extraValue.getEventType();
|
|
||||||
Interval interval = extraValue.getInterval();
|
|
||||||
long count = extraValue.getRawCount();
|
|
||||||
|
|
||||||
item.nodeProperty().addListener((Observable o) -> {
|
|
||||||
final Node node = item.getNode();
|
|
||||||
if (node != null) {
|
|
||||||
node.setStyle("-fx-border-width: 2; -fx-border-color: " + ColorUtilities.getRGBCode(eventType.getSuperType().getColor()) + "; -fx-bar-fill: " + ColorUtilities.getRGBCode(eventType.getColor())); // NON-NLS
|
|
||||||
node.setCursor(Cursor.HAND);
|
|
||||||
|
|
||||||
final Tooltip tooltip = new Tooltip(Bundle.CountsViewPane_tooltip_text(
|
|
||||||
count, eventType.getDisplayName(),
|
|
||||||
item.getXValue(),
|
|
||||||
interval.getEnd().toString(rangeInfo.getTickFormatter())));
|
|
||||||
tooltip.setGraphic(new ImageView(eventType.getFXImage()));
|
|
||||||
Tooltip.install(node, tooltip);
|
|
||||||
|
|
||||||
node.setOnMouseEntered((mouseEntered) -> node.setEffect(new DropShadow(10, eventType.getColor())));
|
|
||||||
node.setOnMouseExited((MouseEvent mouseExited) -> node.setEffect(selectedNodes.contains(node) ? SELECTED_NODE_EFFECT : null));
|
|
||||||
node.setOnMouseClicked(new BarClickHandler(item));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
super.dataItemAdded(series, itemIndex, item); //To change body of generated methods, choose Tools | Templates.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EventHandler for click events on nodes representing a bar(segment) in the
|
* EventHandler for click events on nodes representing a bar(segment) in the
|
||||||
* stacked bar chart.
|
* stacked bar chart.
|
||||||
@ -415,6 +423,10 @@ final class EventCountsChart extends StackedBarChart<String, Number> implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulate extra data stuffed into each {@link Data} item to give click
|
||||||
|
* handler and tooltip access to more info.
|
||||||
|
*/
|
||||||
static class ExtraData {
|
static class ExtraData {
|
||||||
|
|
||||||
private final Interval interval;
|
private final Interval interval;
|
||||||
|
@ -110,7 +110,9 @@ public final class EventDetailsChart extends XYChart<DateTime, EventStripe> impl
|
|||||||
|
|
||||||
private ContextMenu chartContextMenu;
|
private ContextMenu chartContextMenu;
|
||||||
|
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)//at start of layout pass
|
||||||
private Set<String> activeQuickHidefilters;
|
private Set<String> activeQuickHidefilters;
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)//at start of layout pass
|
||||||
private double descriptionWidth;
|
private double descriptionWidth;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -420,12 +422,15 @@ public final class EventDetailsChart extends XYChart<DateTime, EventStripe> impl
|
|||||||
protected void layoutPlotChildren() {
|
protected void layoutPlotChildren() {
|
||||||
setCursor(Cursor.WAIT);
|
setCursor(Cursor.WAIT);
|
||||||
maxY.set(0);
|
maxY.set(0);
|
||||||
|
|
||||||
|
//These don't change during a layout pass and are expensive to compute per node. So we do it once at the start
|
||||||
activeQuickHidefilters = getController().getQuickHideFilters().stream()
|
activeQuickHidefilters = getController().getQuickHideFilters().stream()
|
||||||
.filter(AbstractFilter::isActive)
|
.filter(AbstractFilter::isActive)
|
||||||
.map(DescriptionFilter::getDescription)
|
.map(DescriptionFilter::getDescription)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
descriptionWidth = getDescriptionWidth();
|
//This dosn't change during a layout pass and is expensive to compute per node. So we do it once at the start
|
||||||
|
descriptionWidth = truncateAll.get() ? truncateWidth.get() : USE_PREF_SIZE;
|
||||||
|
|
||||||
if (bandByType.get()) {
|
if (bandByType.get()) {
|
||||||
sortedStripeNodes.stream()
|
sortedStripeNodes.stream()
|
||||||
@ -438,10 +443,6 @@ public final class EventDetailsChart extends XYChart<DateTime, EventStripe> impl
|
|||||||
setCursor(null);
|
setCursor(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getDescriptionWidth() {
|
|
||||||
return truncateAll.get() ? truncateWidth.get() : USE_PREF_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadOnlyDoubleProperty maxVScrollProperty() {
|
ReadOnlyDoubleProperty maxVScrollProperty() {
|
||||||
return maxY.getReadOnlyProperty();
|
return maxY.getReadOnlyProperty();
|
||||||
}
|
}
|
||||||
@ -531,8 +532,8 @@ public final class EventDetailsChart extends XYChart<DateTime, EventStripe> impl
|
|||||||
|
|
||||||
//initial test position
|
//initial test position
|
||||||
double yTop = (oneEventPerRow.get())
|
double yTop = (oneEventPerRow.get())
|
||||||
? (localMax + MINIMUM_EVENT_NODE_GAP)
|
? (localMax + MINIMUM_EVENT_NODE_GAP)// if onePerRow, just put it at end
|
||||||
: computeYTop(minY, h, maxXatY, xLeft, xRight); // if onePerRow, just put it at end
|
: computeYTop(minY, h, maxXatY, xLeft, xRight);
|
||||||
|
|
||||||
localMax = Math.max(yTop + h, localMax);
|
localMax = Math.max(yTop + h, localMax);
|
||||||
|
|
||||||
@ -545,6 +546,23 @@ public final class EventDetailsChart extends XYChart<DateTime, EventStripe> impl
|
|||||||
return localMax; //return new max
|
return localMax; //return new max
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given information about the current layout pass so far and about a
|
||||||
|
* particular node, compute the y position of that node.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param yMin the smallest (towards the top of the screen) y position to
|
||||||
|
* consider
|
||||||
|
* @param h the height of the node we are trying to position
|
||||||
|
* @param maxXatY a map from y ranges to the max x within that range. NOTE:
|
||||||
|
* This map will be updated to include the node in question.
|
||||||
|
* @param xLeft the left x-cord of the node to position
|
||||||
|
* @param xRight the left x-cord of the node to position
|
||||||
|
*
|
||||||
|
* @return the y position for the node in question.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
private double computeYTop(double yMin, double h, TreeRangeMap<Double, Double> maxXatY, double xLeft, double xRight) {
|
private double computeYTop(double yMin, double h, TreeRangeMap<Double, Double> maxXatY, double xLeft, double xRight) {
|
||||||
double yTop = yMin;
|
double yTop = yMin;
|
||||||
double yBottom = yTop + h;
|
double yBottom = yTop + h;
|
||||||
@ -589,10 +607,10 @@ public final class EventDetailsChart extends XYChart<DateTime, EventStripe> impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* expose as public
|
* expose as protected
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void requestChartLayout() {
|
protected void requestChartLayout() {
|
||||||
super.requestChartLayout();
|
super.requestChartLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,20 @@
|
|||||||
/*
|
/*
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
* Autopsy Forensic Browser
|
||||||
* To change this template file, choose Tools | Templates
|
*
|
||||||
* and open the template in the editor.
|
* Copyright 2015 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.timeline.ui.detailview;
|
package org.sleuthkit.autopsy.timeline.ui.detailview;
|
||||||
|
|
||||||
@ -14,10 +27,6 @@ import org.sleuthkit.autopsy.timeline.datamodel.EventStripe;
|
|||||||
* More specifically it takes an EventStripeNode and produces a stream of
|
* More specifically it takes an EventStripeNode and produces a stream of
|
||||||
* EventStripes containing the stripes for the given node and all child
|
* EventStripes containing the stripes for the given node and all child
|
||||||
* eventStripes, ignoring intervening EventCluster nodes.
|
* eventStripes, ignoring intervening EventCluster nodes.
|
||||||
*
|
|
||||||
* @see
|
|
||||||
* #loadSubBundles(org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD.RelativeDetail)
|
|
||||||
* for usage
|
|
||||||
*/
|
*/
|
||||||
class StripeFlattener implements Function<EventStripeNode, Stream<EventStripe>> {
|
class StripeFlattener implements Function<EventStripeNode, Stream<EventStripe>> {
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user