From a23c6d19f8c134f22faa78691d5c6b2cc8bffc2f Mon Sep 17 00:00:00 2001 From: jmillman Date: Fri, 29 Apr 2016 17:04:00 -0400 Subject: [PATCH] add scale to counts y axis label. cleanup in CountsViewPane.java and related code. --- .../ui/AbstractVisualizationPane.java | 60 ++--- .../timeline/ui/countsview/Bundle.properties | 24 -- .../ui/countsview/Bundle_ja.properties | 28 +-- .../ui/countsview/CountsViewPane.java | 207 ++++++++++-------- .../ui/countsview/EventCountsChart.java | 4 +- .../ui/detailview/DetailViewPane.java | 10 +- 6 files changed, 165 insertions(+), 168 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/Bundle.properties diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java index ef29b563af..30fbc0f6f8 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualizationPane.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-15 Basis Technology Corp. + * Copyright 2014-16 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -44,7 +44,6 @@ import javafx.scene.chart.XYChart; import javafx.scene.control.Label; import javafx.scene.control.OverrunStyle; import javafx.scene.control.Tooltip; -import javafx.scene.effect.Effect; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Pane; import javafx.scene.layout.Region; @@ -143,62 +142,70 @@ public abstract class AbstractVisualizationPane getUpdateTask(); /** - * @return return the {@link Effect} applied to 'selected nodes' in this - * visualization, or null if selection is visualized via another - * mechanism - */ - abstract protected Effect getSelectionEffect(); - - /** - * @param tickValue + * Get the label that should be used for a tick mark at the given value. * - * @return a String to use for a tick mark label given a tick value + * @param tickValue The value to get a label for. + * + * @return a String to use for a tick mark label given a tick value. */ abstract protected String getTickMarkLabel(X tickValue); /** - * the spacing (in pixels) between tick marks of the horizontal axis. This - * will be used to layout the decluttered replacement labels. + * Get the spacing, in pixels, between tick marks of the horizontal axis. + * This will be used to layout the decluttered replacement labels. * - * @return the spacing in pixels between tick marks of the horizontal axis + * @return The spacing, in pixels, between tick marks of the horizontal axis */ abstract protected double getTickSpacing(); /** + * Get the X-Axis of this Visualization's chart + * * @return the horizontal axis used by this Visualization's chart */ abstract protected Axis getXAxis(); /** + * Get the Y-Axis of this Visualization's chart + * * @return the vertical axis used by this Visualization's chart */ abstract protected Axis getYAxis(); + /** + * Clear all data items from this chart. + */ @ThreadConfined(type = ThreadConfined.ThreadType.JFX) - abstract protected void resetData(); + abstract protected void clearChartData(); /** * update this visualization based on current state of zoom / filters. @@ -243,7 +250,7 @@ public abstract class AbstractVisualizationPane { - resetData(); + clearChartData(); setDateAxisValues(axisValues); }); } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/Bundle.properties b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/Bundle.properties deleted file mode 100644 index 2b4965f421..0000000000 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/Bundle.properties +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013-15 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#this is the label for the vetical axis -CountsChartPane.numberOfEvents=Number of Events - -CountsViewPane.scaleLabel.text=Scale\: -CountsViewPane.logRadio.text=Logarithmic -CountsViewPane.linearRadio.text=Linear diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/Bundle_ja.properties index 9cbcb05152..e60d46f934 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/Bundle_ja.properties @@ -1,14 +1,14 @@ -CountsChartPane.numberOfEvents=\u30A4\u30D9\u30F3\u30C8\u6570 -CountsViewPane.detailSwitchMessage=\u79D2\u3088\u308A\u5C0F\u3055\u3044\u5358\u4F4D\u306F\u3042\u308A\u307E\u305B\u3093\u3002\n\u8A73\u7D30\u30D3\u30E5\u30FC\u306B\u5909\u66F4\u3057\u307E\u3059\u304B\uFF1F -CountsViewPane.detailSwitchTitle=\u8A73\u7D30\u30D3\u30E5\u30FC\u306B\u5909\u66F4\u3057\u307E\u3059\u304B\uFF1F -Timeline.ui.countsview.menuItem.selectEventType=\u30A4\u30D9\u30F3\u30C8\u30BF\u30A4\u30D7\u3092\u9078\u629E -Timeline.ui.countsview.menuItem.selectTimeandType=\u6642\u9593\u3068\u30BF\u30A4\u30D7\u3092\u9078\u629E -Timeline.ui.countsview.menuItem.selectTimeRange=\u6642\u9593\u7BC4\u56F2\u3092\u9078\u629E -Timeline.ui.countsview.menuItem.zoomIntoTimeRange=\u6642\u9593\u7BC4\u56F2\u3078\u30BA\u30FC\u30E0\u30A4\u30F3 -CountsViewPane.loggedTask.name=\u30AB\u30A6\u30F3\u30C8\u30D3\u30E5\u30FC\u3092\u66F4\u65B0\u4E2D -CountsViewPane.loggedTask.updatingCounts=\u30D3\u30B8\u30E5\u30A2\u30E9\u30A4\u30BC\u30FC\u30B7\u30E7\u30F3\uFF08\u53EF\u8996\u5316\uFF09\u3092\u5165\u529B\u4E2D -CountsViewPane.tooltip.text={0} {1} \u30A4\u30D9\u30F3\u30C8\n{2}\u3068\n{3}\u306E\u9593 -CountsViewPane.linearRadio.text=\u30EA\u30CB\u30A2 -CountsViewPane.logRadio.text=\u5BFE\u6570\u7684 -CountsViewPane.scaleLabel.text=\u30B9\u30B1\u30FC\u30EB\uFF1A -*=Autopsy\u30D5\u30A9\u30EC\u30F3\u30B8\u30C3\u30AF\u30D6\u30E9\u30A6\u30B6 \ No newline at end of file +CountsViewPane.numberOfEvents=\u30a4\u30d9\u30f3\u30c8\u6570 +CountsViewPane.detailSwitchMessage=\u79d2\u3088\u308a\u5c0f\u3055\u3044\u5358\u4f4d\u306f\u3042\u308a\u307e\u305b\u3093\u3002\n\u8a73\u7d30\u30d3\u30e5\u30fc\u306b\u5909\u66f4\u3057\u307e\u3059\u304b\uff1f +CountsViewPane.detailSwitchTitle=\u8a73\u7d30\u30d3\u30e5\u30fc\u306b\u5909\u66f4\u3057\u307e\u3059\u304b\uff1f +Timeline.ui.countsview.menuItem.selectEventType=\u30a4\u30d9\u30f3\u30c8\u30bf\u30a4\u30d7\u3092\u9078\u629e +Timeline.ui.countsview.menuItem.selectTimeandType=\u6642\u9593\u3068\u30bf\u30a4\u30d7\u3092\u9078\u629e +Timeline.ui.countsview.menuItem.selectTimeRange=\u6642\u9593\u7bc4\u56f2\u3092\u9078\u629e +Timeline.ui.countsview.menuItem.zoomIntoTimeRange=\u6642\u9593\u7bc4\u56f2\u3078\u30ba\u30fc\u30e0\u30a4\u30f3 +CountsViewPane.loggedTask.name=\u30ab\u30a6\u30f3\u30c8\u30d3\u30e5\u30fc\u3092\u66f4\u65b0\u4e2d +CountsViewPane.loggedTask.updatingCounts=\u30d3\u30b8\u30e5\u30a2\u30e9\u30a4\u30bc\u30fc\u30b7\u30e7\u30f3\uff08\u53ef\u8996\u5316\uff09\u3092\u5165\u529b\u4e2d +CountsViewPane.tooltip.text={0} {1} \u30a4\u30d9\u30f3\u30c8\n{2}\u3068\n{3}\u306e\u9593 +CountsViewPane.linearRadio.text=\u30ea\u30cb\u30a2 +CountsViewPane.logRadio.text=\u5bfe\u6570\u7684 +CountsViewPane.scaleLabel.text=\u30b9\u30b1\u30fc\u30eb\uff1a +*=Autopsy\u30d5\u30a9\u30ec\u30f3\u30b8\u30c3\u30af\u30d6\u30e9\u30a6\u30b6 \ No newline at end of file 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..47925187e3 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/CountsViewPane.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2014-16 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,7 @@ import java.util.Map; import java.util.function.Function; import javafx.application.Platform; import javafx.beans.Observable; +import javafx.beans.binding.BooleanBinding; import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; import javafx.concurrent.Task; @@ -32,13 +33,11 @@ import javafx.fxml.FXML; import javafx.scene.Node; import javafx.scene.chart.CategoryAxis; import javafx.scene.chart.NumberAxis; -import javafx.scene.chart.StackedBarChart; import javafx.scene.chart.XYChart; import javafx.scene.control.Label; import javafx.scene.control.RadioButton; 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; @@ -48,32 +47,26 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.timeline.FXMLConstructor; 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.ui.AbstractVisualizationPane; -import org.sleuthkit.autopsy.timeline.ui.detailview.DetailViewPane; +import static org.sleuthkit.autopsy.timeline.ui.countsview.Bundle.*; import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo; /** - * FXML Controller class for a {@link StackedBarChart} based - * implementation of a {@link TimeLineView}. + * FXML Controller class for a StackedBarChart based + * implementation of a TimeLineChart. * - * This class listens to changes in the assigned {@link FilteredEventsModel} and - * updates the internal {@link StackedBarChart} to reflect the currently - * requested events. + * This class listens to changes in the assigned FilteredEventsModel and updates + * the internal EventCountsChart to reflect the currently requested events. * * This class captures input from the user in the form of mouse clicks on graph - * bars, and forwards them to the assigned {@link TimeLineController} * + * bars, and forwards them to the assigned TimeLineController * * Concurrency Policy: Access to the private members stackedBarChart, countAxis, * dateAxis, EventTypeMap, and dataSets affects the stackedBarChart so they all - * must only be manipulated on the JavaFx thread (through {@link Platform#runLater(java.lang.Runnable)} - * - * {@link CountsChartPane#filteredEvents} should encapsulate all need - * synchronization internally. - * - * TODO: refactor common code out of this class and {@link DetailViewPane} into - * {@link AbstractVisualizationPane} + * must only be manipulated on the JavaFx thread (through + * Platform.runLater(java.lang.Runnable). The FilteredEventsModel should + * encapsulate all need synchronization internally. */ public class CountsViewPane extends AbstractVisualizationPane { @@ -82,7 +75,7 @@ public class CountsViewPane extends AbstractVisualizationPaneobservableArrayList()); - private final SimpleObjectProperty scale = new SimpleObjectProperty<>(ScaleType.LOGARITHMIC); + private final SimpleObjectProperty scaleProp = new SimpleObjectProperty<>(Scale.LOGARITHMIC); @Override protected String getTickMarkLabel(String labelValueString) { @@ -100,38 +93,42 @@ 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(); - }); + dateAxis.getTickMarks().addListener((Observable tickMarks) -> layoutDateLabels()); + dateAxis.categorySpacingProperty().addListener((Observable spacing) -> layoutDateLabels()); + dateAxis.getCategories().addListener((Observable categories) -> 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))); - scale.addListener(o -> { - countAxis.tickLabelsVisibleProperty().bind(scale.isEqualTo(ScaleType.LINEAR)); - countAxis.tickMarkVisibleProperty().bind(scale.isEqualTo(ScaleType.LINEAR)); - countAxis.minorTickVisibleProperty().bind(scale.isEqualTo(ScaleType.LINEAR)); + //bind tick visibility to scaleProp + BooleanBinding scaleIsLinear = scaleProp.isEqualTo(Scale.LINEAR); + countAxis.tickLabelsVisibleProperty().bind(scaleIsLinear); + countAxis.tickMarkVisibleProperty().bind(scaleIsLinear); + countAxis.minorTickVisibleProperty().bind(scaleIsLinear); + scaleProp.addListener(scale -> { update(); + countAxis.setLabel(Bundle.CountsViewPane_numberOfEvents(scaleProp.get().getDisplayName())); }); - + countAxis.setLabel(Bundle.CountsViewPane_numberOfEvents(scaleProp.get().getDisplayName())); } @Override @@ -150,28 +147,74 @@ public class CountsViewPane extends AbstractVisualizationPane series : dataSeries) { + series.getData().clear(); + } + dataSeries.clear(); + eventTypeToSeriesMap.clear(); + createSeries(); + } + /** + * Enum for the Scales available in the Counts View. + */ + @NbBundle.Messages({ + "ScaleType.Linear=Linear", + "ScaleType.Logarithmic=Logarithmic" + }) + private static enum Scale implements Function { + + LINEAR(Bundle.ScaleType_Linear()) { + @Override + public Double apply(Long inValue) { + return inValue.doubleValue(); + } + }, + LOGARITHMIC(Bundle.ScaleType_Logarithmic()) { + @Override + public Double apply(Long inValue) { + return Math.log10(inValue) + 1; + } + }; + + private final String displayName; + + /** + * Constructor + * + * @param displayName The display name for this Scale. + */ + Scale(String displayName) { + this.displayName = displayName; + } + + /** + * Get the display name of this ScaleType + * + * @return The display name. + */ + public String getDisplayName() { + return displayName; } } + /* + * A Pane that contains widgets to adjust settings specific to a + * CountsViewPane + */ private class CountsViewSettingsPane extends HBox { @FXML private RadioButton logRadio; - @FXML private RadioButton linearRadio; - @FXML private ToggleGroup scaleGroup; @@ -179,58 +222,40 @@ public class CountsViewPane extends AbstractVisualizationPane { if (scaleGroup.getSelectedToggle() == linearRadio) { - scale.set(ScaleType.LINEAR); - } - if (scaleGroup.getSelectedToggle() == logRadio) { - scale.set(ScaleType.LOGARITHMIC); + scaleProp.set(Scale.LINEAR); + } else if (scaleGroup.getSelectedToggle() == logRadio) { + scaleProp.set(Scale.LOGARITHMIC); } }); - logRadio.setText(NbBundle.getMessage(CountsViewPane.class, "CountsViewPane.logRadio.text")); - linearRadio.setText(NbBundle.getMessage(CountsViewPane.class, "CountsViewPane.linearRadio.text")); - scaleLabel.setText(NbBundle.getMessage(CountsViewPane.class, "CountsViewPane.scaleLabel.text")); + logRadio.setText(CountsViewPane_logRadio_text()); + linearRadio.setText(CountsViewPane_linearRadio_text()); + scaleLabel.setText(CountsViewPane_scaleLabel_text()); } + /** + * Constructor + */ CountsViewSettingsPane() { FXMLConstructor.construct(this, "CountsViewSettingsPane.fxml"); // NON-NLS } } - @ThreadConfined(type = ThreadConfined.ThreadType.JFX) - @Override - protected void resetData() { - for (XYChart.Series s : dataSeries) { - s.getData().clear(); - } - - dataSeries.clear(); - eventTypeToSeriesMap.clear(); - createSeries(); - } - - private static enum ScaleType implements Function { - - LINEAR(Long::doubleValue), - LOGARITHMIC(t -> Math.log10(t) + 1); - - private final Function func; - - ScaleType(Function func) { - this.func = func; - } - - @Override - public Double apply(Long t) { - return func.apply(t); - } - } - + /** + * Task that clears the Chart, fetches new data according to the current + * ZoomParams and loads it into the Chart + * + */ @NbBundle.Messages({ "CountsViewPane.loggedTask.name=Updating Counts View", "CountsViewPane.loggedTask.updatingCounts=Populating visualization"}) @@ -249,24 +274,21 @@ public class CountsViewPane extends AbstractVisualizationPane intervals = rangeInfo.getIntervals(); - List categories = Lists.transform(intervals, rangeInfo::formatForTick); //clear old data, and reset ranges and series - resetChart(categories); + resetChart(Lists.transform(intervals, rangeInfo::formatForTick)); updateMessage(Bundle.CountsViewPane_loggedTask_updatingCounts()); int chartMax = 0; int numIntervals = intervals.size(); + Scale activeScale = scaleProp.get(); + /* - * for each interval query database for event counts and add to - * chart. - * - * Doing this in chunks might seem inefficient but it lets us reuse - * more cached results as the user navigates to overlapping viewws - * - * //TODO: implement similar chunked caching in DetailsView -jm + * For each interval, query the database for event counts and add + * the counts to the chart. Doing this in chunks might seem + * inefficient but it lets us reuse more cached results as the user + * navigates to overlapping views. */ for (int i = 0; i < numIntervals; i++) { if (isCancelled()) { @@ -288,7 +310,7 @@ public class CountsViewPane extends AbstractVisualizationPane 0) { final String intervalCategory = rangeInfo.formatForTick(interval); - final double adjustedCount = scale.get().apply(count); + final double adjustedCount = activeScale.apply(count); final XYChart.Data dataItem = new XYChart.Data<>(intervalCategory, adjustedCount, @@ -299,9 +321,10 @@ public class CountsViewPane extends AbstractVisualizationPane { diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/EventCountsChart.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/EventCountsChart.java index 26569ab47c..477ef7eb64 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/EventCountsChart.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/countsview/EventCountsChart.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-15 Basis Technology Corp. + * Copyright 2014-16 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -87,7 +87,6 @@ final class EventCountsChart extends StackedBarChart implements dateAxis.setTickLabelsVisible(false); dateAxis.setTickLabelGap(0); - countAxis.setLabel(NbBundle.getMessage(CountsViewPane.class, "CountsChartPane.numberOfEvents")); countAxis.setAutoRanging(false); countAxis.setLowerBound(0); countAxis.setAnimated(true); @@ -167,6 +166,7 @@ final class EventCountsChart extends StackedBarChart implements return new CountsIntervalSelector(this); } + @Override public ObservableList getSelectedNodes() { return selectedNodes; } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java index 9527a1f2cd..a3e5213878 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java @@ -40,7 +40,6 @@ import javafx.scene.control.RadioButton; import javafx.scene.control.Slider; import javafx.scene.control.ToggleButton; import javafx.scene.control.ToggleGroup; -import javafx.scene.effect.Effect; import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; import javafx.scene.layout.Region; @@ -57,8 +56,6 @@ import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.datamodel.EventStripe; import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent; import org.sleuthkit.autopsy.timeline.ui.AbstractVisualizationPane; -import org.sleuthkit.autopsy.timeline.ui.detailview.HideDescriptionAction; -import org.sleuthkit.autopsy.timeline.ui.detailview.UnhideDescriptionAction; import org.sleuthkit.autopsy.timeline.utils.MappedList; import org.sleuthkit.autopsy.timeline.zooming.DescriptionLoD; @@ -205,7 +202,7 @@ public class DetailViewPane extends AbstractVisualizationPane c1, Boolean selected) { c1.applySelectionEffect(selected);