19 package org.sleuthkit.autopsy.timeline.ui.detailview;
21 import com.google.common.collect.ImmutableList;
22 import java.util.List;
23 import java.util.Objects;
24 import java.util.function.Function;
25 import java.util.function.Predicate;
26 import java.util.stream.Collectors;
27 import javafx.application.Platform;
28 import javafx.beans.InvalidationListener;
29 import javafx.beans.Observable;
30 import javafx.collections.ObservableList;
31 import javafx.concurrent.Task;
32 import javafx.fxml.FXML;
33 import javafx.scene.Node;
34 import javafx.scene.chart.Axis;
35 import javafx.scene.control.Alert;
36 import javafx.scene.control.ButtonBar;
37 import javafx.scene.control.ButtonType;
38 import javafx.scene.control.CheckBox;
39 import javafx.scene.control.Label;
40 import javafx.scene.control.MenuButton;
41 import javafx.scene.control.RadioButton;
42 import javafx.scene.control.Slider;
43 import javafx.scene.control.ToggleButton;
44 import javafx.scene.control.ToggleGroup;
45 import javafx.scene.layout.HBox;
46 import javafx.stage.Modality;
47 import org.apache.commons.lang3.StringUtils;
48 import org.controlsfx.control.action.Action;
49 import org.joda.time.DateTime;
50 import org.joda.time.Interval;
51 import org.openide.util.NbBundle;
86 @NbBundle.Messages(
"DetailViewPane.primaryLaneLabel.text=All Events (Filtered)")
87 private final Axis<EventStripe>
verticalAxis =
new EventAxis<>(Bundle.DetailViewPane_primaryLaneLabel_text());
114 detailsChartDateAxis.getTickMarks().addListener((Observable observable) ->
layoutDateLabels());
115 detailsChartDateAxis.getTickSpacing().addListener(observable ->
layoutDateLabels());
116 verticalAxis.setAutoRanging(
false);
124 .flatMap(detailNode -> detailNode.getEventIDs().stream())
125 .collect(Collectors.toList()));
135 return getChart().getAllNestedEvents();
153 highlightedEvents.addListener((Observable observable) -> {
158 Predicate<EventNodeBase<?>> highlightPredicate =
159 highlightedEvents.stream()
163 public Predicate<EventNodeBase<?>> apply(String description) {
164 return eventNode -> StringUtils.equalsIgnoreCase(eventNode.getDescription(), description);
168 getChart().setHighlightPredicate(highlightPredicate);
186 return new UnhideDescriptionAction(description, descriptionLoD,
getChart());
198 return new HideDescriptionAction(description, descriptionLoD,
getChart());
219 return detailsChartDateAxis.getTickSpacing().get();
224 return detailsChartDateAxis.getTickMarkLabel(value);
259 return ImmutableList.of();
309 "DetailViewPane.truncateSliderLabel.text=max description width (px):",
310 "DetailViewPane.advancedLayoutOptionsButtonLabel.text=Advanced Layout Options",
311 "DetailViewPane.bandByTypeBox.text=Band by Type",
312 "DetailViewPane.oneEventPerRowBox.text=One Per Row",
313 "DetailViewPane.truncateAllBox.text=Truncate Descriptions",
314 "DetailViewPane.showRadio.text=Show Full Description",
315 "DetailViewPane.countsRadio.text=Show Counts Only",
316 "DetailViewPane.hiddenRadio.text=Hide Description"})
319 assert bandByTypeBox != null :
"fx:id=\"bandByTypeBox\" was not injected: check your FXML file 'DetailViewSettings.fxml'.";
320 assert oneEventPerRowBox != null :
"fx:id=\"oneEventPerRowBox\" was not injected: check your FXML file 'DetailViewSettings.fxml'.";
321 assert truncateAllBox != null :
"fx:id=\"truncateAllBox\" was not injected: check your FXML file 'DetailViewSettings.fxml'.";
322 assert truncateWidthSlider != null :
"fx:id=\"truncateAllSlider\" was not injected: check your FXML file 'DetailViewSettings.fxml'.";
323 assert pinnedEventsToggle != null :
"fx:id=\"pinnedEventsToggle\" was not injected: check your FXML file 'DetailViewSettings.fxml'.";
326 bandByTypeBox.selectedProperty().bindBidirectional(layoutSettings.bandByTypeProperty());
328 oneEventPerRowBox.selectedProperty().bindBidirectional(layoutSettings.oneEventPerRowProperty());
329 truncateAllBox.selectedProperty().bindBidirectional(layoutSettings.truncateAllProperty());
330 truncateSliderLabel.disableProperty().bind(truncateAllBox.selectedProperty().not());
331 pinnedEventsToggle.selectedProperty().bindBidirectional(layoutSettings.pinnedLaneShowing());
333 final InvalidationListener sliderListener = observable -> {
334 if (truncateWidthSlider.isValueChanging() ==
false) {
335 layoutSettings.truncateWidthProperty().set(truncateWidthSlider.getValue());
338 truncateWidthSlider.valueProperty().addListener(sliderListener);
339 truncateWidthSlider.valueChangingProperty().addListener(sliderListener);
341 descrVisibility.selectedToggleProperty().addListener((observable, oldToggle, newToggle) -> {
342 if (newToggle == countsRadio) {
343 layoutSettings.descrVisibilityProperty().set(DescriptionVisibility.COUNT_ONLY);
344 }
else if (newToggle == showRadio) {
345 layoutSettings.descrVisibilityProperty().set(DescriptionVisibility.SHOWN);
346 }
else if (newToggle == hiddenRadio) {
347 layoutSettings.descrVisibilityProperty().set(DescriptionVisibility.HIDDEN);
352 truncateSliderLabel.setText(Bundle.DetailViewPane_truncateSliderLabel_text());
353 advancedLayoutOptionsButtonLabel.setText(Bundle.DetailViewPane_advancedLayoutOptionsButtonLabel_text());
354 bandByTypeBox.setText(Bundle.DetailViewPane_bandByTypeBox_text());
355 oneEventPerRowBox.setText(Bundle.DetailViewPane_oneEventPerRowBox_text());
356 truncateAllBox.setText(Bundle.DetailViewPane_truncateAllBox_text());
357 showRadio.setText(Bundle.DetailViewPane_showRadio_text());
358 countsRadio.setText(Bundle.DetailViewPane_countsRadio_text());
359 hiddenRadio.setText(Bundle.DetailViewPane_hiddenRadio_text());
364 "DetailViewPane.loggedTask.queryDb=Retrieving event data",
365 "DetailViewPane.loggedTask.name=Updating Details View",
366 "DetailViewPane.loggedTask.updateUI=Populating view",
367 "DetailViewPane.loggedTask.continueButton=Continue",
368 "DetailViewPane.loggedTask.backButton=Back (Cancel)",
369 "# {0} - number of events",
370 "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?"})
374 super(Bundle.DetailViewPane_loggedTask_name(),
true);
378 protected Boolean
call() throws Exception {
388 if (Objects.equals(currentZoomParams, newZoomParams)) {
392 updateMessage(Bundle.DetailViewPane_loggedTask_queryDb());
396 final int size = eventStripes.size();
399 Task<ButtonType> task =
new Task<ButtonType>() {
401 protected ButtonType call()
throws Exception {
402 ButtonType ContinueButtonType =
new ButtonType(Bundle.DetailViewPane_loggedTask_continueButton(), ButtonBar.ButtonData.OK_DONE);
403 ButtonType back =
new ButtonType(Bundle.DetailViewPane_loggedTask_backButton(), ButtonBar.ButtonData.CANCEL_CLOSE);
405 Alert alert =
new Alert(Alert.AlertType.WARNING, Bundle.DetailViewPane_loggedTask_prompt(size), ContinueButtonType, back);
406 alert.setHeaderText(
"");
407 alert.initModality(Modality.APPLICATION_MODAL);
408 alert.initOwner(getScene().getWindow());
409 ButtonType userResponse = alert.showAndWait().orElse(back);
410 if (userResponse == back) {
417 Platform.runLater(task);
424 currentZoomParams = newZoomParams;
429 updateMessage(Bundle.DetailViewPane_loggedTask_updateUI());
432 for (
int i = 0; i < size; i++) {
436 updateProgress(i, size);
438 Platform.runLater(() ->
getChart().addStripe(stripe));
441 return eventStripes.isEmpty() ==
false;
452 detailsChartDateAxis.setRange(timeRange,
true);
453 pinnedDateAxis.setRange(timeRange,
true);
Action newHideDescriptionAction(String description, DescriptionLoD descriptionLoD)
TimeLineController getController()
boolean hasCustomTimeNavigationControls()
ObservableList< TimeLineEvent > getSelectedEvents()
ObservableList< TimeLineEvent > getAllNestedEvents()
final DateAxis getXAxis()
ToggleButton pinnedEventsToggle
synchronized Interval getTimeRange()
List< EventStripe > getEventStripes()
final ViewMode getViewMode()
FilteredEventsModel getEventsModel()
synchronized void selectEventIDs(Collection< Long > eventIDs)
ImmutableList< Node > getSettingsControls()
ObservableList< NodeType > getSelectedNodes()
ZoomParams currentZoomParams
final DateAxis detailsChartDateAxis
ToggleGroup descrVisibility
void applySelectionEffect(boolean applied)
void setDateValues(Interval timeRange)
MenuButton advancedLayoutOptionsButtonLabel
DetailViewPane(TimeLineController controller)
Boolean isTickBold(DateTime value)
Label truncateSliderLabel
synchronized ZoomParams getZoomParamaters()
void setHighLightedEvents(ObservableList< TimeLineEvent > highlightedEvents)
String getTickMarkLabel(DateTime value)
final DetailsChartLayoutSettings layoutSettings
void applySelectionEffect(EventNodeBase<?> c1, Boolean selected)
final TimeLineController controller
synchronized void retreat()
CheckBox oneEventPerRowBox
synchronized static Logger getLogger(String name)
ImmutableList< Node > getTimeNavigationControls()
final Axis< EventStripe > getYAxis()
static final Logger LOGGER
static void construct(Node node, String fxmlFileName)
synchronized void layoutDateLabels()
void setChart(ChartType chart)
Task< Boolean > getNewUpdateTask()
final Axis< EventStripe > verticalAxis
final MappedList< TimeLineEvent, EventNodeBase<?> > selectedEvents
final DateAxis pinnedDateAxis
Slider truncateWidthSlider
Action newUnhideDescriptionAction(String description, DescriptionLoD descriptionLoD)