From 2eb50ba784f9d06233164737e9f23c9a40f4b19d Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 28 Apr 2016 16:53:22 -0400 Subject: [PATCH 1/3] begin moving axis nodes into AbstractVisualizationPane.java --- .../ui/AbstractVisualizationPane.java | 23 +++++++++----- .../timeline/ui/VisualizationPanel.java | 16 +++------- .../ui/countsview/CountsViewPane.java | 31 +++++++------------ .../ui/detailview/DetailViewPane.java | 20 ++++++------ 4 files changed, 41 insertions(+), 49 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java index ef29b563af..eddb04f56c 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java @@ -29,6 +29,7 @@ import java.util.logging.Level; import javafx.application.Platform; import javafx.beans.InvalidationListener; import javafx.beans.Observable; +import javafx.beans.binding.DoubleBinding; import javafx.beans.property.SimpleBooleanProperty; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; @@ -46,9 +47,11 @@ import javafx.scene.control.OverrunStyle; import javafx.scene.control.Tooltip; import javafx.scene.effect.Effect; import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.scene.text.Text; @@ -101,9 +104,9 @@ public abstract class AbstractVisualizationPane { + setBottom(new HBox(spacer, new VBox(leafPane, branchPane))); + DoubleBinding spacerSize = getYAxis().widthProperty().add(getYAxis().tickLengthProperty()).add(getAxisMargin());//getXAxis().startMarginProperty().multiply(2)); + spacer.minWidthProperty().bind(spacerSize); + spacer.prefWidthProperty().bind(spacerSize); + spacer.maxWidthProperty().bind(spacerSize); + }); createSeries(); @@ -444,6 +451,8 @@ public abstract class AbstractVisualizationPane sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -51,7 +51,6 @@ import javafx.scene.layout.BackgroundFill; import javafx.scene.layout.BorderPane; import javafx.scene.layout.CornerRadii; import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import static javafx.scene.layout.Region.USE_PREF_SIZE; @@ -141,14 +140,7 @@ final public class VisualizationPanel extends BorderPane { @FXML private Label endLabel; - //// replacemetn axis label componenets - @FXML - private Pane partPane; - @FXML - private Pane contextPane; - @FXML - private Region spacer; - + //// header toolbar componenets @FXML private ToolBar toolBar; @@ -359,11 +351,11 @@ final public class VisualizationPanel extends BorderPane { private void setViewMode(VisualizationMode visualizationMode) { switch (visualizationMode) { case COUNTS: - setVisualization(new CountsViewPane(controller, partPane, contextPane, spacer)); + setVisualization(new CountsViewPane(controller)); countsToggle.setSelected(true); break; case DETAIL: - setVisualization(new DetailViewPane(controller, partPane, contextPane, spacer)); + setVisualization(new DetailViewPane(controller)); detailsToggle.setSelected(true); break; } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java index 8d37e68e33..cc0f1cb917 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java @@ -40,8 +40,6 @@ import javafx.scene.control.ToggleGroup; import javafx.scene.control.Tooltip; import javafx.scene.effect.Effect; import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; -import javafx.scene.layout.Region; import org.joda.time.Interval; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; @@ -100,8 +98,8 @@ public class CountsViewPane extends AbstractVisualizationPane(new CountsViewSettingsPane().getChildrenUnmodifiable()); - dateAxis.getTickMarks().addListener((Observable observable) -> { - layoutDateLabels(); - }); - dateAxis.categorySpacingProperty().addListener((Observable observable) -> { - layoutDateLabels(); - }); - dateAxis.getCategories().addListener((Observable observable) -> { - layoutDateLabels(); - }); - - spacer.minWidthProperty().bind(countAxis.widthProperty().add(countAxis.tickLengthProperty()).add(dateAxis.startMarginProperty().multiply(2))); - spacer.prefWidthProperty().bind(countAxis.widthProperty().add(countAxis.tickLengthProperty()).add(dateAxis.startMarginProperty().multiply(2))); - spacer.maxWidthProperty().bind(countAxis.widthProperty().add(countAxis.tickLengthProperty()).add(dateAxis.startMarginProperty().multiply(2))); + dateAxis.getTickMarks().addListener((Observable observable) -> layoutDateLabels()); + dateAxis.categorySpacingProperty().addListener((Observable observable) -> layoutDateLabels()); + dateAxis.getCategories().addListener((Observable observable) -> layoutDateLabels()); scale.addListener(o -> { countAxis.tickLabelsVisibleProperty().bind(scale.isEqualTo(ScaleType.LINEAR)); @@ -135,12 +123,12 @@ public class CountsViewPane extends AbstractVisualizationPane(getSelectedNodes(), EventNodeBase::getEvent); //initialize chart; @@ -116,9 +112,6 @@ public class DetailViewPane extends AbstractVisualizationPane layoutDateLabels()); detailsChartDateAxis.getTickSpacing().addListener(observable -> layoutDateLabels()); verticalAxis.setAutoRanging(false); //prevent XYChart.updateAxisRange() from accessing dataSeries on JFX thread causing ConcurrentModificationException - bottomLeftSpacer.minWidthProperty().bind(verticalAxis.widthProperty().add(verticalAxis.tickLengthProperty())); - bottomLeftSpacer.prefWidthProperty().bind(verticalAxis.widthProperty().add(verticalAxis.tickLengthProperty())); - bottomLeftSpacer.maxWidthProperty().bind(verticalAxis.widthProperty().add(verticalAxis.tickLengthProperty())); selectedNodes.addListener((Observable observable) -> { //update selected nodes highlight @@ -175,7 +168,7 @@ public class DetailViewPane extends AbstractVisualizationPane getXAxis() { + final public DateAxis getXAxis() { return detailsChartDateAxis; } @@ -215,7 +208,7 @@ public class DetailViewPane extends AbstractVisualizationPane getYAxis() { + final protected Axis getYAxis() { return verticalAxis; } @@ -244,6 +237,11 @@ public class DetailViewPane extends AbstractVisualizationPane Date: Thu, 28 Apr 2016 17:00:44 -0400 Subject: [PATCH 2/3] fix alignment of axis labels --- .../ui/AbstractVisualizationPane.java | 78 ++++++++++--------- .../timeline/ui/VisualizationPanel.fxml | 36 ++++----- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java index eddb04f56c..6f7ca0220d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java @@ -84,15 +84,15 @@ import org.sleuthkit.autopsy.timeline.events.RefreshRequestedEvent; * common history context menu items out of derived classes? -jm */ public abstract class AbstractVisualizationPane> extends BorderPane { - + @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 Logger LOGGER = Logger.getLogger(AbstractVisualizationPane.class.getName()); - + public static Tooltip getDefaultTooltip() { return DEFAULT_TOOLTIP; } - + protected final SimpleBooleanProperty hasEvents = new SimpleBooleanProperty(true); /** @@ -100,7 +100,7 @@ public abstract class AbstractVisualizationPane> dataSeries = FXCollections.>observableArrayList(); protected final Map> eventTypeToSeriesMap = new HashMap<>(); - + protected ChartType chart; //// replacement axis label componenets @@ -112,17 +112,17 @@ public abstract class AbstractVisualizationPane updateTask; - + final protected TimeLineController controller; - + final protected FilteredEventsModel filteredEvents; - + final protected ObservableList selectedNodes = FXCollections.observableArrayList(); - + private InvalidationListener invalidationListener = (Observable observable) -> { update(); }; - + public ObservableList getSelectedNodes() { return selectedNodes; } @@ -132,7 +132,7 @@ public abstract class AbstractVisualizationPane settingsNodes; - + public TimeLineController getController() { return controller; } @@ -199,7 +199,7 @@ public abstract class AbstractVisualizationPane getYAxis(); - + @ThreadConfined(type = ThreadConfined.ThreadType.JFX) abstract protected void resetData(); @@ -236,7 +236,7 @@ public abstract class AbstractVisualizationPane getSeries(final EventType et) { return eventTypeToSeriesMap.get(et); } - + protected AbstractVisualizationPane(TimeLineController controller) { this.controller = controller; this.filteredEvents = controller.getEventsModel(); this.filteredEvents.registerForEvents(this); this.filteredEvents.zoomParametersProperty().addListener(invalidationListener); Platform.runLater(() -> { - setBottom(new HBox(spacer, new VBox(leafPane, branchPane))); + VBox vBox = new VBox(leafPane, branchPane); + vBox.setFillWidth(false); + HBox hBox = new HBox(spacer, vBox); + hBox.setFillHeight(false); + setBottom(hBox); DoubleBinding spacerSize = getYAxis().widthProperty().add(getYAxis().tickLengthProperty()).add(getAxisMargin());//getXAxis().startMarginProperty().multiply(2)); spacer.minWidthProperty().bind(spacerSize); spacer.prefWidthProperty().bind(spacerSize); spacer.maxWidthProperty().bind(spacerSize); }); - + createSeries(); - + selectedNodes.addListener((ListChangeListener.Change c) -> { while (c.next()) { c.getRemoved().forEach(n -> applySelectionEffect(n, false)); c.getAddedSubList().forEach(n -> applySelectionEffect(n, true)); } }); - + TimeLineController.getTimeZone().addListener(invalidationListener); //show tooltip text in status bar hoverProperty().addListener(observable -> controller.setStatus(isHover() ? DEFAULT_TOOLTIP.getText() : "")); - + } - + @Subscribe public void handleRefreshRequested(RefreshRequestedEvent event) { update(); @@ -328,7 +332,7 @@ public abstract class AbstractVisualizationPane> tickMarks = FXCollections.observableArrayList(getXAxis().getTickMarks()); tickMarks.sort(Comparator.comparing(Axis.TickMark::getPosition)); - + if (tickMarks.isEmpty() == false) { //get the spacing between ticks in the underlying axis double spacing = getTickSpacing(); @@ -340,7 +344,7 @@ public abstract class AbstractVisualizationPane t : tickMarks) { @@ -349,7 +353,7 @@ public abstract class AbstractVisualizationPane t : tickMarks) { //for each tick //split the label into a TwoPartDateTime @@ -398,21 +402,21 @@ public abstract class AbstractVisualizationPane the type of data displayed along the X-Axis. */ abstract protected class VisualizationUpdateTask extends LoggedTask { - + protected VisualizationUpdateTask(String taskName, boolean logStateChanges) { super(taskName, logStateChanges); } @@ -525,7 +529,7 @@ public abstract class AbstractVisualizationPane { setCenter(center); //clear masker pane setCursor(Cursor.DEFAULT); @@ -554,13 +558,13 @@ public abstract class AbstractVisualizationPane { resetData(); setDateAxisValues(axisValues); }); } - + abstract protected void setDateAxisValues(AxisValuesType values); } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.fxml b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.fxml index ac2748668b..09f2e2b0d3 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.fxml +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.fxml @@ -1,15 +1,22 @@ - - - - - - - - + + + + + + + + + + + + + + + - + @@ -78,17 +85,6 @@ - - - - - - - - - - - From d095f447a60635e73d56605ba6456230697c1a1b Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 29 Apr 2016 10:35:00 -0400 Subject: [PATCH 3/3] use newly reorganized scene graph to snapshot only the actual visualization (including axes) --- .../actions/SaveSnapshotAsReport.java | 6 +- .../timeline/ui/VisualizationPanel.fxml | 1 + .../timeline/ui/VisualizationPanel.java | 71 +++++++++---------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java b/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java index aa46f70ed7..e50e1909a8 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/actions/SaveSnapshotAsReport.java @@ -25,6 +25,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.function.Supplier; import java.util.logging.Level; import javafx.embed.swing.SwingFXUtils; import javafx.scene.Node; @@ -81,7 +82,7 @@ public class SaveSnapshotAsReport extends Action { "SaveSnapShotAsReport.reportName.prompt=leave empty for default report name: {0}.", "SaveSnapShotAsReport.reportName.header=Enter a report name for the Timeline Snapshot Report." }) - public SaveSnapshotAsReport(TimeLineController controller, Node node) { + public SaveSnapshotAsReport(TimeLineController controller, Supplier nodeSupplier) { super(Bundle.SaveSnapShotAsReport_action_name_text()); setLongText(Bundle.SaveSnapShotAsReport_action_longText()); setGraphic(new ImageView(SNAP_SHOT)); @@ -93,8 +94,7 @@ public class SaveSnapshotAsReport extends Action { //capture generation date and use to make default report name Date generationDate = new Date(); final String defaultReportName = FileUtil.escapeFileName(currentCase.getName() + " " + new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss").format(generationDate)); //NON_NLS - - BufferedImage snapshot = SwingFXUtils.fromFXImage(node.snapshot(null, null), null); + BufferedImage snapshot = SwingFXUtils.fromFXImage(nodeSupplier.get().snapshot(null, null), null); //prompt user to pick report name TextInputDialog textInputDialog = new TextInputDialog(); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.fxml b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.fxml index 09f2e2b0d3..218aa21c58 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.fxml +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.fxml @@ -15,6 +15,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java index c1f05303ef..207d842d1f 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/VisualizationPanel.java @@ -140,7 +140,6 @@ final public class VisualizationPanel extends BorderPane { @FXML private Label endLabel; - //// header toolbar componenets @FXML private ToolBar toolBar; @@ -280,7 +279,7 @@ final public class VisualizationPanel extends BorderPane { setViewMode(controller.viewModeProperty().get()); //configure snapshor button / action - ActionUtils.configureButton(new SaveSnapshotAsReport(controller, VisualizationPanel.this), snapShotButton); + ActionUtils.configureButton(new SaveSnapshotAsReport(controller, notificationPane::getContent), snapShotButton); /////configure start and end pickers startLabel.setText(Bundle.VisualizationPanel_startLabel_text()); @@ -419,54 +418,54 @@ final public class VisualizationPanel extends BorderPane { histogramTask = new LoggedTask( NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.title"), true) { // NON-NLS - private final Lighting lighting = new Lighting(); + private final Lighting lighting = new Lighting(); @Override protected Void call() throws Exception { - updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.preparing")); // NON-NLS + updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.preparing")); // NON-NLS - long max = 0; - final RangeDivisionInfo rangeInfo = RangeDivisionInfo.getRangeDivisionInfo(filteredEvents.getSpanningInterval()); - final long lowerBound = rangeInfo.getLowerBound(); - final long upperBound = rangeInfo.getUpperBound(); - Interval timeRange = new Interval(new DateTime(lowerBound, TimeLineController.getJodaTimeZone()), new DateTime(upperBound, TimeLineController.getJodaTimeZone())); + long max = 0; + final RangeDivisionInfo rangeInfo = RangeDivisionInfo.getRangeDivisionInfo(filteredEvents.getSpanningInterval()); + final long lowerBound = rangeInfo.getLowerBound(); + final long upperBound = rangeInfo.getUpperBound(); + Interval timeRange = new Interval(new DateTime(lowerBound, TimeLineController.getJodaTimeZone()), new DateTime(upperBound, TimeLineController.getJodaTimeZone())); - //extend range to block bounderies (ie day, month, year) - int p = 0; // progress counter + //extend range to block bounderies (ie day, month, year) + int p = 0; // progress counter - //clear old data, and reset ranges and series - Platform.runLater(() -> { - updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.resetUI")); // NON-NLS + //clear old data, and reset ranges and series + Platform.runLater(() -> { + updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.resetUI")); // NON-NLS - }); + }); - ArrayList bins = new ArrayList<>(); + ArrayList bins = new ArrayList<>(); - DateTime start = timeRange.getStart(); - while (timeRange.contains(start)) { - if (isCancelled()) { - return null; - } - DateTime end = start.plus(rangeInfo.getPeriodSize().getPeriod()); - final Interval interval = new Interval(start, end); - //increment for next iteration + DateTime start = timeRange.getStart(); + while (timeRange.contains(start)) { + if (isCancelled()) { + return null; + } + DateTime end = start.plus(rangeInfo.getPeriodSize().getPeriod()); + final Interval interval = new Interval(start, end); + //increment for next iteration - start = end; + start = end; - updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.queryDb")); // NON-NLS - //query for current range - long count = filteredEvents.getEventCounts(interval).values().stream().mapToLong(Long::valueOf).sum(); - bins.add(count); + updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.queryDb")); // NON-NLS + //query for current range + long count = filteredEvents.getEventCounts(interval).values().stream().mapToLong(Long::valueOf).sum(); + bins.add(count); - max = Math.max(count, max); + max = Math.max(count, max); - final double fMax = Math.log(max); - final ArrayList fbins = new ArrayList<>(bins); - Platform.runLater(() -> { - updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.updateUI2")); // NON-NLS + final double fMax = Math.log(max); + final ArrayList fbins = new ArrayList<>(bins); + Platform.runLater(() -> { + updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.updateUI2")); // NON-NLS - histogramBox.getChildren().clear(); + histogramBox.getChildren().clear(); for (Long bin : fbins) { if (isCancelled()) { @@ -491,7 +490,7 @@ final public class VisualizationPanel extends BorderPane { return null; } - }; + }; new Thread(histogramTask).start(); controller.monitorTask(histogramTask); }