19 package org.sleuthkit.autopsy.timeline.ui.detailview;
 
   22 import java.util.ArrayList;
 
   24 import java.util.ResourceBundle;
 
   25 import java.util.concurrent.ConcurrentHashMap;
 
   26 import javafx.application.Platform;
 
   27 import javafx.beans.InvalidationListener;
 
   28 import javafx.beans.Observable;
 
   29 import javafx.collections.FXCollections;
 
   30 import javafx.collections.ListChangeListener;
 
   31 import javafx.collections.ObservableList;
 
   32 import javafx.concurrent.Task;
 
   33 import javafx.event.EventHandler;
 
   34 import javafx.fxml.FXML;
 
   35 import javafx.geometry.Orientation;
 
   36 import javafx.scene.Cursor;
 
   37 import javafx.scene.chart.Axis;
 
   38 import javafx.scene.chart.BarChart;
 
   39 import javafx.scene.chart.XYChart;
 
   40 import javafx.scene.control.*;
 
   41 import javafx.scene.effect.Effect;
 
   42 import static javafx.scene.input.KeyCode.DOWN;
 
   43 import static javafx.scene.input.KeyCode.KP_DOWN;
 
   44 import static javafx.scene.input.KeyCode.KP_UP;
 
   45 import static javafx.scene.input.KeyCode.PAGE_DOWN;
 
   46 import static javafx.scene.input.KeyCode.PAGE_UP;
 
   47 import static javafx.scene.input.KeyCode.UP;
 
   48 import javafx.scene.input.KeyEvent;
 
   49 import javafx.scene.input.MouseEvent;
 
   50 import javafx.scene.input.ScrollEvent;
 
   51 import javafx.scene.layout.HBox;
 
   52 import javafx.scene.layout.Pane;
 
   53 import javafx.scene.layout.Priority;
 
   54 import javafx.scene.layout.Region;
 
   55 import javafx.scene.layout.VBox;
 
   56 import org.joda.time.DateTime;
 
   57 import org.openide.util.NbBundle;
 
  114     private final Region 
region = 
new Region();
 
  116     private final ObservableList<AggregateEvent> 
aggregatedEvents = FXCollections.synchronizedObservableList(FXCollections.observableArrayList());
 
  118     private final ObservableList<AggregateEventNode> 
highlightedNodes = FXCollections.synchronizedObservableList(FXCollections.observableArrayList());
 
  125         super(partPane, contextPane, spacer);
 
  131         chart.setPrefHeight(USE_COMPUTED_SIZE);
 
  135         vertScrollBar.setOrientation(Orientation.VERTICAL);
 
  136         VBox vBox = 
