19package org.sleuthkit.autopsy.timeline.ui.detailview;
21import com.google.common.collect.ImmutableList;
23import java.util.Objects;
24import java.util.function.Function;
25import java.util.function.Predicate;
26import java.util.logging.Level;
27import java.util.stream.Collectors;
28import javafx.application.Platform;
29import javafx.beans.InvalidationListener;
30import javafx.beans.Observable;
31import javafx.collections.ObservableList;
32import javafx.concurrent.Task;
33import javafx.fxml.FXML;
34import javafx.scene.Node;
35import javafx.scene.chart.Axis;
36import javafx.scene.control.Alert;
37import javafx.scene.control.ButtonBar;
38import javafx.scene.control.ButtonType;
39import javafx.scene.control.CheckBox;
40import javafx.scene.control.Label;
41import javafx.scene.control.MenuButton;
42import javafx.scene.control.RadioButton;
43import javafx.scene.control.Slider;
44import javafx.scene.control.ToggleButton;
45import javafx.scene.control.ToggleGroup;
46import javafx.scene.layout.HBox;
47import javafx.stage.Modality;
48import org.apache.commons.lang3.StringUtils;
49import org.controlsfx.control.action.Action;
50import org.joda.time.DateTime;
51import org.joda.time.Interval;
52import org.openide.util.NbBundle;
53import org.sleuthkit.autopsy.coreutils.Logger;
54import org.sleuthkit.autopsy.coreutils.ThreadConfined;
55import org.sleuthkit.autopsy.timeline.FXMLConstructor;
56import org.sleuthkit.autopsy.timeline.EventsModel;
57import org.sleuthkit.autopsy.timeline.TimeLineController;
58import org.sleuthkit.autopsy.timeline.ViewMode;
59import org.sleuthkit.autopsy.timeline.ui.AbstractTimelineChart;
60import org.sleuthkit.autopsy.timeline.ui.detailview.datamodel.DetailViewEvent;
61import org.sleuthkit.autopsy.timeline.ui.detailview.datamodel.DetailsViewModel;
62import org.sleuthkit.autopsy.timeline.ui.detailview.datamodel.EventStripe;
63import org.sleuthkit.autopsy.timeline.utils.MappedList;
64import org.sleuthkit.autopsy.timeline.zooming.EventsModelParams;
65import org.sleuthkit.datamodel.TimelineLevelOfDetail;
66import org.sleuthkit.datamodel.TskCoreException;
89 @NbBundle.Messages(
"DetailViewPane.primaryLaneLabel.text=All Events (Filtered)")
90 private final Axis<EventStripe>
verticalAxis =
new EventAxis<>(Bundle.DetailViewPane_primaryLaneLabel_text());
130 .flatMap(detailNode -> detailNode.getEventIDs().stream())
131 .collect(Collectors.toList()));
132 }
catch (TskCoreException ex) {
133 logger.log(Level.SEVERE,
"Error selecting nodes.", ex);
134 new Alert(Alert.AlertType.ERROR,
"Error selecting nodes").showAndWait();
145 return getChart().getAllNestedEvents();
163 highlightedEvents.addListener((Observable observable) -> {
168 Predicate<EventNodeBase<?>> highlightPredicate
169 = highlightedEvents.stream()
173 public Predicate<EventNodeBase<?>> apply(String description) {
174 return eventNode -> StringUtils.equalsIgnoreCase(eventNode.getDescription(), description);
178 getChart().setHighlightPredicate(highlightPredicate);
196 return new UnhideDescriptionAction(description, descriptionLoD,
getChart());
208 return new HideDescriptionAction(description, descriptionLoD,
getChart());
269 return ImmutableList.of();
276 static private class DetailViewSettingsPane
extends HBox {
313 DetailViewSettingsPane(DetailsChartLayoutSettings
layoutSettings) {
319 "DetailViewPane.truncateSliderLabel.text=max description width (px):",
320 "DetailViewPane.advancedLayoutOptionsButtonLabel.text=Advanced Layout Options",
321 "DetailViewPane.bandByTypeBox.text=Band by Type",
322 "DetailViewPane.oneEventPerRowBox.text=One Per Row",
323 "DetailViewPane.truncateAllBox.text=Truncate Descriptions",
324 "DetailViewPane.showRadio.text=Show Full Description",
325 "DetailViewPane.countsRadio.text=Show Counts Only",
326 "DetailViewPane.hiddenRadio.text=Hide Description"})
329 assert
bandByTypeBox != null :
"fx:id=\"bandByTypeBox\" was not injected: check your FXML file 'DetailViewSettings.fxml'.";
330 assert
oneEventPerRowBox != null :
"fx:id=\"oneEventPerRowBox\" was not injected: check your FXML file 'DetailViewSettings.fxml'.";
331 assert
truncateAllBox != null :
"fx:id=\"truncateAllBox\" was not injected: check your FXML file 'DetailViewSettings.fxml'.";
332 assert
truncateWidthSlider != null :
"fx:id=\"truncateAllSlider\" was not injected: check your FXML file 'DetailViewSettings.fxml'.";
333 assert
pinnedEventsToggle != null :
"fx:id=\"pinnedEventsToggle\" was not injected: check your FXML file 'DetailViewSettings.fxml'.";
343 final InvalidationListener sliderListener = observable -> {
351 descrVisibility.selectedToggleProperty().addListener((observable, oldToggle, newToggle) -> {
353 layoutSettings.descrVisibilityProperty().set(DescriptionVisibility.COUNT_ONLY);
355 layoutSettings.descrVisibilityProperty().set(DescriptionVisibility.SHOWN);
357 layoutSettings.descrVisibilityProperty().set(DescriptionVisibility.HIDDEN);
364 bandByTypeBox.setText(Bundle.DetailViewPane_bandByTypeBox_text());
366 truncateAllBox.setText(Bundle.DetailViewPane_truncateAllBox_text());
367 showRadio.setText(Bundle.DetailViewPane_showRadio_text());
368 countsRadio.setText(Bundle.DetailViewPane_countsRadio_text());
369 hiddenRadio.setText(Bundle.DetailViewPane_hiddenRadio_text());
374 "DetailViewPane.loggedTask.queryDb=Retrieving event data",
375 "DetailViewPane.loggedTask.name=Updating Details View",
376 "DetailViewPane.loggedTask.updateUI=Populating view",
377 "DetailViewPane.loggedTask.continueButton=Continue",
378 "DetailViewPane.loggedTask.backButton=Back (Cancel)",
379 "# {0} - number of events",
380 "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?"})
383 DetailsUpdateTask() {
384 super(Bundle.DetailViewPane_loggedTask_name(),
true);
388 protected Boolean
call() throws Exception {
402 updateMessage(Bundle.DetailViewPane_loggedTask_queryDb());
406 final int size = eventStripes.size();
409 Task<ButtonType> task =
new Task<ButtonType>() {
411 protected ButtonType
call()
throws Exception {
412 ButtonType ContinueButtonType =
new ButtonType(Bundle.DetailViewPane_loggedTask_continueButton(), ButtonBar.ButtonData.OK_DONE);
413 ButtonType back =
new ButtonType(Bundle.DetailViewPane_loggedTask_backButton(), ButtonBar.ButtonData.CANCEL_CLOSE);
415 Alert alert =
new Alert(Alert.AlertType.WARNING, Bundle.DetailViewPane_loggedTask_prompt(size), ContinueButtonType, back);
416 alert.setHeaderText(
"");
417 alert.initModality(Modality.APPLICATION_MODAL);
418 alert.initOwner(getScene().getWindow());
419 ButtonType userResponse = alert.showAndWait().orElse(back);
420 if (userResponse == back) {
421 DetailsUpdateTask.this.cancel();
427 Platform.runLater(task);
439 updateMessage(Bundle.DetailViewPane_loggedTask_updateUI());
442 for (
int i = 0; i < size; i++) {
446 updateProgress(i, size);
448 Platform.runLater(() ->
getChart().addStripe(stripe));
451 return eventStripes.isEmpty() ==
false;
synchronized static Logger getLogger(String name)
synchronized Interval getTimeRange()
synchronized EventsModelParams getModelParams()
static void construct(Node node, String fxmlFileName)
final synchronized void selectEventIDs(Collection< Long > eventIDs)
synchronized void retreat()
ViewRefreshTask(String taskName, boolean logStateChanges)
void resetView(AxisValuesType axisValues)
TimeLineController getController()
EventsModel getEventsModel()
final TimeLineController controller
final ReadOnlyBooleanWrapper needsRefresh
ObservableList< NodeType > getSelectedNodes()
AbstractTimelineChart(TimeLineController controller)
synchronized void layoutDateLabels()
void setChart(ChartType chart)
ToggleGroup descrVisibility
ToggleButton pinnedEventsToggle
final DetailsChartLayoutSettings layoutSettings
CheckBox oneEventPerRowBox
Slider truncateWidthSlider
MenuButton advancedLayoutOptionsButtonLabel
Label truncateSliderLabel
void setDateValues(Interval timeRange)
ObservableList< DetailViewEvent > getSelectedEvents()
Action newHideDescriptionAction(String description, TimelineLevelOfDetail descriptionLoD)
final MappedList< DetailViewEvent, EventNodeBase<?> > selectedEvents
ImmutableList< Node > getSettingsControls()
Action newUnhideDescriptionAction(String description, TimelineLevelOfDetail descriptionLoD)
boolean hasCustomTimeNavigationControls()
void setHighLightedEvents(ObservableList< DetailViewEvent > highlightedEvents)
Boolean isTickBold(DateTime value)
final DateAxis detailsChartDateAxis
final Axis< EventStripe > verticalAxis
Task< Boolean > getNewUpdateTask()
EventsModelParams currentZoom
ImmutableList< Node > getTimeNavigationControls()
final DateAxis getXAxis()
final Axis< EventStripe > getYAxis()
ObservableList< DetailViewEvent > getAllNestedEvents()
final DateAxis pinnedDateAxis
String getTickMarkLabel(DateTime value)
DetailViewPane(TimeLineController controller)
final ViewMode getViewMode()
final DetailsViewModel detailsViewModel
void applySelectionEffect(EventNodeBase<?> c1, Boolean selected)
static final Logger logger
void applySelectionEffect(boolean applied)