mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-18 18:47:43 +00:00
Merge remote-tracking branch 'upstream/develop' into TL-list-view
Conflicts: Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailsChart.java
This commit is contained in:
commit
695c5c69c3
@ -676,9 +676,6 @@ public class TimeLineController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({"# {0} - the number of events",
|
|
||||||
"Timeline.pushDescrLOD.confdlg.msg=You are about to show details for {0} events. This might be very slow or even crash Autopsy.\n\nDo you want to continue?",
|
|
||||||
"Timeline.pushDescrLOD.confdlg.title=Change description level of detail?"})
|
|
||||||
synchronized public void pushDescrLOD(DescriptionLoD newLOD) {
|
synchronized public void pushDescrLOD(DescriptionLoD newLOD) {
|
||||||
ZoomParams currentZoom = filteredEvents.zoomParametersProperty().get();
|
ZoomParams currentZoom = filteredEvents.zoomParametersProperty().get();
|
||||||
if (currentZoom == null) {
|
if (currentZoom == null) {
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.timeline.ui;
|
package org.sleuthkit.autopsy.timeline.ui;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@ -68,6 +69,7 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
|||||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
||||||
|
import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for TimeLineChart based visualizations.
|
* Abstract base class for TimeLineChart based visualizations.
|
||||||
@ -410,6 +412,17 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
controller.monitorTask(updateTask);
|
controller.monitorTask(updateTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a RefreshRequestedEvent from the events model by updating the
|
||||||
|
* visualization.
|
||||||
|
*
|
||||||
|
* @param event The RefreshRequestedEvent to handle.
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
public void handleRefreshRequested(RefreshRequestedEvent event) {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispose of this visualization and any resources it holds onto.
|
* Dispose of this visualization and any resources it holds onto.
|
||||||
*/
|
*/
|
||||||
|
@ -336,8 +336,8 @@ public abstract class IntervalSelector<X> extends BorderPane {
|
|||||||
IntervalSelector<X> newIntervalSelector();
|
IntervalSelector<X> newIntervalSelector();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clear any references to previous interval selectors , including
|
* Clear any references to previous interval selectors , including
|
||||||
* removing the interval selector from the ui / scene-graph
|
* removing the interval selector from the UI / scene-graph.
|
||||||
*/
|
*/
|
||||||
void clearIntervalSelector();
|
void clearIntervalSelector();
|
||||||
|
|
||||||
|
@ -44,8 +44,10 @@ public interface TimeLineChart<X> extends ContextMenuProvider, IntervalSelectorP
|
|||||||
|
|
||||||
ObservableList<? extends Node> getSelectedNodes();
|
ObservableList<? extends Node> getSelectedNodes();
|
||||||
|
|
||||||
|
@Override
|
||||||
IntervalSelector<? extends X> getIntervalSelector();
|
IntervalSelector<? extends X> getIntervalSelector();
|
||||||
|
|
||||||
|
@Override
|
||||||
void setIntervalSelector(IntervalSelector<? extends X> newIntervalSelector);
|
void setIntervalSelector(IntervalSelector<? extends X> newIntervalSelector);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,30 +56,29 @@ public interface TimeLineChart<X> extends ContextMenuProvider, IntervalSelectorP
|
|||||||
*
|
*
|
||||||
* @return a new interval selector
|
* @return a new interval selector
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
IntervalSelector<X> newIntervalSelector();
|
IntervalSelector<X> newIntervalSelector();
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* clear any references to previous interval selectors , including removing
|
|
||||||
* the interval selector from the ui / scene-graph
|
|
||||||
*/
|
|
||||||
void clearIntervalSelector();
|
void clearIntervalSelector();
|
||||||
|
|
||||||
|
@Override
|
||||||
public Axis<X> getXAxis();
|
public Axis<X> getXAxis();
|
||||||
|
|
||||||
|
@Override
|
||||||
public TimeLineController getController();
|
public TimeLineController getController();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drag handler class used by {@link TimeLineChart}s to create
|
* Drag handler class used by TimeLineCharts to create IntervalSelectors
|
||||||
* {@link IntervalSelector}s
|
|
||||||
*
|
*
|
||||||
* @param <X> the type of values along the horizontal axis
|
* @param <X> The type of values along the horizontal axis.
|
||||||
* @param <Y> the type of chart this is a drag handler for
|
* @param <Y> The type of chart this is a drag handler for.
|
||||||
*/
|
*/
|
||||||
public static class ChartDragHandler<X, Y extends Region & IntervalSelectorProvider<X>> implements EventHandler<MouseEvent> {
|
public static class ChartDragHandler<X, Y extends Region & IntervalSelectorProvider<X>> implements EventHandler<MouseEvent> {
|
||||||
|
|
||||||
private final Y chart;
|
private final Y chart;
|
||||||
|
|
||||||
private double startX; //hanlder mainstains position of drag start
|
private double startX; //hanlder maintains position of drag start
|
||||||
|
|
||||||
public ChartDragHandler(Y chart) {
|
public ChartDragHandler(Y chart) {
|
||||||
this.chart = chart;
|
this.chart = chart;
|
||||||
|
@ -288,7 +288,7 @@ final public class VisualizationPanel extends BorderPane {
|
|||||||
} else if (newValue == detailsToggle && oldValue != null) {
|
} else if (newValue == detailsToggle && oldValue != null) {
|
||||||
controller.setVisualizationMode(VisualizationMode.DETAIL);
|
controller.setVisualizationMode(VisualizationMode.DETAIL);
|
||||||
} else if (newValue == listToggle && oldValue != null) {
|
} else if (newValue == listToggle && oldValue != null) {
|
||||||
controller.setViewMode(VisualizationMode.LIST);
|
controller.setVisualizationMode(VisualizationMode.LIST);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -387,8 +387,8 @@ final public class VisualizationPanel extends BorderPane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a RefreshRequestedEvent from the events model by refreshing the
|
* Handle a RefreshRequestedEvent from the events model by clearing the
|
||||||
* visualization.
|
* refresh notification.
|
||||||
*
|
*
|
||||||
* NOTE: This VisualizationPanel must be registered with the
|
* NOTE: This VisualizationPanel must be registered with the
|
||||||
* filteredEventsModel's EventBus in order for this handler to be invoked.
|
* filteredEventsModel's EventBus in order for this handler to be invoked.
|
||||||
@ -397,7 +397,6 @@ final public class VisualizationPanel extends BorderPane {
|
|||||||
*/
|
*/
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void handleRefreshRequested(RefreshRequestedEvent event) {
|
public void handleRefreshRequested(RefreshRequestedEvent event) {
|
||||||
visualization.refresh();
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
if (Bundle.VisualizationPanel_tagsAddedOrDeleted().equals(notificationPane.getText())) {
|
if (Bundle.VisualizationPanel_tagsAddedOrDeleted().equals(notificationPane.getText())) {
|
||||||
notificationPane.hide();
|
notificationPane.hide();
|
||||||
@ -548,22 +547,18 @@ final public class VisualizationPanel extends BorderPane {
|
|||||||
controller.monitorTask(histogramTask);
|
controller.monitorTask(histogramTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the time selection UI to match the current zoome paramaters.
|
||||||
|
*/
|
||||||
private void refreshTimeUI() {
|
private void refreshTimeUI() {
|
||||||
refreshTimeUI(filteredEvents.timeRangeProperty().get());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshTimeUI(Interval interval) {
|
|
||||||
|
|
||||||
RangeDivisionInfo rangeDivisionInfo = RangeDivisionInfo.getRangeDivisionInfo(filteredEvents.getSpanningInterval());
|
RangeDivisionInfo rangeDivisionInfo = RangeDivisionInfo.getRangeDivisionInfo(filteredEvents.getSpanningInterval());
|
||||||
|
|
||||||
final long minTime = rangeDivisionInfo.getLowerBound();
|
final long minTime = rangeDivisionInfo.getLowerBound();
|
||||||
final long maxTime = rangeDivisionInfo.getUpperBound();
|
final long maxTime = rangeDivisionInfo.getUpperBound();
|
||||||
|
|
||||||
long startMillis = interval.getStartMillis();
|
long startMillis = filteredEvents.getTimeRange().getStartMillis();
|
||||||
long endMillis = interval.getEndMillis();
|
long endMillis = filteredEvents.getTimeRange().getEndMillis();
|
||||||
|
|
||||||
if (minTime > 0 && maxTime > minTime) {
|
if (minTime > 0 && maxTime > minTime) {
|
||||||
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
startPicker.localDateTimeProperty().removeListener(startListener);
|
startPicker.localDateTimeProperty().removeListener(startListener);
|
||||||
endPicker.localDateTimeProperty().removeListener(endListener);
|
endPicker.localDateTimeProperty().removeListener(endListener);
|
||||||
|
@ -40,6 +40,7 @@ import javafx.scene.control.Label;
|
|||||||
import javafx.scene.control.RadioButton;
|
import javafx.scene.control.RadioButton;
|
||||||
import javafx.scene.control.ToggleGroup;
|
import javafx.scene.control.ToggleGroup;
|
||||||
import javafx.scene.control.Tooltip;
|
import javafx.scene.control.Tooltip;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
@ -60,7 +61,6 @@ import org.sleuthkit.autopsy.timeline.TimeLineController;
|
|||||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane;
|
import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane;
|
||||||
import static org.sleuthkit.autopsy.timeline.ui.countsview.Bundle.*;
|
|
||||||
import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;
|
import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,8 +95,8 @@ public class CountsViewPane extends AbstractVisualizationPane<String, Number, No
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Boolean isTickBold(String value) {
|
protected Boolean isTickBold(String value) {
|
||||||
return dataSeries.stream().flatMap((series) -> series.getData().stream())
|
return dataSeries.stream().flatMap(series -> series.getData().stream())
|
||||||
.anyMatch((data) -> data.getXValue().equals(value) && data.getYValue().intValue() > 0);
|
.anyMatch(data -> data.getXValue().equals(value) && data.getYValue().intValue() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -108,10 +108,6 @@ public class CountsViewPane extends AbstractVisualizationPane<String, Number, No
|
|||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param controller The TimelineController for this visualization.
|
* @param controller The TimelineController for this visualization.
|
||||||
* @param specificPane The container for the specific axis labels.
|
|
||||||
* @param contextPane The container for the contextual axis labels.
|
|
||||||
* @param spacer The Region to use as a spacer to keep the axis labels
|
|
||||||
* aligned.
|
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"# {0} - scale name",
|
"# {0} - scale name",
|
||||||
@ -255,7 +251,9 @@ public class CountsViewPane extends AbstractVisualizationPane<String, Number, No
|
|||||||
private Label scaleLabel;
|
private Label scaleLabel;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ImageView helpImageView;
|
private ImageView logImageView;
|
||||||
|
@FXML
|
||||||
|
private ImageView linearImageView;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
@ -263,44 +261,48 @@ public class CountsViewPane extends AbstractVisualizationPane<String, Number, No
|
|||||||
"CountsViewPane.scaleLabel.text=Scale:",
|
"CountsViewPane.scaleLabel.text=Scale:",
|
||||||
"CountsViewPane.scaleHelp.label.text=Scales: ",
|
"CountsViewPane.scaleHelp.label.text=Scales: ",
|
||||||
"CountsViewPane.linearRadio.text=Linear",
|
"CountsViewPane.linearRadio.text=Linear",
|
||||||
"CountsViewPane.scaleHelp=The default linear scale is good for many use cases. When this scale is selected, the height of the bars represents the counts in a linear, one-to-one fashion, and the y-axis is labeled with values. When the range of values is very large, date ranges with relatively low counts have a bar that may be too small to see. To help avoid the misperception of this as no events, the labels for date ranges with events are bold. To see bars that are too small, there are three options: adjust the window size so that the visualization area has more vertical space, adjust the time range shown so that time periods with relatively much larger bars are excluded, or adjust the scale setting to logarithmic.\n\nThe logarithmic scale represents the number of events in a non-linear way that compresses the difference between very large and very small numbers. Note that even with the logarithmic scale, an extremely large difference in counts may still produce bars too small to see. In this case the only option may be to exclude events to reduce the difference in counts. NOTE: Because the logarithmic scale is applied to each event type separately, the height of the combined bar is not very meaningful, and to emphasize this, no labels are shown on the y-axis. The logarithmic scale should be used to quickly compare the counts ",
|
"CountsViewPane.scaleHelpLinear=The linear scale is good for many use cases. When this scale is selected, the height of the bars represents the counts in a linear, one-to-one fashion, and the y-axis is labeled with values. When the range of values is very large, time periods with low counts may have a bar that is too small to see. To help the user detect this, the labels for date ranges with events are bold. To see bars that are too small, there are three options: adjust the window size so that the visualization area has more vertical space, adjust the time range shown so that time periods with larger bars are excluded, or adjust the scale setting to logarithmic.",
|
||||||
"CountsViewPane.scaleHelp2=across time within a type, or across types for one time period, but not both.",
|
"CountsViewPane.scaleHelpLog=The logarithmic scale represents the number of events in a non-linear way that compresses the difference between large and small numbers. Note that even with the logarithmic scale, an extremely large difference in counts may still produce bars too small to see. In this case the only option may be to filter events to reduce the difference in counts. NOTE: Because the logarithmic scale is applied to each event type separately, the meaning of the height of the combined bar is not intuitive, and to emphasize this, no labels are shown on the y-axis with the logarithmic scale. The logarithmic scale should be used to quickly compare the counts ",
|
||||||
"CountsViewPane.scaleHelp3= The exact numbers (available in tooltips or the result viewer) should be used for absolute comparisons. Use the logarithmic scale with care."})
|
"CountsViewPane.scaleHelpLog2=across time within a type, or across types for one time period, but not both.",
|
||||||
|
"CountsViewPane.scaleHelpLog3= The actual counts (available in tooltips or the result viewer) should be used for absolute comparisons. Use the logarithmic scale with care."})
|
||||||
void initialize() {
|
void initialize() {
|
||||||
assert logRadio != null : "fx:id=\"logRadio\" was not injected: check your FXML file 'CountsViewSettingsPane.fxml'."; // NON-NLS
|
assert logRadio != null : "fx:id=\"logRadio\" was not injected: check your FXML file 'CountsViewSettingsPane.fxml'."; // NON-NLS
|
||||||
assert linearRadio != null : "fx:id=\"linearRadio\" was not injected: check your FXML file 'CountsViewSettingsPane.fxml'."; // NON-NLS
|
assert linearRadio != null : "fx:id=\"linearRadio\" was not injected: check your FXML file 'CountsViewSettingsPane.fxml'."; // NON-NLS
|
||||||
scaleLabel.setText(CountsViewPane_scaleLabel_text());
|
scaleLabel.setText(Bundle.CountsViewPane_scaleLabel_text());
|
||||||
linearRadio.setText(CountsViewPane_linearRadio_text());
|
linearRadio.setText(Bundle.CountsViewPane_linearRadio_text());
|
||||||
logRadio.setText(CountsViewPane_logRadio_text());
|
logRadio.setText(Bundle.CountsViewPane_logRadio_text());
|
||||||
|
|
||||||
scaleGroup.selectedToggleProperty().addListener(observable -> {
|
scaleGroup.selectedToggleProperty().addListener((observable, oldToggle, newToggle) -> {
|
||||||
if (scaleGroup.getSelectedToggle() == linearRadio) {
|
if (newToggle == linearRadio) {
|
||||||
scaleProp.set(Scale.LINEAR);
|
scaleProp.set(Scale.LINEAR);
|
||||||
} else if (scaleGroup.getSelectedToggle() == logRadio) {
|
} else if (newToggle == logRadio) {
|
||||||
scaleProp.set(Scale.LOGARITHMIC);
|
scaleProp.set(Scale.LOGARITHMIC);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
logRadio.setSelected(true);
|
logRadio.setSelected(true);
|
||||||
|
|
||||||
//make a popup hrlp window with descriptions of the scales.
|
//make a popup help "window" with a description of the log scale.
|
||||||
helpImageView.setCursor(Cursor.HAND);
|
logImageView.setCursor(Cursor.HAND);
|
||||||
helpImageView.setOnMouseClicked(clicked -> {
|
logImageView.setOnMouseClicked(clicked -> {
|
||||||
Text text = new Text(Bundle.CountsViewPane_scaleHelp());
|
Text text = new Text(Bundle.CountsViewPane_scaleHelpLog());
|
||||||
Text text2 = new Text(Bundle.CountsViewPane_scaleHelp2());
|
Text text2 = new Text(Bundle.CountsViewPane_scaleHelpLog2());
|
||||||
Font baseFont = text.getFont();
|
Font baseFont = text.getFont();
|
||||||
text2.setFont(Font.font(baseFont.getFamily(), FontWeight.BOLD, FontPosture.ITALIC, baseFont.getSize()));
|
text2.setFont(Font.font(baseFont.getFamily(), FontWeight.BOLD, FontPosture.ITALIC, baseFont.getSize()));
|
||||||
Text text3 = new Text(Bundle.CountsViewPane_scaleHelp3());
|
Text text3 = new Text(Bundle.CountsViewPane_scaleHelpLog3());
|
||||||
|
showPopoverHelp(logImageView,
|
||||||
|
Bundle.CountsViewPane_logRadio_text(),
|
||||||
|
logImageView.getImage(),
|
||||||
|
new TextFlow(text, text2, text3));
|
||||||
|
});
|
||||||
|
|
||||||
Pane borderPane = new BorderPane(null, null, new ImageView(helpImageView.getImage()),
|
//make a popup help "window" with a description of the linear scale.
|
||||||
new TextFlow(text, text2, text3),
|
linearImageView.setCursor(Cursor.HAND);
|
||||||
new Label(Bundle.CountsViewPane_scaleHelp_label_text()));
|
linearImageView.setOnMouseClicked(clicked -> {
|
||||||
borderPane.setPadding(new Insets(10));
|
Text text = new Text(Bundle.CountsViewPane_scaleHelpLinear());
|
||||||
borderPane.setPrefWidth(500);
|
text.setWrappingWidth(480); //This is a hack to fix the layout.
|
||||||
|
showPopoverHelp(linearImageView,
|
||||||
PopOver popOver = new PopOver(borderPane);
|
Bundle.CountsViewPane_linearRadio_text(),
|
||||||
popOver.setDetachable(false);
|
linearImageView.getImage(), text);
|
||||||
popOver.setArrowLocation(PopOver.ArrowLocation.TOP_CENTER);
|
|
||||||
popOver.show(helpImageView);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,6 +314,33 @@ public class CountsViewPane extends AbstractVisualizationPane<String, Number, No
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Static utility to to show a Popover with the given Node as owner.
|
||||||
|
*
|
||||||
|
* @param owner The owner of the Popover
|
||||||
|
* @param headerText A short String that will be shown in the top-left
|
||||||
|
* corner of the Popover.
|
||||||
|
* @param headerImage An Image that will be shown at the top-right corner of
|
||||||
|
* the Popover.
|
||||||
|
* @param content The main content of the Popover, shown in the
|
||||||
|
* bottom-center
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static void showPopoverHelp(final Node owner, final String headerText, final Image headerImage, final Node content) {
|
||||||
|
Pane borderPane = new BorderPane(null, null, new ImageView(headerImage),
|
||||||
|
content,
|
||||||
|
new Label(headerText));
|
||||||
|
borderPane.setPadding(new Insets(10));
|
||||||
|
borderPane.setPrefWidth(500);
|
||||||
|
|
||||||
|
PopOver popOver = new PopOver(borderPane);
|
||||||
|
popOver.setDetachable(false);
|
||||||
|
popOver.setArrowLocation(PopOver.ArrowLocation.TOP_CENTER);
|
||||||
|
|
||||||
|
popOver.show(owner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Task that clears the Chart, fetches new data according to the current
|
* Task that clears the Chart, fetches new data according to the current
|
||||||
* ZoomParams and loads it into the Chart
|
* ZoomParams and loads it into the Chart
|
||||||
|
@ -18,15 +18,23 @@
|
|||||||
</HBox.margin>
|
</HBox.margin>
|
||||||
</Label>
|
</Label>
|
||||||
|
|
||||||
<RadioButton fx:id="logRadio" mnemonicParsing="false" selected="true" styleClass="toggle-butto" text="Logarithmic">
|
<RadioButton fx:id="logRadio" contentDisplay="RIGHT" mnemonicParsing="false" selected="true" styleClass="toggle-butto" text="Logarithmic">
|
||||||
<toggleGroup>
|
<toggleGroup>
|
||||||
<ToggleGroup fx:id="scaleGroup" />
|
<ToggleGroup fx:id="scaleGroup" />
|
||||||
</toggleGroup>
|
</toggleGroup>
|
||||||
</RadioButton>
|
</RadioButton>
|
||||||
<RadioButton fx:id="linearRadio" mnemonicParsing="false" text="Linear" toggleGroup="$scaleGroup" />
|
|
||||||
|
|
||||||
|
|
||||||
<ImageView fx:id="helpImageView" fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
|
<ImageView fx:id="logImageView" fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
|
||||||
|
<image>
|
||||||
|
<Image url="@../../images/question-frame.png" />
|
||||||
|
</image>
|
||||||
|
<HBox.margin>
|
||||||
|
<Insets right="5.0" />
|
||||||
|
</HBox.margin>
|
||||||
|
</ImageView>
|
||||||
|
<RadioButton fx:id="linearRadio" contentDisplay="RIGHT" mnemonicParsing="false" text="Linear" toggleGroup="$scaleGroup" />
|
||||||
|
<ImageView fx:id="linearImageView" fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
|
||||||
<image>
|
<image>
|
||||||
<Image url="@../../images/question-frame.png" />
|
<Image url="@../../images/question-frame.png" />
|
||||||
</image>
|
</image>
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
package org.sleuthkit.autopsy.timeline.ui.detailview;
|
package org.sleuthkit.autopsy.timeline.ui.detailview;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -58,6 +59,7 @@ import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent;
|
|||||||
import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane;
|
import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane;
|
||||||
import org.sleuthkit.autopsy.timeline.utils.MappedList;
|
import org.sleuthkit.autopsy.timeline.utils.MappedList;
|
||||||
import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD;
|
import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD;
|
||||||
|
import org.sleuthkit.autopsy.timeline.zooming.ZoomParams;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class for a DetailsChart based implementation of a timeline view.
|
* Controller class for a DetailsChart based implementation of a timeline view.
|
||||||
@ -89,6 +91,12 @@ public class DetailViewPane extends AbstractVisualizationPane<DateTime, EventStr
|
|||||||
*/
|
*/
|
||||||
private final MappedList<TimeLineEvent, EventNodeBase<?>> selectedEvents;
|
private final MappedList<TimeLineEvent, EventNodeBase<?>> selectedEvents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local copy of the zoomParams. Used to backout of a zoomParam change
|
||||||
|
* without needing to requery/redraw the vis.
|
||||||
|
*/
|
||||||
|
private ZoomParams currentZoomParams;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for a DetailViewPane
|
* Constructor for a DetailViewPane
|
||||||
*
|
*
|
||||||
@ -357,7 +365,8 @@ public class DetailViewPane extends AbstractVisualizationPane<DateTime, EventStr
|
|||||||
"DetailViewPane.loggedTask.continueButton=Continue",
|
"DetailViewPane.loggedTask.continueButton=Continue",
|
||||||
"DetailViewPane.loggedTask.backButton=Back (Cancel)",
|
"DetailViewPane.loggedTask.backButton=Back (Cancel)",
|
||||||
"# {0} - number of events",
|
"# {0} - number of events",
|
||||||
"DetailViewPane.loggedTask.prompt=You are about to show details for {0} events. This might be very slow or even crash Autopsy.\n\nDo you want to continue?"})
|
|
||||||
|
"DetailViewPane.loggedTask.prompt=You are about to show details for {0} events. This might be very slow and could exhaust available memory.\n\nDo you want to continue?"})
|
||||||
private class DetailsUpdateTask extends VisualizationRefreshTask<Interval> {
|
private class DetailsUpdateTask extends VisualizationRefreshTask<Interval> {
|
||||||
|
|
||||||
DetailsUpdateTask() {
|
DetailsUpdateTask() {
|
||||||
@ -367,13 +376,17 @@ public class DetailViewPane extends AbstractVisualizationPane<DateTime, EventStr
|
|||||||
@Override
|
@Override
|
||||||
protected Boolean call() throws Exception {
|
protected Boolean call() throws Exception {
|
||||||
super.call();
|
super.call();
|
||||||
|
|
||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
FilteredEventsModel eventsModel = getEventsModel();
|
FilteredEventsModel eventsModel = getEventsModel();
|
||||||
|
ZoomParams newZoomParams = eventsModel.getZoomParamaters();
|
||||||
|
|
||||||
//clear the chart and set the horixontal axis
|
//if the zoomParams haven't actually changed, just bail
|
||||||
resetChart(eventsModel.getTimeRange());
|
if (Objects.equals(currentZoomParams, newZoomParams)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
updateMessage(Bundle.DetailViewPane_loggedTask_queryDb());
|
updateMessage(Bundle.DetailViewPane_loggedTask_queryDb());
|
||||||
|
|
||||||
@ -392,17 +405,25 @@ public class DetailViewPane extends AbstractVisualizationPane<DateTime, EventStr
|
|||||||
alert.setHeaderText("");
|
alert.setHeaderText("");
|
||||||
alert.initModality(Modality.APPLICATION_MODAL);
|
alert.initModality(Modality.APPLICATION_MODAL);
|
||||||
alert.initOwner(getScene().getWindow());
|
alert.initOwner(getScene().getWindow());
|
||||||
ButtonType orElse = alert.showAndWait().orElse(back);
|
ButtonType userResponse = alert.showAndWait().orElse(back);
|
||||||
if (orElse == back) {
|
if (userResponse == back) {
|
||||||
DetailsUpdateTask.this.cancel();
|
DetailsUpdateTask.this.cancel();
|
||||||
}
|
}
|
||||||
return orElse;
|
return userResponse;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//show dialog on JFX thread and block this thread until the dialog is dismissed.
|
//show dialog on JFX thread and block this thread until the dialog is dismissed.
|
||||||
Platform.runLater(task);
|
Platform.runLater(task);
|
||||||
task.get();
|
task.get();
|
||||||
}
|
}
|
||||||
|
if (isCancelled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//we are going to accept the new zoomParams
|
||||||
|
currentZoomParams = newZoomParams;
|
||||||
|
|
||||||
|
//clear the chart and set the horixontal axis
|
||||||
|
resetChart(eventsModel.getTimeRange());
|
||||||
|
|
||||||
updateMessage(Bundle.DetailViewPane_loggedTask_updateUI());
|
updateMessage(Bundle.DetailViewPane_loggedTask_updateUI());
|
||||||
|
|
||||||
|
@ -61,9 +61,14 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
private final Axis<EventStripe> verticalAxis;
|
private final Axis<EventStripe> verticalAxis;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* property that holds the interval selector if one is active
|
* Property that holds the interval selector if one is active
|
||||||
*/
|
*/
|
||||||
private final SimpleObjectProperty<IntervalSelector<? extends DateTime>> intervalSelector = new SimpleObjectProperty<>();
|
private final SimpleObjectProperty<IntervalSelector<? extends DateTime>> intervalSelectorProp = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ObservableSet of GuieLines displayed in this chart
|
||||||
|
*/
|
||||||
|
private final ObservableSet<GuideLine> guideLines = FXCollections.observableSet();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Predicate used to determine if a EventNode should be highlighted. Can be
|
* Predicate used to determine if a EventNode should be highlighted. Can be
|
||||||
@ -74,12 +79,12 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
private final SimpleObjectProperty<Predicate<EventNodeBase<?>>> highlightPredicate = new SimpleObjectProperty<>((x) -> false);
|
private final SimpleObjectProperty<Predicate<EventNodeBase<?>>> highlightPredicate = new SimpleObjectProperty<>((x) -> false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* an ObservableList of the Nodes that are selected in this chart.
|
* An ObservableList of the Nodes that are selected in this chart.
|
||||||
*/
|
*/
|
||||||
private final ObservableList<EventNodeBase<?>> selectedNodes;
|
private final ObservableList<EventNodeBase<?>> selectedNodes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* an ObservableList representing all the events in the tree as a flat list
|
* An ObservableList representing all the events in the tree as a flat list
|
||||||
* of events whose roots are in the eventStripes lists
|
* of events whose roots are in the eventStripes lists
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -97,12 +102,25 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
private final TimeLineController controller;
|
private final TimeLineController controller;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* an ObservableList of root event stripes to display in the chart. Must
|
* An ObservableList of root event stripes to display in the chart.
|
||||||
* only be modified on the JFX Thread.
|
|
||||||
*/
|
*/
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||||
private final ObservableList<EventStripe> rootEventStripes = FXCollections.observableArrayList();
|
private final ObservableList<EventStripe> rootEventStripes = FXCollections.observableArrayList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param controller The TimeLineController for this chart.
|
||||||
|
* @param detailsChartDateAxis The DateAxis to use in this chart.
|
||||||
|
* @param pinnedDateAxis The DateAxis to use for the pinned lane. It
|
||||||
|
* will not be shown on screen, but must not be
|
||||||
|
* null or the same as the detailsChartDateAxis.
|
||||||
|
* @param verticalAxis An Axis<EventStripe> to use as the vertical
|
||||||
|
* axis in the primary lane.
|
||||||
|
* @param selectedNodes An ObservableList<EventNodeBase<?>>, that
|
||||||
|
* will be used to keep track of the nodes
|
||||||
|
* selected in this chart.
|
||||||
|
*/
|
||||||
DetailsChart(TimeLineController controller, DateAxis detailsChartDateAxis, DateAxis pinnedDateAxis, Axis<EventStripe> verticalAxis, ObservableList<EventNodeBase<?>> selectedNodes) {
|
DetailsChart(TimeLineController controller, DateAxis detailsChartDateAxis, DateAxis pinnedDateAxis, Axis<EventStripe> verticalAxis, ObservableList<EventNodeBase<?>> selectedNodes) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
this.layoutSettings = new DetailsChartLayoutSettings(controller);
|
this.layoutSettings = new DetailsChartLayoutSettings(controller);
|
||||||
@ -112,8 +130,9 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
this.selectedNodes = selectedNodes;
|
this.selectedNodes = selectedNodes;
|
||||||
|
|
||||||
FilteredEventsModel eventsModel = getController().getEventsModel();
|
FilteredEventsModel eventsModel = getController().getEventsModel();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the time range is changed, clear the guide line and the interval
|
* If the time range is changed, clear the guide line and the interval
|
||||||
* selector, since they may not be in view any more.
|
* selector, since they may not be in view any more.
|
||||||
*/
|
*/
|
||||||
eventsModel.timeRangeProperty().addListener(o -> clearTimeBasedUIElements());
|
eventsModel.timeRangeProperty().addListener(o -> clearTimeBasedUIElements());
|
||||||
@ -126,9 +145,9 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
* Get the DateTime represented by the given x-position in this chart.
|
* Get the DateTime represented by the given x-position in this chart.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param xPos the x-position to get the DataTime for
|
* @param xPos The x-position to get the DataTime for.
|
||||||
*
|
*
|
||||||
* @return the DateTime represented by the given x-position in this chart.
|
* @return The DateTime represented by the given x-position in this chart.
|
||||||
*/
|
*/
|
||||||
DateTime getDateTimeForPosition(double xPos) {
|
DateTime getDateTimeForPosition(double xPos) {
|
||||||
return getXAxis().getValueForDisplay(getXAxis().parentToLocal(xPos, 0).getX());
|
return getXAxis().getValueForDisplay(getXAxis().parentToLocal(xPos, 0).getX());
|
||||||
@ -137,7 +156,7 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
/**
|
/**
|
||||||
* Add an EventStripe to the list of root stripes.
|
* Add an EventStripe to the list of root stripes.
|
||||||
*
|
*
|
||||||
* @param stripe the EventStripe to add.
|
* @param stripe The EventStripe to add.
|
||||||
*/
|
*/
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||||
void addStripe(EventStripe stripe) {
|
void addStripe(EventStripe stripe) {
|
||||||
@ -146,10 +165,9 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Remove the given GuideLine from this chart.
|
* Remove the given GuideLine from this chart.
|
||||||
*
|
*
|
||||||
* @param guideLine the GuideLine to remove
|
* @param guideLine The GuideLine to remove.
|
||||||
*/
|
*/
|
||||||
void clearGuideLine(GuideLine guideLine) {
|
void clearGuideLine(GuideLine guideLine) {
|
||||||
guideLines.remove(guideLine);
|
guideLines.remove(guideLine);
|
||||||
@ -161,23 +179,22 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the DetailsCharLayoutSettings for this chart.
|
* Get the DetailsChartLayoutSettings for this chart.
|
||||||
*
|
*
|
||||||
* @return the DetailsCharLayoutSettings for this chart.
|
* @return The DetailsChartLayoutSettings for this chart.
|
||||||
*/
|
*/
|
||||||
DetailsChartLayoutSettings getLayoutSettings() {
|
DetailsChartLayoutSettings getLayoutSettings() {
|
||||||
return layoutSettings;
|
return layoutSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Set the Predicate used to determine if a EventNode should be highlighted.
|
* Set the Predicate used to determine if a EventNode should be highlighted.
|
||||||
* Can be a combination of conditions such as: be in the selectedNodes list
|
* Can be a combination of conditions such as: be in the selectedNodes list
|
||||||
* OR have a particular description, but it must include be in the
|
* OR have a particular description, but it must include be in the
|
||||||
* selectedNodes (selectedNodes::contains).
|
* selectedNodes (selectedNodes::contains).
|
||||||
*
|
*
|
||||||
* @param highlightPredicate the Predicate used to determine which nodes to
|
* @param highlightPredicate The Predicate used to determine which nodes to
|
||||||
* highlight
|
* highlight.
|
||||||
*/
|
*/
|
||||||
void setHighlightPredicate(Predicate<EventNodeBase<?>> highlightPredicate) {
|
void setHighlightPredicate(Predicate<EventNodeBase<?>> highlightPredicate) {
|
||||||
this.highlightPredicate.set(highlightPredicate);
|
this.highlightPredicate.set(highlightPredicate);
|
||||||
@ -208,14 +225,9 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
clearIntervalSelector();
|
clearIntervalSelector();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ObservableSet of GuieLines displayed in this chart
|
|
||||||
*/
|
|
||||||
private final ObservableSet<GuideLine> guideLines = FXCollections.observableSet();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearIntervalSelector() {
|
public void clearIntervalSelector() {
|
||||||
intervalSelector.set(null);
|
intervalSelectorProp.set(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -225,16 +237,12 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IntervalSelector<? extends DateTime> getIntervalSelector() {
|
public IntervalSelector<? extends DateTime> getIntervalSelector() {
|
||||||
return intervalSelector.get();
|
return intervalSelectorProp.get();
|
||||||
}
|
|
||||||
|
|
||||||
private SimpleObjectProperty<IntervalSelector<? extends DateTime>> intervalSelector() {
|
|
||||||
return intervalSelector;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIntervalSelector(IntervalSelector<? extends DateTime> newIntervalSelector) {
|
public void setIntervalSelector(IntervalSelector<? extends DateTime> newIntervalSelector) {
|
||||||
intervalSelector.set(newIntervalSelector);
|
intervalSelectorProp.set(newIntervalSelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -277,7 +285,7 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
/**
|
/**
|
||||||
* Get the ObservableList of root EventStripes.
|
* Get the ObservableList of root EventStripes.
|
||||||
*
|
*
|
||||||
* @return the ObservableList of root EventStripes.
|
* @return The ObservableList of root EventStripes.
|
||||||
*/
|
*/
|
||||||
ObservableList<EventStripe> getRootEventStripes() {
|
ObservableList<EventStripe> getRootEventStripes() {
|
||||||
return rootEventStripes;
|
return rootEventStripes;
|
||||||
@ -385,8 +393,9 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
private final Pane rootPane;
|
private final Pane rootPane;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The divder position of masterDetailPane is saved when the pinned lane
|
* The divider position of masterDetailPane is saved when the pinned
|
||||||
* is hidden so it can be restored when the pinned lane is shown again.
|
* lane is hidden so it can be restored when the pinned lane is shown
|
||||||
|
* again.
|
||||||
*/
|
*/
|
||||||
private double dividerPosition = .1;
|
private double dividerPosition = .1;
|
||||||
|
|
||||||
@ -400,8 +409,7 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
pinnedView = new ScrollingLaneWrapper(pinnedLane);
|
pinnedView = new ScrollingLaneWrapper(pinnedLane);
|
||||||
|
|
||||||
pinnedLane.setMinHeight(MIN_PINNED_LANE_HEIGHT);
|
pinnedLane.setMinHeight(MIN_PINNED_LANE_HEIGHT);
|
||||||
pinnedLane.maxVScrollProperty().addListener(maxVSCrollProp -> syncPinnedHeight());
|
pinnedLane.maxVScrollProperty().addListener(maxVScroll -> syncPinnedHeight());
|
||||||
syncPinnedHeight();
|
|
||||||
|
|
||||||
//assemble scene graph
|
//assemble scene graph
|
||||||
masterDetailPane = new MasterDetailPane(Side.TOP, primaryView, pinnedView, false);
|
masterDetailPane = new MasterDetailPane(Side.TOP, primaryView, pinnedView, false);
|
||||||
@ -413,10 +421,8 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
|
|
||||||
//maintain highlighted effect on correct nodes
|
//maintain highlighted effect on correct nodes
|
||||||
getSkinnable().highlightPredicate.addListener((observable, oldPredicate, newPredicate) -> {
|
getSkinnable().highlightPredicate.addListener((observable, oldPredicate, newPredicate) -> {
|
||||||
primaryLane.getAllNodes().forEach(eNode ->
|
primaryLane.getAllNodes().forEach(primaryNode -> primaryNode.applyHighlightEffect(newPredicate.test(primaryNode)));
|
||||||
eNode.applyHighlightEffect(newPredicate.test(eNode)));
|
pinnedLane.getAllNodes().forEach(pinnedNode -> pinnedNode.applyHighlightEffect(newPredicate.test(pinnedNode)));
|
||||||
pinnedLane.getAllNodes().forEach(eNode ->
|
|
||||||
eNode.applyHighlightEffect(newPredicate.test(eNode)));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
//configure mouse listeners
|
//configure mouse listeners
|
||||||
@ -430,7 +436,7 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
syncPinnedLaneShowing();
|
syncPinnedLaneShowing();
|
||||||
|
|
||||||
//show and remove interval selector in sync with control state change
|
//show and remove interval selector in sync with control state change
|
||||||
getSkinnable().intervalSelector().addListener((observable, oldIntervalSelector, newIntervalSelector) -> {
|
getSkinnable().intervalSelectorProp.addListener((observable, oldIntervalSelector, newIntervalSelector) -> {
|
||||||
rootPane.getChildren().remove(oldIntervalSelector);
|
rootPane.getChildren().remove(oldIntervalSelector);
|
||||||
if (null != newIntervalSelector) {
|
if (null != newIntervalSelector) {
|
||||||
rootPane.getChildren().add(newIntervalSelector);
|
rootPane.getChildren().add(newIntervalSelector);
|
||||||
@ -460,11 +466,11 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
/**
|
/**
|
||||||
* Add the given listeners to the given chart lane
|
* Add the given listeners to the given chart lane
|
||||||
*
|
*
|
||||||
* @param chartLane the Chart lane to add the listeners to
|
* @param chartLane The Chart lane to add the listeners to.
|
||||||
* @param mouseClickedHandler the mouseClickedHandler to add to chart
|
* @param mouseClickedHandler The MouseClickedHandler to add to chart.
|
||||||
* @param chartDragHandler1 the ChartDragHandler to add to the chart
|
* @param chartDragHandler1 The ChartDragHandler to add to the chart
|
||||||
* as pressed, released, dragged, and clicked
|
* as pressed, released, dragged, and clicked
|
||||||
* handler
|
* handler.
|
||||||
*/
|
*/
|
||||||
static private void configureMouseListeners(final DetailsChartLane<?> chartLane, final TimeLineChart.MouseClickedHandler<DateTime, DetailsChart> mouseClickedHandler, final TimeLineChart.ChartDragHandler<DateTime, DetailsChart> chartDragHandler) {
|
static private void configureMouseListeners(final DetailsChartLane<?> chartLane, final TimeLineChart.MouseClickedHandler<DateTime, DetailsChart> mouseClickedHandler, final TimeLineChart.ChartDragHandler<DateTime, DetailsChart> chartDragHandler) {
|
||||||
chartLane.setOnMousePressed(chartDragHandler);
|
chartLane.setOnMousePressed(chartDragHandler);
|
||||||
@ -474,14 +480,22 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
chartLane.addEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickedHandler);
|
chartLane.addEventHandler(MouseEvent.MOUSE_CLICKED, mouseClickedHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the pinned lane if and only if the settings object says it
|
||||||
|
* should be.
|
||||||
|
*/
|
||||||
private void syncPinnedLaneShowing() {
|
private void syncPinnedLaneShowing() {
|
||||||
boolean selected = getSkinnable().getLayoutSettings().isPinnedLaneShowing();
|
boolean pinnedLaneShowing = getSkinnable().getLayoutSettings().isPinnedLaneShowing();
|
||||||
if (selected == false) {
|
if (pinnedLaneShowing == false) {
|
||||||
|
//Save the divider position for later.
|
||||||
dividerPosition = masterDetailPane.getDividerPosition();
|
dividerPosition = masterDetailPane.getDividerPosition();
|
||||||
}
|
}
|
||||||
masterDetailPane.setShowDetailNode(selected);
|
|
||||||
if (selected) {
|
masterDetailPane.setShowDetailNode(pinnedLaneShowing);
|
||||||
|
|
||||||
|
if (pinnedLaneShowing) {
|
||||||
syncPinnedHeight();
|
syncPinnedHeight();
|
||||||
|
//Restore the devider position.
|
||||||
masterDetailPane.setDividerPosition(dividerPosition);
|
masterDetailPane.setDividerPosition(dividerPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import javafx.scene.image.Image;
|
|||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||||
|
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.IntervalSelector;
|
import org.sleuthkit.autopsy.timeline.ui.IntervalSelector;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.TimeLineChart;
|
import org.sleuthkit.autopsy.timeline.ui.TimeLineChart;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
@ -136,9 +136,9 @@ Visualization Area: Counts View
|
|||||||
-------------------------------
|
-------------------------------
|
||||||
The Counts View shows a stacked bar chart with time periods along the x-axis and event counts along the y-axis. The height of each bar represents the number of events that occurred in that time period. The different colored segments represent different event types. Right clicking the bars brings up a context menu with selection and zooming actions.
|
The Counts View shows a stacked bar chart with time periods along the x-axis and event counts along the y-axis. The height of each bar represents the number of events that occurred in that time period. The different colored segments represent different event types. Right clicking the bars brings up a context menu with selection and zooming actions.
|
||||||
|
|
||||||
The only setting specific to the Counts View is what kind of vertical scale to use. The default linear scale is good for many use cases. When this scale is selected, the height of the bars represents the counts in a linear, one-to-one fashion, and the y-axis is labeled with values. When the range of count values is very large, date ranges with relatively low counts have a bar that may be too small to see. To help avoid the misperception of this as no events, the labels for time periods with events are bold relative to the labels for time periods with no events.
|
The only setting specific to the Counts View is what kind of vertical scale to use: The linear scale is good for many use cases. When this scale is selected, the height of the bars represents the counts in a linear, one-to-one fashion, and the y-axis is labeled with values. When the range of values is very large, time periods with low counts may have a bar that is too small to see. To help the user detect this, the labels for date ranges with events are bold. To see bars that are too small, there are three options: adjust the window size so that the visualization area has more vertical space, adjust the time range shown so that time periods with larger bars are excluded, or adjust the scale setting to logarithmic.
|
||||||
To see the events when the bar for a period is too small, there are three options: adjust the window size so that the visualization area has more vertical space, adjust the time range shown so that time periods with relatively much larger bars are excluded, or adjust the scale setting to logarithmic. The logarithmic scale represents the number of events in a non-linear way that compresses the difference between very large and very small numbers. Note that even with the logarithmic scale, an extremely large difference in counts may still produce bars too small to see. In this case the only option may be to exclude events to reduce the difference in counts.
|
|
||||||
Because the logarithmic scale is applied to each event type separately, the height of the combined bar is not very meaningful, and to emphasize this, no labels are shown on the y-axis. The logarithmic scale should be used to quickly compare the counts relative across _time within a type, or across types for one time period, but not both_. The exact numbers (available in tooltips or the result viewer) should be used for absolute comparisons. Use the logarithmic scales with care.
|
The logarithmic scale represents the number of events in a non-linear way that compresses the difference between large and small numbers. Note that even with the logarithmic scale, an extremely large difference in counts may still produce bars too small to see. In this case the only option may be to filter events to reduce the difference in counts. NOTE: Because the logarithmic scale is applied to each event type separately, the meaning of the height of the combined bar is not intuitive, and to emphasize this, no labels are shown on the y-axis with the logarithmic scale. The logarithmic scale should be used to quickly compare the counts *across time within a type, or across types for one time period, but not both.* The actual counts (available in tooltips or the result viewer) should be used for absolute comparisons. Use the logarithmic scale with care.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user