new VBox();
 
  137         VBox.setVgrow(vertScrollBar, Priority.ALWAYS);
 
  138         vBox.getChildren().add(vertScrollBar);
 
  139         vBox.getChildren().add(region);
 
  142         dateAxis.setAutoRanging(
false);
 
  143         region.minHeightProperty().bind(dateAxis.heightProperty());
 
  144         vertScrollBar.visibleAmountProperty().bind(
chart.heightProperty().multiply(100).divide(
chart.getMaxVScroll()));
 
  147         highlightedNodes.addListener((ListChangeListener.Change<? extends 
AggregateEventNode> change) -> {
 
  148             while (change.next()) {
 
  149                 change.getAddedSubList().forEach(aeNode -> {
 
  150                     aeNode.applyHighlightEffect(true);
 
  152                 change.getRemoved().forEach(aeNode -> {
 
  153                     aeNode.applyHighlightEffect(false);
 
  158         setOnMouseClicked((MouseEvent t) -> {
 
  164         this.onScrollProperty().set((EventHandler<ScrollEvent>) (ScrollEvent t) -> {
 
  165             vertScrollBar.valueProperty().set(Math.max(0, Math.min(100, vertScrollBar.getValue() - t.getDeltaY() / 200.0)));
 
  168         this.setOnKeyPressed((KeyEvent t) -> {
 
  169             switch (t.getCode()) {
 
  189         this.vertScrollBar.valueProperty().addListener((o, oldValue, newValue) -> {
 
  190             chart.setVScroll(newValue.doubleValue() / 100.0);
 
  192         spacer.minWidthProperty().bind(verticalAxis.widthProperty().add(verticalAxis.tickLengthProperty()));
 
  193         spacer.prefWidthProperty().bind(verticalAxis.widthProperty().add(verticalAxis.tickLengthProperty()));
 
  194         spacer.maxWidthProperty().bind(verticalAxis.widthProperty().add(verticalAxis.tickLengthProperty()));
 
  196         dateAxis.setTickLabelsVisible(
false);
 
  198         dateAxis.getTickMarks().addListener((Observable observable) -> {
 
  201         dateAxis.getTickSpacing().addListener((Observable observable) -> {
 
  205         dateAxis.setTickLabelGap(0);
 
  208             highlightedNodes.clear();
 
  210                 for (AggregateEventNode n : 
chart.getNodes((
 
  211                         AggregateEventNode t) -> t.getEvent().getDescription().equals(tn.getEvent().getDescription()))) {
 
  212                     highlightedNodes.add(n);
 
  220         vertScrollBar.valueProperty().set(Math.max(0, Math.min(100, vertScrollBar.getValue() + factor * (chart.getHeight() / chart.getMaxVScroll().get()))));
 
  224         this.treeSelectionModel = selectionModel;
 
  226         treeSelectionModel.getSelectedItems().addListener((Observable observable) -> {
 
  227             highlightedNodes.clear();
 
  228             for (TreeItem<NavTreeNode> tn : treeSelectionModel.getSelectedItems()) {
 
  232                     highlightedNodes.add(n);
 
  255         return dateAxis.getTickSpacing().get();
 
  260         return dateAxis.getTickMarkLabel(value);
 
  271         XYChart.Series<DateTime, 
AggregateEvent> series = eventTypeToSeriesMap.get(et);
 
  272         if (series == null) {
 
  273             series = 
new XYChart.Series<>();
 
  275             eventTypeToSeriesMap.put(et, series);
 
  276             dataSets.add(series);
 
  284         return new LoggedTask<Boolean>(NbBundle.getMessage(this.getClass(), 
"DetailViewPane.loggedTask.name"), 
true) {
 
  287             protected Boolean call() 
throws Exception {
 
  291                 Platform.runLater(() -> {
 
  292                     if (isCancelled() == 
false) {
 
  293                         setCursor(Cursor.WAIT);
 
  297                 updateProgress(-1, 1);
 
  298                 updateMessage(NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.loggedTask.preparing"));
 
  304                 updateMessage(NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.loggedTask.queryDb"));
 
  305                 aggregatedEvents.setAll(filteredEvents.getAggregatedEvents());
 
  307                 Platform.runLater(() -> {
 
  316                     vertScrollBar.setValue(0);
 
  317                     eventTypeToSeriesMap.clear();
 
  320                 final int size = aggregatedEvents.size();
 
  326                     updateProgress(i++, size);
 
  327                     updateMessage(NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.loggedTask.updateUI"));
 
  328                     final XYChart.Data<DateTime, 
AggregateEvent> xyData = 
new BarChart.Data<>(
new DateTime(e.getSpan().getStartMillis()), e);
 
  330                     Platform.runLater(() -> {
 
  331                         if (isCancelled() == 
false) {
 
  332                             getSeries(e.getType()).getData().add(xyData);
 
  337                 Platform.runLater(() -> {
 
  338                     setCursor(Cursor.NONE);
 
  340                     updateProgress(1, 1);
 
  342                 return aggregatedEvents.isEmpty() == 
false;
 
  354         c1.applySelectionEffect(applied);
 
  425             assert bandByTypeBox != null : 
"fx:id=\"bandByTypeBox\" was not injected: check your FXML file 'DetailViewSettings.fxml'."; 
 
  426             assert oneEventPerRowBox != null : 
"fx:id=\"oneEventPerRowBox\" was not injected: check your FXML file 'DetailViewSettings.fxml'."; 
 
  427             assert truncateAllBox != null : 
"fx:id=\"truncateAllBox\" was not injected: check your FXML file 'DetailViewSettings.fxml'."; 
 
  428             assert truncateWidthSlider != null : 
"fx:id=\"truncateAllSlider\" was not injected: check your FXML file 'DetailViewSettings.fxml'."; 
 
  429             bandByTypeBox.selectedProperty().bindBidirectional(chart.getBandByType());
 
  430             truncateAllBox.selectedProperty().bindBidirectional(chart.getTruncateAll());
 
  431             oneEventPerRowBox.selectedProperty().bindBidirectional(chart.getOneEventPerRow());
 
  432             truncateSliderLabel.disableProperty().bind(truncateAllBox.selectedProperty().not());
 
  433             truncateSliderLabel.setText(NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.truncateSliderLabel.text"));
 
  434             final InvalidationListener sliderListener = o -> {
 
  435                 if (truncateWidthSlider.isValueChanging() == 
false) {
 
  436                     chart.getTruncateWidth().set(truncateWidthSlider.getValue());
 
  439             truncateWidthSlider.valueProperty().addListener(sliderListener);
 
  440             truncateWidthSlider.valueChangingProperty().addListener(sliderListener);
 
  442             descrVisibility.selectedToggleProperty().addListener((observable, oldToggle, newToggle) -> {
 
  443                 if (newToggle == countsRadio) {
 
  444                     chart.getDescrVisibility().set(DescriptionVisibility.COUNT_ONLY);
 
  445                 } 
else if (newToggle == showRadio) {
 
  446                     chart.getDescrVisibility().set(DescriptionVisibility.SHOWN);
 
  447                 } 
else if (newToggle == hiddenRadio) {
 
  448                     chart.getDescrVisibility().set(DescriptionVisibility.HIDDEN);
 
  452             advancedLayoutOptionsButtonLabel.setText(
 
  453                     NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.advancedLayoutOptionsButtonLabel.text"));
 
  454             bandByTypeBox.setText(NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.bandByTypeBox.text"));
 
  455             bandByTypeBoxMenuItem.setText(
 
  456                     NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.bandByTypeBoxMenuItem.text"));
 
  457             oneEventPerRowBox.setText(NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.oneEventPerRowBox.text"));
 
  458             oneEventPerRowBoxMenuItem.setText(
 
  459                     NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.oneEventPerRowBoxMenuItem.text"));
 
  460             truncateAllBox.setText(NbBundle.getMessage(
this.getClass(), 
"DetailViewPan.truncateAllBox.text"));
 
  461             truncateAllBoxMenuItem.setText(
 
  462                     NbBundle.getMessage(
this.getClass(), 
"DetailViewPan.truncateAllBoxMenuItem.text"));
 
  463             truncateSliderLabelMenuItem.setText(
 
  464                     NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.truncateSlideLabelMenuItem.text"));
 
  465             descVisibilitySeparatorMenuItem.setText(
 
  466                     NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.descVisSeparatorMenuItem.text"));
 
  467             showRadioMenuItem.setText(NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.showRadioMenuItem.text"));
 
  468             showRadio.setText(NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.showRadio.text"));
 
  469             countsRadioMenuItem.setText(NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.countsRadioMenuItem.text"));
 
  470             countsRadio.setText(NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.countsRadio.text"));
 
  471             hiddenRadioMenuItem.setText(NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.hiddenRadioMenuItem.text"));
 
  472             hiddenRadio.setText(NbBundle.getMessage(
this.getClass(), 
"DetailViewPane.hiddenRadio.text"));
 
SeparatorMenuItem descVisibilitySeparatorMenuItem
 
void setChartClickHandler()
 
void setSelectionModel(MultipleSelectionModel< TreeItem< NavTreeNode >> selectionModel)
 
CustomMenuItem showRadioMenuItem
 
void incrementScrollValue(int factor)
 
ReadOnlyListWrapper< N > selectedNodes
 
CustomMenuItem truncateSliderLabelMenuItem
 
final ObservableList< AggregateEvent > aggregatedEvents
 
Axis< AggregateEvent > getYAxis()
 
void applySelectionEffect(AggregateEventNode c1, Boolean applied)
 
Effect getSelectionEffect()
 
final ObservableList< BarChart.Series< X, Y > > dataSets
 
static void construct(Node n, String fxmlFileName)
 
static RangeDivisionInfo getRangeDivisionInfo(Interval timeRange)
 
ToggleGroup descrVisibility
 
MenuButton advancedLayoutOptionsButtonLabel
 
CustomMenuItem hiddenRadioMenuItem
 
Boolean isTickBold(DateTime value)
 
final Map< EventType, XYChart.Series< DateTime, AggregateEvent > > eventTypeToSeriesMap
 
CustomMenuItem bandByTypeBoxMenuItem
 
Label truncateSliderLabel
 
CustomMenuItem countsRadioMenuItem
 
String getTickMarkLabel(DateTime value)
 
static DateTimeZone getJodaTimeZone()
 
Axis< DateTime > getXAxis()
 
MultipleSelectionModel< TreeItem< NavTreeNode > > treeSelectionModel
 
final Axis< AggregateEvent > verticalAxis
 
CheckBox oneEventPerRowBox
 
final ObservableList< AggregateEventNode > highlightedNodes
 
synchronized void layoutDateLabels()
 
CustomMenuItem truncateAllBoxMenuItem
 
CustomMenuItem oneEventPerRowBoxMenuItem
 
Task< Boolean > getUpdateTask()
 
static final Logger LOGGER
 
AggregateEvent getEvent()
 
final ScrollBar vertScrollBar
 
DetailViewPane(Pane partPane, Pane contextPane, Region spacer)
 
static Logger getLogger(String name)
 
List< Node > settingsNodes
 
XYChart.Series< DateTime, AggregateEvent > getSeries(final EventType et)
 
Slider truncateWidthSlider
 
ObservableList< AggregateEvent > getAggregatedEvents()