19 package org.sleuthkit.autopsy.timeline.ui;
22 import java.time.Instant;
23 import java.time.LocalDateTime;
24 import java.time.ZonedDateTime;
25 import java.util.ArrayList;
26 import java.util.ResourceBundle;
27 import javafx.application.Platform;
28 import javafx.beans.InvalidationListener;
29 import javafx.beans.Observable;
30 import javafx.beans.value.ChangeListener;
31 import javafx.beans.value.ObservableValue;
32 import javafx.event.ActionEvent;
33 import javafx.fxml.FXML;
34 import javafx.geometry.Insets;
35 import javafx.geometry.Rectangle2D;
36 import javafx.scene.SnapshotParameters;
37 import javafx.scene.control.*;
38 import javafx.scene.effect.Lighting;
39 import javafx.scene.image.WritableImage;
40 import javafx.scene.input.MouseEvent;
41 import javafx.scene.layout.Background;
42 import javafx.scene.layout.BackgroundFill;
43 import javafx.scene.layout.BorderPane;
44 import javafx.scene.layout.CornerRadii;
45 import javafx.scene.layout.HBox;
46 import javafx.scene.layout.Pane;
47 import javafx.scene.layout.Priority;
48 import javafx.scene.layout.Region;
49 import static javafx.scene.layout.Region.USE_PREF_SIZE;
50 import javafx.scene.layout.StackPane;
51 import javafx.scene.paint.Color;
52 import javax.annotation.concurrent.GuardedBy;
53 import jfxtras.scene.control.LocalDateTimeTextField;
54 import org.controlsfx.control.RangeSlider;
55 import org.controlsfx.control.action.Action;
56 import org.joda.time.DateTime;
57 import org.joda.time.DateTimeZone;
58 import org.joda.time.Interval;
59 import org.openide.util.NbBundle;
106 private final RangeSlider
rangeSlider = new RangeSlider(0, 1.0, .25, .75);
160 = (observable1, oldValue, newValue) -> {
162 Long minTime = filteredEvents.getMinTime() * 1000;
163 controller.pushTimeRange(
new Interval(
164 new Double(
rangeSlider.getLowValue() + minTime).longValue(),
165 new Double(
rangeSlider.getHighValue() + minTime).longValue(),
170 private final InvalidationListener
endListener = (Observable observable) -> {
171 if (
endPicker.getLocalDateTime() != null) {
177 private final InvalidationListener
startListener = (Observable observable) -> {
184 static private final Background
background =
new Background(
new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY));
186 static private final Lighting
lighting =
new Lighting();
195 assert
endPicker != null :
"fx:id=\"endPicker\" was not injected: check your FXML file 'ViewWrapper.fxml'.";
196 assert
histogramBox != null :
"fx:id=\"histogramBox\" was not injected: check your FXML file 'ViewWrapper.fxml'.";
197 assert
startPicker != null :
"fx:id=\"startPicker\" was not injected: check your FXML file 'ViewWrapper.fxml'.";
198 assert
rangeHistogramStack != null :
"fx:id=\"rangeHistogramStack\" was not injected: check your FXML file 'ViewWrapper.fxml'.";
199 assert
countsToggle != null :
"fx:id=\"countsToggle\" was not injected: check your FXML file 'VisToggle.fxml'.";
200 assert
detailsToggle != null :
"fx:id=\"eventsToggle\" was not injected: check your FXML file 'VisToggle.fxml'.";
204 ChangeListener<Toggle> toggleListener = (ObservableValue<? extends Toggle> observable,
206 Toggle newValue) -> {
207 if (newValue == null) {
209 }
else if (newValue ==
countsToggle && oldValue != null) {
217 countsToggle.getToggleGroup().selectedToggleProperty().addListener(toggleListener);
219 countsToggle.toggleGroupProperty().addListener((Observable observable) -> {
220 countsToggle.getToggleGroup().selectedToggleProperty().addListener(toggleListener);
223 countsToggle.setText(NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.countsToggle.text"));
224 detailsToggle.setText(NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.detailsToggle.text"));
251 histogramBox.setStyle(
" -fx-padding: 0,0.5em,0,.5em; ");
256 MenuItem menuItem =
new MenuItem(b.getDisplayName());
257 menuItem.setOnAction((event) -> {
259 controller.pushPeriod(b.getPeriod());
261 controller.showFullRange();
266 zoomMenuButton.setText(NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.zoomMenuButton.text"));
277 final SnapshotParameters snapshotParameters =
new SnapshotParameters();
278 snapshotParameters.setViewport(
new Rectangle2D(
visualization.getBoundsInParent().getMinX(),
visualization.getBoundsInParent().getMinY(),
282 WritableImage snapshot = this.snapshot(snapshotParameters, null);
287 snapShotButton.setText(NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.snapShotButton.text"));
351 controller.
getNeedsHistogramRebuild().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
364 switch (visualizationMode) {
377 Platform.runLater(() -> {
392 visualization.
hasEvents.addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
393 if (newValue ==
false) {
397 setBackground(
new Background(
new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY)));
400 },
new NoEventsDialog(() -> {
418 NbBundle.getMessage(this.getClass(),
"VisualizationPanel.histogramTask.title"),
true) {
421 protected Void call()
throws Exception {
423 updateMessage(NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.histogramTask.preparing"));
435 Platform.runLater(() -> {
436 updateMessage(NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.histogramTask.resetUI"));
440 ArrayList<Long> bins =
new ArrayList<>();
442 DateTime start = timeRange.getStart();
443 while (timeRange.contains(start)) {
448 final Interval interval =
new Interval(start, end);
453 updateMessage(NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.histogramTask.queryDb"));
458 max = Math.max(count, max);
460 final double fMax = Math.log(max);
461 final ArrayList<Long> fbins =
new ArrayList<>(bins);
462 Platform.runLater(() -> {
463 updateMessage(NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.histogramTask.updateUI2"));
467 for (Long bin : fbins) {
471 Region bar =
new Region();
473 bar.prefHeightProperty().bind(
histogramBox.heightProperty().multiply(Math.log(bin)).divide(fMax));
474 bar.setMaxHeight(USE_PREF_SIZE);
475 bar.setMinHeight(USE_PREF_SIZE);
476 bar.setBackground(background);
477 bar.setOnMouseEntered((MouseEvent event) -> {
478 Tooltip.install(bar,
new Tooltip(bin.toString()));
480 bar.setEffect(lighting);
482 HBox.setHgrow(bar, Priority.ALWAYS);
500 this.filteredEvents.
timeRange().addListener((Observable observable) -> {
514 if (minTime > 0 && maxTime > minTime) {
516 Platform.runLater(() -> {
517 startPicker.localDateTimeProperty().removeListener(startListener);
518 endPicker.localDateTimeProperty().removeListener(endListener);
523 rangeSlider.setHighValue(interval.getEndMillis() - minTime);
524 rangeSlider.setLowValue(interval.getStartMillis() - minTime);
530 startPicker.localDateTimeProperty().addListener(startListener);
531 endPicker.localDateTimeProperty().addListener(endListener);
575 assert resetFiltersButton != null :
"fx:id=\"resetFiltersButton\" was not injected: check your FXML file 'NoEventsDialog.fxml'.";
576 assert dismissButton != null :
"fx:id=\"dismissButton\" was not injected: check your FXML file 'NoEventsDialog.fxml'.";
577 assert zoomButton != null :
"fx:id=\"zoomButton\" was not injected: check your FXML file 'NoEventsDialog.fxml'.";
579 visualizationModeLabel.setText(
580 NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.visualizationModeLabel.text"));
581 noEventsDialogLabel.setText(
582 NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.noEventsDialogLabel.text"));
583 zoomButton.setText(NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.zoomButton.text"));
584 startLabel.setText(NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.startLabel.text"));
585 endLabel.setText(NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.endLabel.text"));
588 zoomButton.setOnAction(zoomOutAction);
589 zoomButton.disableProperty().bind(zoomOutAction.disabledProperty());
591 dismissButton.setOnAction(e -> {
595 resetFiltersButton.setOnAction(defaultFiltersAction);
596 resetFiltersButton.disableProperty().bind(defaultFiltersAction.disabledProperty());
597 resetFiltersButton.setText(
598 NbBundle.getMessage(
this.getClass(),
"VisualizationPanel.resetFiltersButton.text"));
final InvalidationListener endListener
ToggleButton detailsToggle
final ChangeListener< Object > rangeSliderListener
synchronized void pushZoomInTime()
List< Node > getSettingsNodes()
LocalDateTimeTextField endPicker
void setModel(FilteredEventsModel filteredEvents)
LocalDateTimeTextField startPicker
FilteredEventsModel getEventsModel()
Button resetFiltersButton
static ReadOnlyObjectProperty< TimeZone > getTimeZone()
LoggedTask< Void > histogramTask
synchronized void setController(TimeLineController controller)
final SimpleBooleanProperty hasEvents
synchronized void setController(TimeLineController controller)
TimeLineController controller
static final Background background
ReadOnlyBooleanProperty getNeedsHistogramRebuild()
VisualizationPanel(NavPanel navPanel)
static final Logger LOGGER
static void construct(Node n, String fxmlFileName)
static RangeDivisionInfo getRangeDivisionInfo(Interval timeRange)
static final Lighting lighting
synchronized ReadOnlyObjectProperty< Interval > timeRange()
FilteredEventsModel filteredEvents
static ZoneId getTimeZoneID()
final InvalidationListener startListener
synchronized void monitorTask(final Task<?> task)
synchronized void dispose()
Map< EventType, Long > getEventCounts(Interval timeRange)
synchronized void refreshHistorgram()
Label visualizationModeLabel
ToggleButton countsToggle
final Interval getSpanningInterval()
Label noEventsDialogLabel
static DateTimeZone getJodaTimeZone()
final Runnable closeCallback
final RangeSlider rangeSlider
StackPane rangeHistogramStack
NoEventsDialog(Runnable closeCallback)
synchronized ReadOnlyObjectProperty< VisualizationMode > getViewMode()
AbstractVisualization<?,?,?,?> visualization
void setChart(DetailViewPane detailViewPane)
synchronized void pushZoomOutTime()
TimeUnits getPeriodSize()
void setViewMode(VisualizationMode visualizationMode)
synchronized void pushTimeRange(Interval timeRange)
synchronized void setViewMode(VisualizationMode visualizationMode)
MenuButton zoomMenuButton
void refreshTimeUI(Interval interval)