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()