mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-19 11:07:43 +00:00
split AbstractVisualizationPane into AbstractTimeLineView and AbstractTimelineChart
CountsViewPane and DetailViewPane extend AbstractTimelineChart, ListViewPane extends AbstractTimeLineView
This commit is contained in:
parent
b3c6f0a40c
commit
4d14c32a94
@ -0,0 +1,360 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.timeline.ui;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.InvalidationListener;
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||||
|
import javafx.beans.property.ReadOnlyBooleanWrapper;
|
||||||
|
import javafx.concurrent.Task;
|
||||||
|
import javafx.scene.Cursor;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.layout.BorderPane;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
|
import org.controlsfx.control.MaskerPane;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.LoggedTask;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
|
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||||
|
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||||
|
import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent;
|
||||||
|
|
||||||
|
public abstract class AbstractTimeLineView extends BorderPane {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(AbstractTimeLineView.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boolean property that holds true if the visualization does not show any
|
||||||
|
* events with the current zoom and filter settings.
|
||||||
|
*/
|
||||||
|
private final ReadOnlyBooleanWrapper hasVisibleEvents = new ReadOnlyBooleanWrapper(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boolean property that holds true if the visualization may not represent
|
||||||
|
* the current state of the DB, because, for example, tags have been updated
|
||||||
|
* but the vis. was not refreshed.
|
||||||
|
*/
|
||||||
|
private final ReadOnlyBooleanWrapper outOfDate = new ReadOnlyBooleanWrapper(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of Nodes to insert into the toolbar. This should be set in an
|
||||||
|
* implementations constructor.
|
||||||
|
*/
|
||||||
|
private List<Node> settingsNodes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener that is attached to various properties that should trigger a vis
|
||||||
|
* update when they change.
|
||||||
|
*/
|
||||||
|
private InvalidationListener updateListener = (Observable any) -> refresh();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* task used to reload the content of this visualization
|
||||||
|
*/
|
||||||
|
private Task<Boolean> updateTask;
|
||||||
|
|
||||||
|
private final TimeLineController controller;
|
||||||
|
private final FilteredEventsModel filteredEvents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param controller
|
||||||
|
*/
|
||||||
|
public AbstractTimeLineView(TimeLineController controller) {
|
||||||
|
this.controller = controller;
|
||||||
|
this.filteredEvents = controller.getEventsModel();
|
||||||
|
this.filteredEvents.registerForEvents(this);
|
||||||
|
this.filteredEvents.zoomParametersProperty().addListener(updateListener);
|
||||||
|
TimeLineController.getTimeZone().addListener(updateListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a RefreshRequestedEvent from the events model by updating the
|
||||||
|
* visualization.
|
||||||
|
*
|
||||||
|
* @param event The RefreshRequestedEvent to handle.
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
public void handleRefreshRequested(RefreshRequestedEvent event) {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the visualization represent an out-of-date state of the DB. It might
|
||||||
|
* if, for example, tags have been updated but the vis. was not refreshed.
|
||||||
|
*
|
||||||
|
* @return True if the visualization does not represent the curent state of
|
||||||
|
* the DB.
|
||||||
|
*/
|
||||||
|
public boolean isOutOfDate() {
|
||||||
|
return outOfDate.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a ReadOnlyBooleanProperty that holds true if this visualization does
|
||||||
|
* not represent the current state of the DB>
|
||||||
|
*
|
||||||
|
* @return A ReadOnlyBooleanProperty that holds the out-of-date state for
|
||||||
|
* this visualization.
|
||||||
|
*/
|
||||||
|
public ReadOnlyBooleanProperty outOfDateProperty() {
|
||||||
|
return outOfDate.getReadOnlyProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the TimelineController for this visualization.
|
||||||
|
*
|
||||||
|
* @return The TimelineController for this visualization.
|
||||||
|
*/
|
||||||
|
protected TimeLineController getController() {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh this visualization based on current state of zoom / filters.
|
||||||
|
* Primarily this invokes the background VisualizationUpdateTask returned by
|
||||||
|
* getUpdateTask(), which derived classes must implement.
|
||||||
|
*
|
||||||
|
* TODO: replace this logic with a javafx Service ? -jm
|
||||||
|
*/
|
||||||
|
protected final synchronized void refresh() {
|
||||||
|
if (updateTask != null) {
|
||||||
|
updateTask.cancel(true);
|
||||||
|
updateTask = null;
|
||||||
|
}
|
||||||
|
updateTask = getNewUpdateTask();
|
||||||
|
updateTask.stateProperty().addListener((Observable observable) -> {
|
||||||
|
switch (updateTask.getState()) {
|
||||||
|
case CANCELLED:
|
||||||
|
case FAILED:
|
||||||
|
case READY:
|
||||||
|
case RUNNING:
|
||||||
|
case SCHEDULED:
|
||||||
|
break;
|
||||||
|
case SUCCEEDED:
|
||||||
|
try {
|
||||||
|
this.hasVisibleEvents.set(updateTask.get());
|
||||||
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Unexpected exception updating visualization", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
getController().monitorTask(updateTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the FilteredEventsModel for this visualization.
|
||||||
|
*
|
||||||
|
* @return The FilteredEventsModel for this visualization.
|
||||||
|
*/
|
||||||
|
protected FilteredEventsModel getEventsModel() {
|
||||||
|
return filteredEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a new background Task that fetches the appropriate data and loads it
|
||||||
|
* into this visualization.
|
||||||
|
*
|
||||||
|
* @return A new task to execute on a background thread to reload this
|
||||||
|
* visualization with different data.
|
||||||
|
*/
|
||||||
|
protected abstract Task<Boolean> getNewUpdateTask();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a List of nodes containing settings widgets to insert into this
|
||||||
|
* visualization's header.
|
||||||
|
*
|
||||||
|
* @return The List of settings Nodes.
|
||||||
|
*/
|
||||||
|
protected List<Node> getSettingsNodes() {
|
||||||
|
return Collections.unmodifiableList(settingsNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the List of nodes containing settings widgets to insert into this
|
||||||
|
* visualization's header.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param settingsNodes The List of nodes containing settings widgets to
|
||||||
|
* insert into this visualization's header.
|
||||||
|
*/
|
||||||
|
final protected void setSettingsNodes(List<Node> settingsNodes) {
|
||||||
|
this.settingsNodes = new ArrayList<>(settingsNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispose of this visualization and any resources it holds onto.
|
||||||
|
*/
|
||||||
|
final synchronized void dispose() {
|
||||||
|
//cancel and gc updateTask
|
||||||
|
if (updateTask != null) {
|
||||||
|
updateTask.cancel(true);
|
||||||
|
updateTask = null;
|
||||||
|
}
|
||||||
|
//remvoe and gc updateListener
|
||||||
|
this.filteredEvents.zoomParametersProperty().removeListener(updateListener);
|
||||||
|
TimeLineController.getTimeZone().removeListener(updateListener);
|
||||||
|
updateListener = null;
|
||||||
|
filteredEvents.unRegisterForEvents(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Are there are any events visible in this visualization with the current
|
||||||
|
* view parameters?
|
||||||
|
*
|
||||||
|
* @return True if there are events visible in this visualization with the
|
||||||
|
* current view parameters.
|
||||||
|
*/
|
||||||
|
boolean hasVisibleEvents() {
|
||||||
|
return hasVisibleEventsProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A property that indicates whether there are any events visible in this
|
||||||
|
* visualization with the current view parameters.
|
||||||
|
*
|
||||||
|
* @return A property that indicates whether there are any events visible in
|
||||||
|
* this visualization with the current view parameters.
|
||||||
|
*/
|
||||||
|
ReadOnlyBooleanProperty hasVisibleEventsProperty() {
|
||||||
|
return hasVisibleEvents.getReadOnlyProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set this visualization out of date because, for example, tags have been
|
||||||
|
* updated but the vis. was not refreshed.
|
||||||
|
*/
|
||||||
|
void setOutOfDate() {
|
||||||
|
outOfDate.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all data items from this chart.
|
||||||
|
*/
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||||
|
abstract protected void clearData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for Tasks that refreshes a view when the view settings change.
|
||||||
|
*
|
||||||
|
* @param <AxisValuesType> The type of a single object that can represent
|
||||||
|
* the range of data displayed along the X-Axis.
|
||||||
|
*/
|
||||||
|
protected abstract class ViewRefreshTask<AxisValuesType> extends LoggedTask<Boolean> {
|
||||||
|
|
||||||
|
private final Node center;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param taskName The name of this task.
|
||||||
|
* @param logStateChanges Whether or not task state changes should be
|
||||||
|
* logged.
|
||||||
|
*/
|
||||||
|
protected ViewRefreshTask(String taskName, boolean logStateChanges) {
|
||||||
|
super(taskName, logStateChanges);
|
||||||
|
this.center = getCenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets initial progress value and message and shows blocking progress
|
||||||
|
* indicator over the visualization. Derived Tasks should be sure to
|
||||||
|
* call this as part of their call() implementation.
|
||||||
|
*
|
||||||
|
* @return True
|
||||||
|
*
|
||||||
|
* @throws Exception If there is an unhandled exception during the
|
||||||
|
* background operation
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages(value = {"VisualizationUpdateTask.preparing=Analyzing zoom and filter settings"})
|
||||||
|
@Override
|
||||||
|
protected Boolean call() throws Exception {
|
||||||
|
updateProgress(-1, 1);
|
||||||
|
updateMessage(Bundle.VisualizationUpdateTask_preparing());
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
MaskerPane maskerPane = new MaskerPane();
|
||||||
|
maskerPane.textProperty().bind(messageProperty());
|
||||||
|
maskerPane.progressProperty().bind(progressProperty());
|
||||||
|
setCenter(new StackPane(center, maskerPane));
|
||||||
|
setCursor(Cursor.WAIT);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the horizontal axis and removes the blocking progress
|
||||||
|
* indicator. Derived Tasks should be sure to call this as part of their
|
||||||
|
* succeeded() implementation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void succeeded() {
|
||||||
|
super.succeeded();
|
||||||
|
outOfDate.set(false);
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the blocking progress indicator. Derived Tasks should be sure
|
||||||
|
* to call this as part of their cancelled() implementation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void cancelled() {
|
||||||
|
super.cancelled();
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the blocking progress indicator. Derived Tasks should be sure
|
||||||
|
* to call this as part of their failed() implementation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void failed() {
|
||||||
|
super.failed();
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the blocking progress indicator and reset the cursor to the
|
||||||
|
* default.
|
||||||
|
*/
|
||||||
|
private void cleanup() {
|
||||||
|
setCenter(center); //clear masker pane installed in call()
|
||||||
|
setCursor(Cursor.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the horizontal range that this chart will show.
|
||||||
|
*
|
||||||
|
* @param values A single object representing the range that this chart
|
||||||
|
* will show.
|
||||||
|
*/
|
||||||
|
protected abstract void setDateValues(AxisValuesType values);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the chart data and sets the horizontal axis range. For use
|
||||||
|
* within the derived implementation of the call() method.
|
||||||
|
*
|
||||||
|
* @param axisValues
|
||||||
|
*/
|
||||||
|
@ThreadConfined(type = ThreadConfined.ThreadType.NOT_UI)
|
||||||
|
protected void resetView(AxisValuesType axisValues) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
clearData();
|
||||||
|
setDateValues(axisValues);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,27 +18,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.timeline.ui;
|
package org.sleuthkit.autopsy.timeline.ui;
|
||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import javafx.application.Platform;
|
|
||||||
import javafx.beans.InvalidationListener;
|
|
||||||
import javafx.beans.Observable;
|
|
||||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
|
||||||
import javafx.beans.property.ReadOnlyBooleanWrapper;
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.collections.transformation.SortedList;
|
import javafx.collections.transformation.SortedList;
|
||||||
import javafx.concurrent.Task;
|
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Cursor;
|
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.chart.Axis;
|
import javafx.scene.chart.Axis;
|
||||||
import javafx.scene.chart.XYChart;
|
import javafx.scene.chart.XYChart;
|
||||||
@ -46,14 +33,12 @@ import javafx.scene.control.Label;
|
|||||||
import javafx.scene.control.OverrunStyle;
|
import javafx.scene.control.OverrunStyle;
|
||||||
import javafx.scene.control.Tooltip;
|
import javafx.scene.control.Tooltip;
|
||||||
import javafx.scene.layout.Border;
|
import javafx.scene.layout.Border;
|
||||||
import javafx.scene.layout.BorderPane;
|
|
||||||
import javafx.scene.layout.BorderStroke;
|
import javafx.scene.layout.BorderStroke;
|
||||||
import javafx.scene.layout.BorderStrokeStyle;
|
import javafx.scene.layout.BorderStrokeStyle;
|
||||||
import javafx.scene.layout.BorderWidths;
|
import javafx.scene.layout.BorderWidths;
|
||||||
import javafx.scene.layout.CornerRadii;
|
import javafx.scene.layout.CornerRadii;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
import javafx.scene.layout.StackPane;
|
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.scene.text.Font;
|
import javafx.scene.text.Font;
|
||||||
import javafx.scene.text.FontWeight;
|
import javafx.scene.text.FontWeight;
|
||||||
@ -61,15 +46,11 @@ import javafx.scene.text.Text;
|
|||||||
import javafx.scene.text.TextAlignment;
|
import javafx.scene.text.TextAlignment;
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.controlsfx.control.MaskerPane;
|
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.coreutils.LoggedTask;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
||||||
import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for TimeLineChart based visualizations.
|
* Abstract base class for TimeLineChart based visualizations.
|
||||||
@ -85,9 +66,9 @@ import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent;
|
|||||||
*
|
*
|
||||||
* TODO: pull up common history context menu items out of derived classes? -jm
|
* TODO: pull up common history context menu items out of derived classes? -jm
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, ChartType extends Region & TimeLineChart<X>> extends BorderPane implements TimeLineView {
|
public abstract class AbstractTimelineChart<X, Y, NodeType extends Node, ChartType extends Region & TimeLineChart<X>> extends AbstractTimeLineView {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(AbstractVisualizationPane.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(AbstractTimelineChart.class.getName());
|
||||||
|
|
||||||
@NbBundle.Messages("AbstractVisualization.Default_Tooltip.text=Drag the mouse to select a time interval to zoom into.\nRight-click for more actions.")
|
@NbBundle.Messages("AbstractVisualization.Default_Tooltip.text=Drag the mouse to select a time interval to zoom into.\nRight-click for more actions.")
|
||||||
private static final Tooltip DEFAULT_TOOLTIP = new Tooltip(Bundle.AbstractVisualization_Default_Tooltip_text());
|
private static final Tooltip DEFAULT_TOOLTIP = new Tooltip(Bundle.AbstractVisualization_Default_Tooltip_text());
|
||||||
@ -99,22 +80,19 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
*
|
*
|
||||||
* @return The default Tooltip.
|
* @return The default Tooltip.
|
||||||
*/
|
*/
|
||||||
public static Tooltip getDefaultTooltip() {
|
static public Tooltip getDefaultTooltip() {
|
||||||
return DEFAULT_TOOLTIP;
|
return DEFAULT_TOOLTIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Boolean property that holds true if the visualization may not represent
|
* The visualization nodes that are selected.
|
||||||
* the current state of the DB, because, for example, tags have been updated
|
*
|
||||||
* but the vis. was not refreshed.
|
* @return An ObservableList<NodeType> of the nodes that are selected in
|
||||||
|
* this visualization.
|
||||||
*/
|
*/
|
||||||
private final ReadOnlyBooleanWrapper outOfDate = new ReadOnlyBooleanWrapper(false);
|
protected ObservableList<NodeType> getSelectedNodes() {
|
||||||
|
return selectedNodes;
|
||||||
/**
|
}
|
||||||
* Boolean property that holds true if the visualization does not show any
|
|
||||||
* events with the current zoom and filter settings.
|
|
||||||
*/
|
|
||||||
private final ReadOnlyBooleanWrapper hasVisibleEvents = new ReadOnlyBooleanWrapper(true);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access to chart data via series
|
* Access to chart data via series
|
||||||
@ -127,54 +105,11 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
//// replacement axis label componenets
|
//// replacement axis label componenets
|
||||||
private final Pane specificLabelPane = new Pane(); // container for the specfic labels in the decluttered axis
|
private final Pane specificLabelPane = new Pane(); // container for the specfic labels in the decluttered axis
|
||||||
private final Pane contextLabelPane = new Pane();// container for the contextual labels in the decluttered axis
|
private final Pane contextLabelPane = new Pane();// container for the contextual labels in the decluttered axis
|
||||||
|
// container for the contextual labels in the decluttered axis
|
||||||
private final Region spacer = new Region();
|
private final Region spacer = new Region();
|
||||||
|
|
||||||
/**
|
|
||||||
* task used to reload the content of this visualization
|
|
||||||
*/
|
|
||||||
private Task<Boolean> updateTask;
|
|
||||||
|
|
||||||
final private TimeLineController controller;
|
|
||||||
final private FilteredEventsModel filteredEvents;
|
|
||||||
|
|
||||||
final private ObservableList<NodeType> selectedNodes = FXCollections.observableArrayList();
|
final private ObservableList<NodeType> selectedNodes = FXCollections.observableArrayList();
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener that is attached to various properties that should trigger a vis
|
|
||||||
* update when they change.
|
|
||||||
*/
|
|
||||||
private InvalidationListener updateListener = any -> refresh();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does the visualization represent an out-of-date state of the DB. It might
|
|
||||||
* if, for example, tags have been updated but the vis. was not refreshed.
|
|
||||||
*
|
|
||||||
* @return True if the visualization does not represent the curent state of
|
|
||||||
* the DB.
|
|
||||||
*/
|
|
||||||
public boolean isOutOfDate() {
|
|
||||||
return outOfDate.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set this visualization out of date because, for example, tags have been
|
|
||||||
* updated but the vis. was not refreshed.
|
|
||||||
*/
|
|
||||||
void setOutOfDate() {
|
|
||||||
outOfDate.set(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a ReadOnlyBooleanProperty that holds true if this visualization does
|
|
||||||
* not represent the current state of the DB>
|
|
||||||
*
|
|
||||||
* @return A ReadOnlyBooleanProperty that holds the out-of-date state for
|
|
||||||
* this visualization.
|
|
||||||
*/
|
|
||||||
public ReadOnlyBooleanProperty outOfDateProperty() {
|
|
||||||
return outOfDate.getReadOnlyProperty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Pane getSpecificLabelPane() {
|
public Pane getSpecificLabelPane() {
|
||||||
return specificLabelPane;
|
return specificLabelPane;
|
||||||
}
|
}
|
||||||
@ -187,53 +122,6 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
return spacer;
|
return spacer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The visualization nodes that are selected.
|
|
||||||
*
|
|
||||||
* @return An ObservableList<NodeType> of the nodes that are selected in
|
|
||||||
* this visualization.
|
|
||||||
*/
|
|
||||||
protected ObservableList<NodeType> getSelectedNodes() {
|
|
||||||
return selectedNodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of Nodes to insert into the toolbar. This should be set in an
|
|
||||||
* implementations constructor.
|
|
||||||
*/
|
|
||||||
private List<Node> settingsNodes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a List of nodes containing settings widgets to insert into this
|
|
||||||
* visualization's header.
|
|
||||||
*
|
|
||||||
* @return The List of settings Nodes.
|
|
||||||
*/
|
|
||||||
protected List<Node> getSettingsNodes() {
|
|
||||||
return Collections.unmodifiableList(settingsNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the List of nodes containing settings widgets to insert into this
|
|
||||||
* visualization's header.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param settingsNodes The List of nodes containing settings widgets to
|
|
||||||
* insert into this visualization's header.
|
|
||||||
*/
|
|
||||||
protected void setSettingsNodes(List<Node> settingsNodes) {
|
|
||||||
this.settingsNodes = new ArrayList<>(settingsNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the TimelineController for this visualization.
|
|
||||||
*
|
|
||||||
* @return The TimelineController for this visualization.
|
|
||||||
*/
|
|
||||||
protected TimeLineController getController() {
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the CharType that implements this visualization.
|
* Get the CharType that implements this visualization.
|
||||||
*
|
*
|
||||||
@ -243,15 +131,6 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
return chart;
|
return chart;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the FilteredEventsModel for this visualization.
|
|
||||||
*
|
|
||||||
* @return The FilteredEventsModel for this visualization.
|
|
||||||
*/
|
|
||||||
protected FilteredEventsModel getEventsModel() {
|
|
||||||
return filteredEvents;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the ChartType that implements this visualization.
|
* Set the ChartType that implements this visualization.
|
||||||
*
|
*
|
||||||
@ -263,28 +142,6 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
setCenter(chart);
|
setCenter(chart);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A property that indicates whether there are any events visible in this
|
|
||||||
* visualization with the current view parameters.
|
|
||||||
*
|
|
||||||
* @return A property that indicates whether there are any events visible in
|
|
||||||
* this visualization with the current view parameters.
|
|
||||||
*/
|
|
||||||
ReadOnlyBooleanProperty hasVisibleEventsProperty() {
|
|
||||||
return hasVisibleEvents.getReadOnlyProperty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Are there are any events visible in this visualization with the current
|
|
||||||
* view parameters?
|
|
||||||
*
|
|
||||||
* @return True if there are events visible in this visualization with the
|
|
||||||
* current view parameters.
|
|
||||||
*/
|
|
||||||
boolean hasVisibleEvents() {
|
|
||||||
return hasVisibleEventsProperty().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply this visualization's 'selection effect' to the given node.
|
* Apply this visualization's 'selection effect' to the given node.
|
||||||
*
|
*
|
||||||
@ -324,15 +181,6 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
*/
|
*/
|
||||||
abstract protected void applySelectionEffect(NodeType node, Boolean applied);
|
abstract protected void applySelectionEffect(NodeType node, Boolean applied);
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a new background Task that fetches the appropriate data and loads it
|
|
||||||
* into this visualization.
|
|
||||||
*
|
|
||||||
* @return A new task to execute on a background thread to reload this
|
|
||||||
* visualization with different data.
|
|
||||||
*/
|
|
||||||
abstract protected Task<Boolean> getNewUpdateTask();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the label that should be used for a tick mark at the given value.
|
* Get the label that should be used for a tick mark at the given value.
|
||||||
*
|
*
|
||||||
@ -373,74 +221,6 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
*/
|
*/
|
||||||
abstract protected double getAxisMargin();
|
abstract protected double getAxisMargin();
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear all data items from this chart.
|
|
||||||
*/
|
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
|
||||||
abstract protected void clearChartData();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refresh this visualization based on current state of zoom / filters.
|
|
||||||
* Primarily this invokes the background VisualizationUpdateTask returned by
|
|
||||||
* getUpdateTask(), which derived classes must implement.
|
|
||||||
*
|
|
||||||
* TODO: replace this logic with a javafx Service ? -jm
|
|
||||||
*/
|
|
||||||
protected final synchronized void refresh() {
|
|
||||||
if (updateTask != null) {
|
|
||||||
updateTask.cancel(true);
|
|
||||||
updateTask = null;
|
|
||||||
}
|
|
||||||
updateTask = getNewUpdateTask();
|
|
||||||
updateTask.stateProperty().addListener((Observable observable) -> {
|
|
||||||
switch (updateTask.getState()) {
|
|
||||||
case CANCELLED:
|
|
||||||
case FAILED:
|
|
||||||
case READY:
|
|
||||||
case RUNNING:
|
|
||||||
case SCHEDULED:
|
|
||||||
break;
|
|
||||||
case SUCCEEDED:
|
|
||||||
try {
|
|
||||||
this.hasVisibleEvents.set(updateTask.get());
|
|
||||||
} catch (InterruptedException | ExecutionException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Unexpected exception updating visualization", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
controller.monitorTask(updateTask);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle a RefreshRequestedEvent from the events model by updating the
|
|
||||||
* visualization.
|
|
||||||
*
|
|
||||||
* @param event The RefreshRequestedEvent to handle.
|
|
||||||
*/
|
|
||||||
@Subscribe
|
|
||||||
public void handleRefreshRequested(RefreshRequestedEvent event) {
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dispose of this visualization and any resources it holds onto.
|
|
||||||
*/
|
|
||||||
final synchronized void dispose() {
|
|
||||||
|
|
||||||
//cancel and gc updateTask
|
|
||||||
if (updateTask != null) {
|
|
||||||
updateTask.cancel(true);
|
|
||||||
updateTask = null;
|
|
||||||
}
|
|
||||||
//remvoe and gc updateListener
|
|
||||||
this.filteredEvents.zoomParametersProperty().removeListener(updateListener);
|
|
||||||
TimeLineController.getTimeZone().removeListener(updateListener);
|
|
||||||
updateListener = null;
|
|
||||||
|
|
||||||
filteredEvents.unRegisterForEvents(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a series for each event type in a consistent order.
|
* Make a series for each event type in a consistent order.
|
||||||
*/
|
*/
|
||||||
@ -470,23 +250,8 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
*
|
*
|
||||||
* @param controller The TimelineController for this visualization.
|
* @param controller The TimelineController for this visualization.
|
||||||
*/
|
*/
|
||||||
protected AbstractVisualizationPane(TimeLineController controller) {
|
protected AbstractTimelineChart(TimeLineController controller) {
|
||||||
this.controller = controller;
|
super(controller);
|
||||||
this.filteredEvents = controller.getEventsModel();
|
|
||||||
this.filteredEvents.registerForEvents(this);
|
|
||||||
this.filteredEvents.zoomParametersProperty().addListener(updateListener);
|
|
||||||
// Platform.runLater(() -> {
|
|
||||||
// VBox vBox = new VBox(specificLabelPane, contextLabelPane);
|
|
||||||
// vBox.setFillWidth(false);
|
|
||||||
// HBox hBox = new HBox(spacer, vBox);
|
|
||||||
// hBox.setFillHeight(false);
|
|
||||||
// setBottom(hBox);
|
|
||||||
// DoubleBinding spacerSize = getYAxis().widthProperty().add(getYAxis().tickLengthProperty()).add(getAxisMargin());
|
|
||||||
// spacer.minWidthProperty().bind(spacerSize);
|
|
||||||
// spacer.prefWidthProperty().bind(spacerSize);
|
|
||||||
// spacer.maxWidthProperty().bind(spacerSize);
|
|
||||||
// });
|
|
||||||
|
|
||||||
createSeries();
|
createSeries();
|
||||||
|
|
||||||
selectedNodes.addListener((ListChangeListener.Change<? extends NodeType> change) -> {
|
selectedNodes.addListener((ListChangeListener.Change<? extends NodeType> change) -> {
|
||||||
@ -496,10 +261,8 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
TimeLineController.getTimeZone().addListener(updateListener);
|
|
||||||
|
|
||||||
//show tooltip text in status bar
|
//show tooltip text in status bar
|
||||||
hoverProperty().addListener(hoverProp -> controller.setStatusMessage(isHover() ? DEFAULT_TOOLTIP.getText() : ""));
|
hoverProperty().addListener(hoverProp -> controller.setStatusMessage(isHover() ? getDefaultTooltip().getText() : ""));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,116 +453,4 @@ public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node, Cha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for Tasks that refresh a visualization when the view settings
|
|
||||||
* change.
|
|
||||||
*
|
|
||||||
* @param <AxisValuesType> The type of a single object that can represent
|
|
||||||
* the range of data displayed along the X-Axis.
|
|
||||||
*/
|
|
||||||
abstract protected class VisualizationRefreshTask<AxisValuesType> extends LoggedTask<Boolean> {
|
|
||||||
|
|
||||||
private final Node center;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param taskName The name of this task.
|
|
||||||
* @param logStateChanges Whether or not task state changes should be
|
|
||||||
* logged.
|
|
||||||
*/
|
|
||||||
protected VisualizationRefreshTask(String taskName, boolean logStateChanges) {
|
|
||||||
super(taskName, logStateChanges);
|
|
||||||
this.center = getCenter();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets initial progress value and message and shows blocking progress
|
|
||||||
* indicator over the visualization. Derived Tasks should be sure to
|
|
||||||
* call this as part of their call() implementation.
|
|
||||||
*
|
|
||||||
* @return True
|
|
||||||
*
|
|
||||||
* @throws Exception If there is an unhandled exception during the
|
|
||||||
* background operation
|
|
||||||
*/
|
|
||||||
@NbBundle.Messages({"VisualizationUpdateTask.preparing=Analyzing zoom and filter settings"})
|
|
||||||
@Override
|
|
||||||
protected Boolean call() throws Exception {
|
|
||||||
updateProgress(-1, 1);
|
|
||||||
updateMessage(Bundle.VisualizationUpdateTask_preparing());
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
MaskerPane maskerPane = new MaskerPane();
|
|
||||||
maskerPane.textProperty().bind(messageProperty());
|
|
||||||
maskerPane.progressProperty().bind(progressProperty());
|
|
||||||
setCenter(new StackPane(center, maskerPane));
|
|
||||||
setCursor(Cursor.WAIT);
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the horizontal axis and removes the blocking progress
|
|
||||||
* indicator. Derived Tasks should be sure to call this as part of their
|
|
||||||
* succeeded() implementation.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void succeeded() {
|
|
||||||
super.succeeded();
|
|
||||||
outOfDate.set(false);
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the blocking progress indicator. Derived Tasks should be sure
|
|
||||||
* to call this as part of their cancelled() implementation.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void cancelled() {
|
|
||||||
super.cancelled();
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the blocking progress indicator. Derived Tasks should be sure
|
|
||||||
* to call this as part of their failed() implementation.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void failed() {
|
|
||||||
super.failed();
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the blocking progress indicator and reset the cursor to the
|
|
||||||
* default.
|
|
||||||
*/
|
|
||||||
private void cleanup() {
|
|
||||||
setCenter(center); //clear masker pane installed in call()
|
|
||||||
setCursor(Cursor.DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the chart data and sets the horizontal axis range. For use
|
|
||||||
* within the derived implementation of the call() method.
|
|
||||||
*
|
|
||||||
* @param axisValues
|
|
||||||
*/
|
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.NOT_UI)
|
|
||||||
protected void resetChart(AxisValuesType axisValues) {
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
clearChartData();
|
|
||||||
setDateAxisValues(axisValues);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the horizontal range that this chart will show.
|
|
||||||
*
|
|
||||||
* @param values A single object representing the range that this chart
|
|
||||||
* will show.
|
|
||||||
*/
|
|
||||||
abstract protected void setDateAxisValues(AxisValuesType values);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* To change this license header, choose License Headers in Project Properties.
|
|
||||||
* To change this template file, choose Tools | Templates
|
|
||||||
* and open the template in the editor.
|
|
||||||
*/
|
|
||||||
package org.sleuthkit.autopsy.timeline.ui;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author jmillman
|
|
||||||
*/
|
|
||||||
public interface TimeLineView {
|
|
||||||
|
|
||||||
}
|
|
@ -121,7 +121,7 @@ final public class VisualizationPanel extends BorderPane {
|
|||||||
private LoggedTask<Void> histogramTask;
|
private LoggedTask<Void> histogramTask;
|
||||||
|
|
||||||
private final EventsTree eventsTree;
|
private final EventsTree eventsTree;
|
||||||
private AbstractVisualizationPane<?, ?, ?, ?> visualization;
|
private AbstractTimeLineView visualization;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HBox that contains the histogram bars.
|
* HBox that contains the histogram bars.
|
||||||
@ -580,7 +580,7 @@ final public class VisualizationPanel extends BorderPane {
|
|||||||
* AbstractVislualization for one of the correct type.
|
* AbstractVislualization for one of the correct type.
|
||||||
*/
|
*/
|
||||||
private void syncVisualizationMode() {
|
private void syncVisualizationMode() {
|
||||||
AbstractVisualizationPane<?, ?, ?, ?> vizPane;
|
AbstractTimeLineView vizPane;
|
||||||
VisualizationMode visMode = controller.visualizationModeProperty().get();
|
VisualizationMode visMode = controller.visualizationModeProperty().get();
|
||||||
|
|
||||||
//make new visualization.
|
//make new visualization.
|
||||||
|
@ -60,7 +60,7 @@ import org.sleuthkit.autopsy.timeline.FXMLConstructor;
|
|||||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane;
|
import org.sleuthkit.autopsy.timeline.ui.AbstractTimelineChart;
|
||||||
import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;
|
import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -79,7 +79,7 @@ import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;
|
|||||||
* Platform.runLater(java.lang.Runnable). The FilteredEventsModel should
|
* Platform.runLater(java.lang.Runnable). The FilteredEventsModel should
|
||||||
* encapsulate all need synchronization internally.
|
* encapsulate all need synchronization internally.
|
||||||
*/
|
*/
|
||||||
public class CountsViewPane extends AbstractVisualizationPane<String, Number, Node, EventCountsChart> {
|
public class CountsViewPane extends AbstractTimelineChart<String, Number, Node, EventCountsChart> {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(CountsViewPane.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(CountsViewPane.class.getName());
|
||||||
|
|
||||||
@ -170,7 +170,7 @@ public class CountsViewPane extends AbstractVisualizationPane<String, Number, No
|
|||||||
|
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||||
@Override
|
@Override
|
||||||
protected void clearChartData() {
|
protected void clearData() {
|
||||||
for (XYChart.Series<String, Number> series : dataSeries) {
|
for (XYChart.Series<String, Number> series : dataSeries) {
|
||||||
series.getData().clear();
|
series.getData().clear();
|
||||||
}
|
}
|
||||||
@ -349,7 +349,7 @@ public class CountsViewPane extends AbstractVisualizationPane<String, Number, No
|
|||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"CountsViewPane.loggedTask.name=Updating Counts View",
|
"CountsViewPane.loggedTask.name=Updating Counts View",
|
||||||
"CountsViewPane.loggedTask.updatingCounts=Populating visualization"})
|
"CountsViewPane.loggedTask.updatingCounts=Populating visualization"})
|
||||||
private class CountsUpdateTask extends VisualizationRefreshTask<List<String>> {
|
private class CountsUpdateTask extends ViewRefreshTask<List<String>> {
|
||||||
|
|
||||||
CountsUpdateTask() {
|
CountsUpdateTask() {
|
||||||
super(Bundle.CountsViewPane_loggedTask_name(), true);
|
super(Bundle.CountsViewPane_loggedTask_name(), true);
|
||||||
@ -374,7 +374,7 @@ public class CountsViewPane extends AbstractVisualizationPane<String, Number, No
|
|||||||
List<Interval> intervals = rangeInfo.getIntervals();
|
List<Interval> intervals = rangeInfo.getIntervals();
|
||||||
|
|
||||||
//clear old data, and reset ranges and series
|
//clear old data, and reset ranges and series
|
||||||
resetChart(Lists.transform(intervals, rangeInfo::formatForTick));
|
resetView(Lists.transform(intervals, rangeInfo::formatForTick));
|
||||||
|
|
||||||
updateMessage(Bundle.CountsViewPane_loggedTask_updatingCounts());
|
updateMessage(Bundle.CountsViewPane_loggedTask_updatingCounts());
|
||||||
int chartMax = 0;
|
int chartMax = 0;
|
||||||
@ -432,7 +432,7 @@ public class CountsViewPane extends AbstractVisualizationPane<String, Number, No
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setDateAxisValues(List<String> categories) {
|
protected void setDateValues(List<String> categories) {
|
||||||
dateAxis.getCategories().setAll(categories);
|
dateAxis.getCategories().setAll(categories);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ import org.sleuthkit.autopsy.timeline.TimeLineController;
|
|||||||
import org.sleuthkit.autopsy.timeline.datamodel.EventStripe;
|
import org.sleuthkit.autopsy.timeline.datamodel.EventStripe;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent;
|
import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane;
|
import org.sleuthkit.autopsy.timeline.ui.AbstractTimelineChart;
|
||||||
import org.sleuthkit.autopsy.timeline.utils.MappedList;
|
import org.sleuthkit.autopsy.timeline.utils.MappedList;
|
||||||
import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD;
|
import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD;
|
||||||
import org.sleuthkit.autopsy.timeline.zooming.ZoomParams;
|
import org.sleuthkit.autopsy.timeline.zooming.ZoomParams;
|
||||||
@ -75,7 +75,7 @@ import org.sleuthkit.autopsy.timeline.zooming.ZoomParams;
|
|||||||
* grouped EventStripes, etc, etc. The leaves of the trees are EventClusters or
|
* grouped EventStripes, etc, etc. The leaves of the trees are EventClusters or
|
||||||
* SingleEvents.
|
* SingleEvents.
|
||||||
*/
|
*/
|
||||||
public class DetailViewPane extends AbstractVisualizationPane<DateTime, EventStripe, EventNodeBase<?>, DetailsChart> {
|
public class DetailViewPane extends AbstractTimelineChart<DateTime, EventStripe, EventNodeBase<?>, DetailsChart> {
|
||||||
|
|
||||||
private final static Logger LOGGER = Logger.getLogger(DetailViewPane.class.getName());
|
private final static Logger LOGGER = Logger.getLogger(DetailViewPane.class.getName());
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ public class DetailViewPane extends AbstractVisualizationPane<DateTime, EventStr
|
|||||||
|
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||||
@Override
|
@Override
|
||||||
protected void clearChartData() {
|
protected void clearData() {
|
||||||
getChart().reset();
|
getChart().reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,9 +365,8 @@ public class DetailViewPane extends AbstractVisualizationPane<DateTime, EventStr
|
|||||||
"DetailViewPane.loggedTask.continueButton=Continue",
|
"DetailViewPane.loggedTask.continueButton=Continue",
|
||||||
"DetailViewPane.loggedTask.backButton=Back (Cancel)",
|
"DetailViewPane.loggedTask.backButton=Back (Cancel)",
|
||||||
"# {0} - number of events",
|
"# {0} - number of events",
|
||||||
|
|
||||||
"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?"})
|
"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?"})
|
||||||
private class DetailsUpdateTask extends VisualizationRefreshTask<Interval> {
|
private class DetailsUpdateTask extends ViewRefreshTask<Interval> {
|
||||||
|
|
||||||
DetailsUpdateTask() {
|
DetailsUpdateTask() {
|
||||||
super(Bundle.DetailViewPane_loggedTask_name(), true);
|
super(Bundle.DetailViewPane_loggedTask_name(), true);
|
||||||
@ -423,7 +422,7 @@ public class DetailViewPane extends AbstractVisualizationPane<DateTime, EventStr
|
|||||||
currentZoomParams = newZoomParams;
|
currentZoomParams = newZoomParams;
|
||||||
|
|
||||||
//clear the chart and set the horixontal axis
|
//clear the chart and set the horixontal axis
|
||||||
resetChart(eventsModel.getTimeRange());
|
resetView(eventsModel.getTimeRange());
|
||||||
|
|
||||||
updateMessage(Bundle.DetailViewPane_loggedTask_updateUI());
|
updateMessage(Bundle.DetailViewPane_loggedTask_updateUI());
|
||||||
|
|
||||||
@ -447,7 +446,7 @@ public class DetailViewPane extends AbstractVisualizationPane<DateTime, EventStr
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setDateAxisValues(Interval timeRange) {
|
protected void setDateValues(Interval timeRange) {
|
||||||
detailsChartDateAxis.setRange(timeRange, true);
|
detailsChartDateAxis.setRange(timeRange, true);
|
||||||
pinnedDateAxis.setRange(timeRange, true);
|
pinnedDateAxis.setRange(timeRange, true);
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import javafx.scene.control.ContextMenu;
|
|||||||
import javafx.scene.control.Control;
|
import javafx.scene.control.Control;
|
||||||
import javafx.scene.control.Skin;
|
import javafx.scene.control.Skin;
|
||||||
import javafx.scene.control.SkinBase;
|
import javafx.scene.control.SkinBase;
|
||||||
|
import javafx.scene.control.Tooltip;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
@ -216,6 +217,10 @@ final class DetailsChart extends Control implements TimeLineChart<DateTime> {
|
|||||||
return nestedEvents;
|
return nestedEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tooltip getDefaultTooltip() {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear any time based UI elements (GuideLines, IntervalSelector,...) from
|
* Clear any time based UI elements (GuideLines, IntervalSelector,...) from
|
||||||
* this chart.
|
* this chart.
|
||||||
|
@ -58,7 +58,7 @@ import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent;
|
|||||||
import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent;
|
import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent;
|
||||||
import org.sleuthkit.autopsy.timeline.filters.AbstractFilter;
|
import org.sleuthkit.autopsy.timeline.filters.AbstractFilter;
|
||||||
import org.sleuthkit.autopsy.timeline.filters.DescriptionFilter;
|
import org.sleuthkit.autopsy.timeline.filters.DescriptionFilter;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane;
|
import org.sleuthkit.autopsy.timeline.ui.AbstractTimelineChart;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.ContextMenuProvider;
|
import org.sleuthkit.autopsy.timeline.ui.ContextMenuProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,7 +178,7 @@ abstract class DetailsChartLane<Y extends TimeLineEvent> extends XYChart<DateTim
|
|||||||
//add a dummy series or the chart is never rendered
|
//add a dummy series or the chart is never rendered
|
||||||
setData(FXCollections.observableList(Arrays.asList(new Series<DateTime, Y>())));
|
setData(FXCollections.observableList(Arrays.asList(new Series<DateTime, Y>())));
|
||||||
|
|
||||||
Tooltip.install(this, AbstractVisualizationPane.getDefaultTooltip());
|
Tooltip.install(this, AbstractTimelineChart.getDefaultTooltip());
|
||||||
|
|
||||||
dateAxis.setAutoRanging(false);
|
dateAxis.setAutoRanging(false);
|
||||||
setLegendVisible(false);
|
setLegendVisible(false);
|
||||||
|
@ -77,7 +77,7 @@ import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent;
|
|||||||
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
||||||
import org.sleuthkit.autopsy.timeline.events.TagsAddedEvent;
|
import org.sleuthkit.autopsy.timeline.events.TagsAddedEvent;
|
||||||
import org.sleuthkit.autopsy.timeline.events.TagsDeletedEvent;
|
import org.sleuthkit.autopsy.timeline.events.TagsDeletedEvent;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane;
|
import org.sleuthkit.autopsy.timeline.ui.AbstractTimelineChart;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.ContextMenuProvider;
|
import org.sleuthkit.autopsy.timeline.ui.ContextMenuProvider;
|
||||||
import static org.sleuthkit.autopsy.timeline.ui.detailview.EventNodeBase.show;
|
import static org.sleuthkit.autopsy.timeline.ui.detailview.EventNodeBase.show;
|
||||||
import static org.sleuthkit.autopsy.timeline.ui.detailview.MultiEventNodeBase.CORNER_RADII_3;
|
import static org.sleuthkit.autopsy.timeline.ui.detailview.MultiEventNodeBase.CORNER_RADII_3;
|
||||||
@ -167,7 +167,7 @@ public abstract class EventNodeBase<Type extends TimeLineEvent> extends StackPan
|
|||||||
|
|
||||||
//set up mouse hover effect and tooltip
|
//set up mouse hover effect and tooltip
|
||||||
setOnMouseEntered(mouseEntered -> {
|
setOnMouseEntered(mouseEntered -> {
|
||||||
Tooltip.uninstall(chartLane, AbstractVisualizationPane.getDefaultTooltip());
|
Tooltip.uninstall(chartLane, AbstractTimelineChart.getDefaultTooltip());
|
||||||
showHoverControls(true);
|
showHoverControls(true);
|
||||||
toFront();
|
toFront();
|
||||||
});
|
});
|
||||||
@ -176,7 +176,7 @@ public abstract class EventNodeBase<Type extends TimeLineEvent> extends StackPan
|
|||||||
if (parentNode != null) {
|
if (parentNode != null) {
|
||||||
parentNode.showHoverControls(true);
|
parentNode.showHoverControls(true);
|
||||||
} else {
|
} else {
|
||||||
Tooltip.install(chartLane, AbstractVisualizationPane.getDefaultTooltip());
|
Tooltip.install(chartLane, AbstractTimelineChart.getDefaultTooltip());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setOnMouseClicked(new ClickHandler());
|
setOnMouseClicked(new ClickHandler());
|
||||||
|
@ -25,7 +25,6 @@ import javafx.scene.shape.Line;
|
|||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclass of {@link Line} with appropriate behavior (mouse listeners) to act
|
* Subclass of {@link Line} with appropriate behavior (mouse listeners) to act
|
||||||
@ -35,7 +34,7 @@ import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane;
|
|||||||
"GuideLine.tooltip.text={0}\nRight-click to remove.\nDrag to reposition."})
|
"GuideLine.tooltip.text={0}\nRight-click to remove.\nDrag to reposition."})
|
||||||
class GuideLine extends Line {
|
class GuideLine extends Line {
|
||||||
|
|
||||||
private static final Tooltip CHART_DEFAULT_TOOLTIP = AbstractVisualizationPane.getDefaultTooltip();
|
private final Tooltip CHART_DEFAULT_TOOLTIP ;
|
||||||
|
|
||||||
private final Tooltip tooltip = new Tooltip();
|
private final Tooltip tooltip = new Tooltip();
|
||||||
private final DetailsChart chart;
|
private final DetailsChart chart;
|
||||||
@ -49,6 +48,7 @@ class GuideLine extends Line {
|
|||||||
*/
|
*/
|
||||||
GuideLine(DetailsChart chart) {
|
GuideLine(DetailsChart chart) {
|
||||||
super(0, 0, 0, 0);
|
super(0, 0, 0, 0);
|
||||||
|
CHART_DEFAULT_TOOLTIP = chart.getDefaultTooltip();
|
||||||
this.chart = chart;
|
this.chart = chart;
|
||||||
Axis<DateTime> xAxis = chart.getXAxis();
|
Axis<DateTime> xAxis = chart.getXAxis();
|
||||||
endYProperty().bind(chart.heightProperty().subtract(xAxis.heightProperty().subtract(xAxis.tickLengthProperty())));
|
endYProperty().bind(chart.heightProperty().subtract(xAxis.heightProperty().subtract(xAxis.tickLengthProperty())));
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.timeline.ui.listvew;
|
package org.sleuthkit.autopsy.timeline.ui.listvew;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Collection;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
@ -43,16 +43,30 @@ class ListChart extends BorderPane implements TimeLineChart<Long> {
|
|||||||
@FXML
|
@FXML
|
||||||
private TableView<Long> table;
|
private TableView<Long> table;
|
||||||
|
|
||||||
Callback<TableColumn.CellDataFeatures<Long, Long>, ObservableValue<Long>> cellValueFactory = param -> new SimpleObjectProperty<>(param.getValue());
|
private static final Callback<TableColumn.CellDataFeatures<Long, Long>, ObservableValue<Long>> CELL_VALUE_FACTORY = param -> new SimpleObjectProperty<>(param.getValue());
|
||||||
|
|
||||||
private final TimeLineController controller;
|
private final TimeLineController controller;
|
||||||
private final TableColumn<Long, Long> idColumn = new TableColumn<>("Event ID");
|
|
||||||
private final TableColumn<Long, Long> millisColumn = new TableColumn<>("Date/Time");
|
@FXML
|
||||||
private final TableColumn<Long, Long> iconColumn = new TableColumn<>("Icon");
|
private TableColumn<Long, Long> idColumn;
|
||||||
private final TableColumn<Long, Long> descriptionColumn = new TableColumn<>("Description");
|
|
||||||
private final TableColumn<Long, Long> baseTypeColumn = new TableColumn<>("Base Type");
|
@FXML
|
||||||
private final TableColumn<Long, Long> subTypeColumn = new TableColumn<>("Sub Type");
|
private TableColumn<Long, Long> millisColumn;
|
||||||
private final TableColumn<Long, Long> knownColumn = new TableColumn<>("Known");
|
|
||||||
|
@FXML
|
||||||
|
private TableColumn<Long, Long> iconColumn;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TableColumn<Long, Long> descriptionColumn;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TableColumn<Long, Long> baseTypeColumn;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TableColumn<Long, Long> subTypeColumn;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TableColumn<Long, Long> knownColumn;
|
||||||
|
|
||||||
ListChart(TimeLineController controller) {
|
ListChart(TimeLineController controller) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
@ -71,26 +85,27 @@ class ListChart extends BorderPane implements TimeLineChart<Long> {
|
|||||||
assert subTypeColumn != null : "fx:id=\"subTypeColumn\" was not injected: check your FXML file 'ListViewPane.fxml'.";
|
assert subTypeColumn != null : "fx:id=\"subTypeColumn\" was not injected: check your FXML file 'ListViewPane.fxml'.";
|
||||||
assert knownColumn != null : "fx:id=\"knownColumn\" was not injected: check your FXML file 'ListViewPane.fxml'.";
|
assert knownColumn != null : "fx:id=\"knownColumn\" was not injected: check your FXML file 'ListViewPane.fxml'.";
|
||||||
|
|
||||||
// setRowFactory(tableView -> new EventRow());
|
table.setRowFactory(tableView -> new EventRow());
|
||||||
idColumn.setCellValueFactory(cellValueFactory);
|
idColumn.setCellValueFactory(CELL_VALUE_FACTORY);
|
||||||
|
|
||||||
millisColumn.setCellValueFactory(cellValueFactory);
|
millisColumn.setCellValueFactory(CELL_VALUE_FACTORY);
|
||||||
millisColumn.setCellFactory(col -> new EpochMillisCell());
|
millisColumn.setCellFactory(col -> new EpochMillisCell());
|
||||||
|
|
||||||
iconColumn.setCellValueFactory(cellValueFactory);
|
iconColumn.setCellValueFactory(CELL_VALUE_FACTORY);
|
||||||
iconColumn.setCellFactory(col -> new ImageCell());
|
iconColumn.setCellFactory(col -> new ImageCell());
|
||||||
|
|
||||||
descriptionColumn.setCellValueFactory(cellValueFactory);
|
descriptionColumn.setCellValueFactory(CELL_VALUE_FACTORY);
|
||||||
descriptionColumn.setCellFactory(col -> new DescriptionCell());
|
descriptionColumn.setCellFactory(col -> new DescriptionCell());
|
||||||
|
|
||||||
baseTypeColumn.setCellValueFactory(cellValueFactory);
|
baseTypeColumn.setCellValueFactory(CELL_VALUE_FACTORY);
|
||||||
baseTypeColumn.setCellFactory(col -> new BaseTypeCell());
|
baseTypeColumn.setCellFactory(col -> new BaseTypeCell());
|
||||||
|
|
||||||
subTypeColumn.setCellValueFactory(cellValueFactory);
|
subTypeColumn.setCellValueFactory(CELL_VALUE_FACTORY);
|
||||||
subTypeColumn.setCellFactory(col -> new EventTypeCell());
|
subTypeColumn.setCellFactory(col -> new EventTypeCell());
|
||||||
|
|
||||||
knownColumn.setCellValueFactory(cellValueFactory);
|
knownColumn.setCellValueFactory(CELL_VALUE_FACTORY);
|
||||||
knownColumn.setCellFactory(col -> new KnownCell());
|
knownColumn.setCellFactory(col -> new KnownCell());
|
||||||
|
|
||||||
eventCountLabel.textProperty().bind(Bindings.size(table.getItems()).asString().concat(" events"));
|
eventCountLabel.textProperty().bind(Bindings.size(table.getItems()).asString().concat(" events"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +161,7 @@ class ListChart extends BorderPane implements TimeLineChart<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||||
void setEventIDs(List<Long> eventIDs) {
|
void setEventIDs(Collection<Long> eventIDs) {
|
||||||
table.getItems().setAll(eventIDs);
|
table.getItems().setAll(eventIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<?import javafx.scene.layout.HBox?>
|
<?import javafx.scene.layout.HBox?>
|
||||||
<?import javafx.scene.layout.Region?>
|
<?import javafx.scene.layout.Region?>
|
||||||
|
|
||||||
<fx:root maxHeight="-Infinity" minHeight="-Infinity" minWidth="-Infinity" type="BorderPane" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
|
<fx:root type="BorderPane" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
|
||||||
<top>
|
<top>
|
||||||
<HBox alignment="CENTER" BorderPane.alignment="CENTER">
|
<HBox alignment="CENTER" BorderPane.alignment="CENTER">
|
||||||
<children>
|
<children>
|
||||||
@ -23,13 +23,13 @@
|
|||||||
<center>
|
<center>
|
||||||
<TableView fx:id="table" tableMenuButtonVisible="true" BorderPane.alignment="CENTER">
|
<TableView fx:id="table" tableMenuButtonVisible="true" BorderPane.alignment="CENTER">
|
||||||
<columns>
|
<columns>
|
||||||
<TableColumn fx:id="idColumn" editable="false" maxWidth="200.0" prefWidth="75.0" sortable="false" text="ID" />
|
<TableColumn fx:id="millisColumn" editable="false" maxWidth="200.0" minWidth="150.0" prefWidth="150.0" resizable="false" sortable="false" text="Date/Time" />
|
||||||
<TableColumn fx:id="millisColumn" editable="false" maxWidth="300.0" minWidth="150.0" prefWidth="300.0" resizable="false" sortable="false" text="Date/Time" />
|
|
||||||
<TableColumn fx:id="iconColumn" editable="false" maxWidth="36.0" minWidth="36.0" prefWidth="36.0" resizable="false" sortable="false" text="Icon" />
|
<TableColumn fx:id="iconColumn" editable="false" maxWidth="36.0" minWidth="36.0" prefWidth="36.0" resizable="false" sortable="false" text="Icon" />
|
||||||
<TableColumn fx:id="descriptionColumn" editable="false" maxWidth="1000.0" minWidth="100.0" prefWidth="200.0" sortable="false" text="Description" />
|
<TableColumn fx:id="descriptionColumn" editable="false" maxWidth="1000.0" minWidth="100.0" prefWidth="300.0" sortable="false" text="Description" />
|
||||||
<TableColumn fx:id="baseTypeColumn" editable="false" maxWidth="75.0" minWidth="75.0" prefWidth="75.0" sortable="false" text="BaseType" />
|
<TableColumn fx:id="baseTypeColumn" editable="false" maxWidth="75.0" minWidth="75.0" prefWidth="75.0" sortable="false" text="BaseType" />
|
||||||
<TableColumn fx:id="subTypeColumn" editable="false" maxWidth="75.0" minWidth="75.0" prefWidth="75.0" sortable="false" text="SubType" />
|
<TableColumn fx:id="subTypeColumn" editable="false" maxWidth="100.0" minWidth="100.0" prefWidth="100.0" sortable="false" text="SubType" />
|
||||||
<TableColumn fx:id="knownColumn" editable="false" maxWidth="100.0" minWidth="75.0" prefWidth="75.0" sortable="false" text="Known" />
|
<TableColumn fx:id="knownColumn" editable="false" maxWidth="75.0" minWidth="75.0" prefWidth="75.0" sortable="false" text="Known" />
|
||||||
|
<TableColumn fx:id="idColumn" editable="false" maxWidth="150.0" minWidth="50.0" prefWidth="75.0" sortable="false" text="ID" />
|
||||||
</columns>
|
</columns>
|
||||||
<columnResizePolicy>
|
<columnResizePolicy>
|
||||||
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
|
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
|
||||||
|
@ -8,15 +8,11 @@ package org.sleuthkit.autopsy.timeline.ui.listvew;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.scene.Node;
|
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
import javafx.scene.chart.Axis;
|
|
||||||
import org.joda.time.Interval;
|
import org.joda.time.Interval;
|
||||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent;
|
import org.sleuthkit.autopsy.timeline.ui.AbstractTimeLineView;
|
||||||
import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane;
|
|
||||||
import org.sleuthkit.autopsy.timeline.ui.TimeLineView;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param <X> The type of data plotted along the x axis
|
* @param <X> The type of data plotted along the x axis
|
||||||
@ -33,7 +29,9 @@ import org.sleuthkit.autopsy.timeline.ui.TimeLineView;
|
|||||||
* public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node,
|
* public abstract class AbstractVisualizationPane<X, Y, NodeType extends Node,
|
||||||
* ChartType extends Region & TimeLineChart<X>> extends BorderPane {
|
* ChartType extends Region & TimeLineChart<X>> extends BorderPane {
|
||||||
*/
|
*/
|
||||||
public class ListViewPane extends AbstractVisualizationPane<Long, SingleEvent, Node, ListChart> implements TimeLineView {
|
public class ListViewPane extends AbstractTimeLineView {
|
||||||
|
|
||||||
|
private final ListChart listChart;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -42,55 +40,21 @@ public class ListViewPane extends AbstractVisualizationPane<Long, SingleEvent, N
|
|||||||
*/
|
*/
|
||||||
public ListViewPane(TimeLineController controller) {
|
public ListViewPane(TimeLineController controller) {
|
||||||
super(controller);
|
super(controller);
|
||||||
|
listChart = new ListChart(controller);
|
||||||
|
|
||||||
//initialize chart;
|
//initialize chart;
|
||||||
setChart(new ListChart(controller));
|
setCenter(listChart);
|
||||||
setSettingsNodes(new ListViewPane.ListViewSettingsPane().getChildrenUnmodifiable());
|
setSettingsNodes(new ListViewPane.ListViewSettingsPane().getChildrenUnmodifiable());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Boolean isTickBold(Long value) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applySelectionEffect(Node node, Boolean applied) {
|
|
||||||
// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Task<Boolean> getNewUpdateTask() {
|
protected Task<Boolean> getNewUpdateTask() {
|
||||||
return new ListUpdateTask();
|
return new ListUpdateTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getTickMarkLabel(Long tickValue) {
|
protected void clearData() {
|
||||||
return "";
|
listChart.clear();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected double getTickSpacing() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Axis<Long> getXAxis() {
|
|
||||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Axis<SingleEvent> getYAxis() {
|
|
||||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected double getAxisMargin() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void clearChartData() {
|
|
||||||
getChart().clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ListViewSettingsPane extends Parent {
|
private static class ListViewSettingsPane extends Parent {
|
||||||
@ -99,7 +63,7 @@ public class ListViewPane extends AbstractVisualizationPane<Long, SingleEvent, N
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ListUpdateTask extends VisualizationRefreshTask<Interval> {
|
private class ListUpdateTask extends ViewRefreshTask<Interval> {
|
||||||
|
|
||||||
ListUpdateTask() {
|
ListUpdateTask() {
|
||||||
super("List update task", true);
|
super("List update task", true);
|
||||||
@ -114,12 +78,12 @@ public class ListViewPane extends AbstractVisualizationPane<Long, SingleEvent, N
|
|||||||
FilteredEventsModel eventsModel = getEventsModel();
|
FilteredEventsModel eventsModel = getEventsModel();
|
||||||
|
|
||||||
//clear the chart and set the horixontal axis
|
//clear the chart and set the horixontal axis
|
||||||
resetChart(eventsModel.getTimeRange());
|
resetView(eventsModel.getTimeRange());
|
||||||
|
|
||||||
updateMessage("Querying db for events");
|
updateMessage("Querying db for events");
|
||||||
//get the event stripes to be displayed
|
//get the event stripes to be displayed
|
||||||
List<Long> eventIDs = eventsModel.getEventIDs();
|
List<Long> eventIDs = eventsModel.getEventIDs();
|
||||||
Platform.runLater(() -> getChart().setEventIDs(eventIDs));
|
Platform.runLater(() -> listChart.setEventIDs(eventIDs));
|
||||||
|
|
||||||
updateMessage("updating ui");
|
updateMessage("updating ui");
|
||||||
return eventIDs.isEmpty() == false;
|
return eventIDs.isEmpty() == false;
|
||||||
@ -132,9 +96,8 @@ public class ListViewPane extends AbstractVisualizationPane<Long, SingleEvent, N
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setDateAxisValues(Interval timeRange) {
|
protected void setDateValues(Interval timeRange) {
|
||||||
// detailsChartDateAxis.setRange(timeRange, true);
|
|
||||||
// pinnedDateAxis.setRange(timeRange, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user