add permanent refresh button enabled when tags are updated

This commit is contained in:
jmillman 2016-05-04 12:23:23 -04:00
parent dfce250309
commit c98658f88e
2 changed files with 200 additions and 160 deletions

View File

@ -1,79 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?> <?import javafx.geometry.Insets?>
<?import java.lang.*?> <?import javafx.scene.control.Button?>
<?import javafx.geometry.*?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.MenuButton?>
<?import javafx.scene.image.*?> <?import javafx.scene.control.Separator?>
<?import javafx.scene.layout.*?> <?import javafx.scene.control.ToggleButton?>
<?import jfxtras.scene.control.*?> <?import javafx.scene.control.ToolBar?>
<?import org.controlsfx.control.*?> <?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?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 jfxtras.scene.control.LocalDateTimeTextField?>
<?import org.controlsfx.control.SegmentedButton?>
<fx:root prefHeight="-1.0" prefWidth="-1.0" type="javafx.scene.layout.BorderPane" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1"> <fx:root prefHeight="-1.0" prefWidth="-1.0" type="javafx.scene.layout.BorderPane" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
<top> <top>
<ToolBar fx:id="toolBar" prefWidth="200.0" BorderPane.alignment="CENTER"> <HBox BorderPane.alignment="CENTER">
<items> <children>
<HBox alignment="CENTER" BorderPane.alignment="CENTER"> <ToolBar fx:id="toolBar" prefWidth="200.0" HBox.hgrow="ALWAYS">
<children> <items>
<Label fx:id="visualizationModeLabel"> <HBox alignment="CENTER" BorderPane.alignment="CENTER">
<HBox.margin> <children>
<Insets right="5.0" /> <Label fx:id="visualizationModeLabel">
</HBox.margin> <HBox.margin>
<font> <Insets right="5.0" />
<Font name="System Bold" size="14.0" /> </HBox.margin>
</font>
</Label>
<org.controlsfx.control.SegmentedButton maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity">
<buttons>
<ToggleButton fx:id="countsToggle" alignment="TOP_LEFT" mnemonicParsing="false" selected="true">
<graphic>
<ImageView fitHeight="16.0" fitWidth="16.0" mouseTransparent="true" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../images/chart_bar.png" />
</image>
</ImageView>
</graphic>
<font> <font>
<Font name="System Bold" size="16.0" /> <Font name="System Bold" size="14.0" />
</font> </font>
</ToggleButton> </Label>
<ToggleButton fx:id="detailsToggle" alignment="CENTER_RIGHT" layoutX="74.0" mnemonicParsing="false" selected="false">
<graphic> <org.controlsfx.control.SegmentedButton maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity">
<ImageView fitHeight="16.0" fitWidth="16.0" mouseTransparent="true" pickOnBounds="true" preserveRatio="true" rotate="0.0" smooth="true" style="-fx-background-color:white;" x="2.0" y="1.0"> <buttons>
<image> <ToggleButton fx:id="countsToggle" alignment="TOP_LEFT" mnemonicParsing="false" selected="true">
<Image url="@../images/20140521121247760_easyicon_net_32_colorized.png" /> <graphic>
</image> <ImageView fitHeight="16.0" fitWidth="16.0" mouseTransparent="true" pickOnBounds="true" preserveRatio="true">
</ImageView> <image>
</graphic> <Image url="@../images/chart_bar.png" />
<font> </image>
<Font name="System Bold" size="16.0" /> </ImageView>
</font> </graphic>
</ToggleButton> <font>
</buttons> <Font name="System Bold" size="16.0" />
</font>
</org.controlsfx.control.SegmentedButton> </ToggleButton>
</children> <ToggleButton fx:id="detailsToggle" alignment="CENTER_RIGHT" layoutX="74.0" mnemonicParsing="false" selected="false">
<padding> <graphic>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" /> <ImageView fitHeight="16.0" fitWidth="16.0" mouseTransparent="true" pickOnBounds="true" preserveRatio="true" rotate="0.0" smooth="true" style="-fx-background-color:white;" x="2.0" y="1.0">
</padding> <image>
<BorderPane.margin> <Image url="@../images/20140521121247760_easyicon_net_32_colorized.png" />
<Insets left="10.0" /> </image>
</BorderPane.margin> </ImageView>
</HBox> </graphic>
<Separator orientation="VERTICAL" /> <font>
<Button fx:id="snapShotButton" mnemonicParsing="false"> <Font name="System Bold" size="16.0" />
<graphic> </font>
</ToggleButton>
</buttons>
</org.controlsfx.control.SegmentedButton>
</children>
<padding>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</padding>
<BorderPane.margin>
<Insets left="10.0" />
</BorderPane.margin>
</HBox>
</items>
</ToolBar>
<ToolBar maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
<items>
<Separator orientation="VERTICAL" />
<Button fx:id="snapShotButton" mnemonicParsing="false">
<graphic>
<ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../images/image.png" />
</image>
</ImageView>
</graphic>
</Button>
<Separator halignment="LEFT" maxWidth="1.7976931348623157E308" orientation="VERTICAL" />
<Button fx:id="refreshButton" alignment="CENTER_RIGHT" mnemonicParsing="false" text="Refresh">
<graphic>
<ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true"> <ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
<image> <image>
<Image url="@../images/image.png" /> <Image url="@../images/arrow-circle-double-135.png" />
</image> </image>
</ImageView> </ImageView>
</graphic> </graphic>
</Button> </Button>
<Separator orientation="VERTICAL" /> </items>
</items> </ToolBar>
</ToolBar> </children>
</HBox>
</top> </top>
<bottom> <bottom>
<VBox maxHeight="-Infinity"> <VBox maxHeight="-Infinity">

View File

@ -29,6 +29,7 @@ import java.util.function.Supplier;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.InvalidationListener; import javafx.beans.InvalidationListener;
import javafx.beans.Observable; import javafx.beans.Observable;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@ -96,16 +97,16 @@ import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;
* TODO: refactor common code out of histogram and CountsView? -jm * TODO: refactor common code out of histogram and CountsView? -jm
*/ */
final public class VisualizationPanel extends BorderPane { final public class VisualizationPanel extends BorderPane {
private static final Logger LOGGER = Logger.getLogger(VisualizationPanel.class.getName()); private static final Logger LOGGER = Logger.getLogger(VisualizationPanel.class.getName());
private static final Image INFORMATION = new Image("org/sleuthkit/autopsy/timeline/images/information.png", 16, 16, true, true); // NON-NLS private static final Image INFORMATION = new Image("org/sleuthkit/autopsy/timeline/images/information.png", 16, 16, true, true); // NON-NLS
private static final Image REFRESH = new Image("org/sleuthkit/autopsy/timeline/images/arrow-circle-double-135.png"); // NON-NLS private static final Image REFRESH = new Image("org/sleuthkit/autopsy/timeline/images/arrow-circle-double-135.png"); // NON-NLS
private static final Background background = new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY)); private static final Background background = new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY));
@GuardedBy("this") @GuardedBy("this")
private LoggedTask<Void> histogramTask; private LoggedTask<Void> histogramTask;
private final EventsTree eventsTree; private final EventsTree eventsTree;
private AbstractVisualizationPane<?, ?, ?, ?> visualization; private AbstractVisualizationPane<?, ?, ?, ?> visualization;
//// range slider and histogram componenets //// range slider and histogram componenets
@ -120,13 +121,13 @@ final public class VisualizationPanel extends BorderPane {
*/ */
@FXML @FXML
private StackPane rangeHistogramStack; private StackPane rangeHistogramStack;
private final RangeSlider rangeSlider = new RangeSlider(0, 1.0, .25, .75); private final RangeSlider rangeSlider = new RangeSlider(0, 1.0, .25, .75);
//// time range selection components //// time range selection components
@FXML @FXML
private MenuButton zoomMenuButton; private MenuButton zoomMenuButton;
@FXML @FXML
private Button zoomOutButton; private Button zoomOutButton;
@FXML @FXML
@ -158,13 +159,15 @@ final public class VisualizationPanel extends BorderPane {
@FXML @FXML
private Button snapShotButton; private Button snapShotButton;
@FXML @FXML
private Button refreshButton;
@FXML
private Label visualizationModeLabel; private Label visualizationModeLabel;
/** /**
* wraps contained visualization so that we can show notifications over it. * wraps contained visualization so that we can show notifications over it.
*/ */
private final NotificationPane notificationPane = new NotificationPane(); private final NotificationPane notificationPane = new NotificationPane();
private final ReadOnlyBooleanWrapper needsRefresh = new ReadOnlyBooleanWrapper(false);
private final TimeLineController controller; private final TimeLineController controller;
private final FilteredEventsModel filteredEvents; private final FilteredEventsModel filteredEvents;
@ -190,7 +193,7 @@ final public class VisualizationPanel extends BorderPane {
/** /**
* hides the notification pane on any event * hides the notification pane on any event
*/ */
private final InvalidationListener zoomListener = any -> notificationPane.hide(); private final InvalidationListener zoomListener = any -> setNeedsRefresh(false);
/** /**
* listen to change in end time picker and push to controller * listen to change in end time picker and push to controller
@ -225,14 +228,14 @@ final public class VisualizationPanel extends BorderPane {
private static LocalDateTime epochMillisToLocalDateTime(long millis) { private static LocalDateTime epochMillisToLocalDateTime(long millis) {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), TimeLineController.getTimeZoneID()); return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), TimeLineController.getTimeZoneID());
} }
public VisualizationPanel(@Nonnull TimeLineController controller, @Nonnull EventsTree eventsTree) { public VisualizationPanel(@Nonnull TimeLineController controller, @Nonnull EventsTree eventsTree) {
this.controller = controller; this.controller = controller;
this.filteredEvents = controller.getEventsModel(); this.filteredEvents = controller.getEventsModel();
this.eventsTree = eventsTree; this.eventsTree = eventsTree;
FXMLConstructor.construct(this, "VisualizationPanel.fxml"); // NON-NLS FXMLConstructor.construct(this, "VisualizationPanel.fxml"); // NON-NLS
} }
@FXML // This method is called by the FXMLLoader when initialization is complete @FXML // This method is called by the FXMLLoader when initialization is complete
@NbBundle.Messages({ @NbBundle.Messages({
"VisualizationPanel.visualizationModeLabel.text=Visualization Mode:", "VisualizationPanel.visualizationModeLabel.text=Visualization Mode:",
@ -266,7 +269,7 @@ final public class VisualizationPanel extends BorderPane {
controller.setViewMode(VisualizationMode.DETAIL); controller.setViewMode(VisualizationMode.DETAIL);
} }
}; };
if (countsToggle.getToggleGroup() != null) { if (countsToggle.getToggleGroup() != null) {
countsToggle.getToggleGroup().selectedToggleProperty().addListener(toggleListener); countsToggle.getToggleGroup().selectedToggleProperty().addListener(toggleListener);
} else { } else {
@ -279,6 +282,7 @@ final public class VisualizationPanel extends BorderPane {
//configure snapshor button / action //configure snapshor button / action
ActionUtils.configureButton(new SaveSnapshotAsReport(controller, VisualizationPanel.this), snapShotButton); ActionUtils.configureButton(new SaveSnapshotAsReport(controller, VisualizationPanel.this), snapShotButton);
ActionUtils.configureButton(new Refresh(), refreshButton);
/////configure start and end pickers /////configure start and end pickers
startLabel.setText(Bundle.VisualizationPanel_startLabel_text()); startLabel.setText(Bundle.VisualizationPanel_startLabel_text());
@ -343,9 +347,9 @@ final public class VisualizationPanel extends BorderPane {
} }
}); });
refreshHistorgram(); refreshHistorgram();
} }
private void setViewMode(VisualizationMode visualizationMode) { private void setViewMode(VisualizationMode visualizationMode) {
switch (visualizationMode) { switch (visualizationMode) {
case COUNTS: case COUNTS:
@ -357,75 +361,83 @@ final public class VisualizationPanel extends BorderPane {
detailsToggle.setSelected(true); detailsToggle.setSelected(true);
break; break;
} }
} }
private synchronized void setVisualization(final AbstractVisualizationPane<?, ?, ?, ?> newViz) { private synchronized void setVisualization(final AbstractVisualizationPane<?, ?, ?, ?> newViz) {
Platform.runLater(() -> { Platform.runLater(() -> {
synchronized (VisualizationPanel.this) { if (visualization != null) {
if (visualization != null) { toolBar.getItems().removeAll(visualization.getSettingsNodes());
toolBar.getItems().removeAll(visualization.getSettingsNodes()); visualization.dispose();
visualization.dispose(); }
}
visualization = newViz;
visualization = newViz; visualization.update();
visualization.update(); toolBar.getItems().addAll(newViz.getSettingsNodes());
toolBar.getItems().addAll(newViz.getSettingsNodes());
notificationPane.setContent(visualization);
notificationPane.setContent(visualization); if (visualization instanceof DetailViewPane) {
if (visualization instanceof DetailViewPane) { Platform.runLater(() -> {
Platform.runLater(() -> { ((DetailViewPane) visualization).setHighLightedEvents(eventsTree.getSelectedEvents());
((DetailViewPane) visualization).setHighLightedEvents(eventsTree.getSelectedEvents()); eventsTree.setDetailViewPane((DetailViewPane) visualization);
eventsTree.setDetailViewPane((DetailViewPane) visualization);
});
}
visualization.hasEvents.addListener((observable, oldValue, newValue) -> {
if (newValue == false) {
notificationPane.setContent(
new StackPane(visualization,
new Region() {
{
setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY)));
setOpacity(.3);
}
},
new NoEventsDialog(() -> notificationPane.setContent(visualization))));
} else {
notificationPane.setContent(visualization);
}
}); });
} }
visualization.hasEvents.addListener((observable, oldValue, newValue) -> {
if (newValue == false) {
notificationPane.setContent(
new StackPane(visualization,
new Region() {
{
setBackground(new Background(new BackgroundFill(Color.GREY, CornerRadii.EMPTY, Insets.EMPTY)));
setOpacity(.3);
}
},
new NoEventsDialog(() -> notificationPane.setContent(visualization))));
} else {
notificationPane.setContent(visualization);
}
});
}); });
setNeedsRefresh(false);
} }
@Subscribe @Subscribe
@NbBundle.Messages("VisualizationPanel.tagsAddedOrDeleted=Tags have been created and/or deleted. The visualization may not be up to date.") @NbBundle.Messages("VisualizationPanel.tagsAddedOrDeleted=Tags have been created and/or deleted. The visualization may not be up to date.")
public void handleTimeLineTagEvent(TagsUpdatedEvent event) { public void handleTimeLineTagEvent(TagsUpdatedEvent event) {
Platform.runLater(() -> { setNeedsRefresh(true);
notificationPane.setCloseButtonVisible(false);
notificationPane.getActions().setAll(new Refresh());
notificationPane.show(Bundle.VisualizationPanel_tagsAddedOrDeleted(), new ImageView(INFORMATION));
});
} }
@Subscribe @Subscribe
public void handleRefreshRequestedEvent(RefreshRequestedEvent event) { public void handleRefreshRequestedEvent(RefreshRequestedEvent event) {
Platform.runLater(notificationPane::hide); setNeedsRefresh(false);
} }
private void setNeedsRefresh(Boolean needsRefresh) {
Platform.runLater(() -> {
VisualizationPanel.this.needsRefresh.set(needsRefresh);
if (needsRefresh) {
notificationPane.show(Bundle.VisualizationPanel_tagsAddedOrDeleted(), new ImageView(INFORMATION));
} else {
notificationPane.hide();
}
});
}
synchronized private void refreshHistorgram() { synchronized private void refreshHistorgram() {
if (histogramTask != null) { if (histogramTask != null) {
histogramTask.cancel(true); histogramTask.cancel(true);
} }
histogramTask = new LoggedTask<Void>( histogramTask = new LoggedTask<Void>(
NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.title"), true) { // NON-NLS NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.title"), true) { // NON-NLS
private final Lighting lighting = new Lighting(); private final Lighting lighting = new Lighting();
@Override @Override
protected Void call() throws Exception { 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; long max = 0;
@ -442,9 +454,9 @@ final public class VisualizationPanel extends BorderPane {
updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.resetUI")); // NON-NLS updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.resetUI")); // NON-NLS
}); });
ArrayList<Long> bins = new ArrayList<>(); ArrayList<Long> bins = new ArrayList<>();
DateTime start = timeRange.getStart(); DateTime start = timeRange.getStart();
while (timeRange.contains(start)) { while (timeRange.contains(start)) {
if (isCancelled()) { if (isCancelled()) {
@ -455,21 +467,21 @@ final public class VisualizationPanel extends BorderPane {
//increment for next iteration //increment for next iteration
start = end; start = end;
updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.queryDb")); // NON-NLS updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.queryDb")); // NON-NLS
//query for current range //query for current range
long count = filteredEvents.getEventCounts(interval).values().stream().mapToLong(Long::valueOf).sum(); long count = filteredEvents.getEventCounts(interval).values().stream().mapToLong(Long::valueOf).sum();
bins.add(count); bins.add(count);
max = Math.max(count, max); max = Math.max(count, max);
final double fMax = Math.log(max); final double fMax = Math.log(max);
final ArrayList<Long> fbins = new ArrayList<>(bins); final ArrayList<Long> fbins = new ArrayList<>(bins);
Platform.runLater(() -> { Platform.runLater(() -> {
updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.updateUI2")); // NON-NLS updateMessage(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.histogramTask.updateUI2")); // NON-NLS
histogramBox.getChildren().clear(); histogramBox.getChildren().clear();
for (Long bin : fbins) { for (Long bin : fbins) {
if (isCancelled()) { if (isCancelled()) {
break; break;
@ -492,41 +504,41 @@ final public class VisualizationPanel extends BorderPane {
} }
return null; return null;
} }
}; };
new Thread(histogramTask).start(); new Thread(histogramTask).start();
controller.monitorTask(histogramTask); controller.monitorTask(histogramTask);
} }
private void refreshTimeUI() { private void refreshTimeUI() {
refreshTimeUI(filteredEvents.timeRangeProperty().get()); refreshTimeUI(filteredEvents.timeRangeProperty().get());
} }
private void refreshTimeUI(Interval interval) { private void refreshTimeUI(Interval interval) {
RangeDivisionInfo rangeDivisionInfo = RangeDivisionInfo.getRangeDivisionInfo(filteredEvents.getSpanningInterval()); RangeDivisionInfo rangeDivisionInfo = RangeDivisionInfo.getRangeDivisionInfo(filteredEvents.getSpanningInterval());
final long minTime = rangeDivisionInfo.getLowerBound(); final long minTime = rangeDivisionInfo.getLowerBound();
final long maxTime = rangeDivisionInfo.getUpperBound(); final long maxTime = rangeDivisionInfo.getUpperBound();
long startMillis = interval.getStartMillis(); long startMillis = interval.getStartMillis();
long endMillis = interval.getEndMillis(); long endMillis = interval.getEndMillis();
if (minTime > 0 && maxTime > minTime) { if (minTime > 0 && maxTime > minTime) {
Platform.runLater(() -> { Platform.runLater(() -> {
startPicker.localDateTimeProperty().removeListener(startListener); startPicker.localDateTimeProperty().removeListener(startListener);
endPicker.localDateTimeProperty().removeListener(endListener); endPicker.localDateTimeProperty().removeListener(endListener);
rangeSlider.highValueChangingProperty().removeListener(rangeSliderListener); rangeSlider.highValueChangingProperty().removeListener(rangeSliderListener);
rangeSlider.lowValueChangingProperty().removeListener(rangeSliderListener); rangeSlider.lowValueChangingProperty().removeListener(rangeSliderListener);
rangeSlider.setMax((maxTime - minTime)); rangeSlider.setMax((maxTime - minTime));
rangeSlider.setLowValue(startMillis - minTime); rangeSlider.setLowValue(startMillis - minTime);
rangeSlider.setHighValue(endMillis - minTime); rangeSlider.setHighValue(endMillis - minTime);
startPicker.setLocalDateTime(epochMillisToLocalDateTime(startMillis)); startPicker.setLocalDateTime(epochMillisToLocalDateTime(startMillis));
endPicker.setLocalDateTime(epochMillisToLocalDateTime(endMillis)); endPicker.setLocalDateTime(epochMillisToLocalDateTime(endMillis));
rangeSlider.highValueChangingProperty().addListener(rangeSliderListener); rangeSlider.highValueChangingProperty().addListener(rangeSliderListener);
rangeSlider.lowValueChangingProperty().addListener(rangeSliderListener); rangeSlider.lowValueChangingProperty().addListener(rangeSliderListener);
startPicker.localDateTimeProperty().addListener(startListener); startPicker.localDateTimeProperty().addListener(startListener);
@ -534,10 +546,10 @@ final public class VisualizationPanel extends BorderPane {
}); });
} }
} }
@NbBundle.Messages("NoEventsDialog.titledPane.text=No Visible Events") @NbBundle.Messages("NoEventsDialog.titledPane.text=No Visible Events")
private class NoEventsDialog extends StackPane { private class NoEventsDialog extends StackPane {
@FXML @FXML
private TitledPane titledPane; private TitledPane titledPane;
@FXML @FXML
@ -550,14 +562,14 @@ final public class VisualizationPanel extends BorderPane {
private Button zoomButton; private Button zoomButton;
@FXML @FXML
private Label noEventsDialogLabel; private Label noEventsDialogLabel;
private final Runnable closeCallback; private final Runnable closeCallback;
private NoEventsDialog(Runnable closeCallback) { private NoEventsDialog(Runnable closeCallback) {
this.closeCallback = closeCallback; this.closeCallback = closeCallback;
FXMLConstructor.construct(this, "NoEventsDialog.fxml"); // NON-NLS FXMLConstructor.construct(this, "NoEventsDialog.fxml"); // NON-NLS
} }
@FXML @FXML
void initialize() { void initialize() {
assert resetFiltersButton != null : "fx:id=\"resetFiltersButton\" was not injected: check your FXML file 'NoEventsDialog.fxml'."; // NON-NLS assert resetFiltersButton != null : "fx:id=\"resetFiltersButton\" was not injected: check your FXML file 'NoEventsDialog.fxml'."; // NON-NLS
@ -568,7 +580,7 @@ final public class VisualizationPanel extends BorderPane {
noEventsDialogLabel.setText(NbBundle.getMessage(NoEventsDialog.class, "VisualizationPanel.noEventsDialogLabel.text")); // NON-NLS noEventsDialogLabel.setText(NbBundle.getMessage(NoEventsDialog.class, "VisualizationPanel.noEventsDialogLabel.text")); // NON-NLS
dismissButton.setOnAction(actionEvent -> closeCallback.run()); dismissButton.setOnAction(actionEvent -> closeCallback.run());
ActionUtils.configureButton(new ZoomToEvents(controller), zoomButton); ActionUtils.configureButton(new ZoomToEvents(controller), zoomButton);
ActionUtils.configureButton(new Back(controller), backButton); ActionUtils.configureButton(new Back(controller), backButton);
ActionUtils.configureButton(new ResetFilters(controller), resetFiltersButton); ActionUtils.configureButton(new ResetFilters(controller), resetFiltersButton);
@ -580,15 +592,15 @@ final public class VisualizationPanel extends BorderPane {
* the selected LocalDateTime as start/end to the timelinecontroller. * the selected LocalDateTime as start/end to the timelinecontroller.
*/ */
private class PickerListener implements InvalidationListener { private class PickerListener implements InvalidationListener {
private final BiFunction< Interval, Long, Interval> intervalMapper; private final BiFunction< Interval, Long, Interval> intervalMapper;
private final Supplier<LocalDateTimeTextField> pickerSupplier; private final Supplier<LocalDateTimeTextField> pickerSupplier;
PickerListener(Supplier<LocalDateTimeTextField> pickerSupplier, BiFunction<Interval, Long, Interval> intervalMapper) { PickerListener(Supplier<LocalDateTimeTextField> pickerSupplier, BiFunction<Interval, Long, Interval> intervalMapper) {
this.pickerSupplier = pickerSupplier; this.pickerSupplier = pickerSupplier;
this.intervalMapper = intervalMapper; this.intervalMapper = intervalMapper;
} }
@Override @Override
public void invalidated(Observable observable) { public void invalidated(Observable observable) {
LocalDateTime pickerTime = pickerSupplier.get().getLocalDateTime(); LocalDateTime pickerTime = pickerSupplier.get().getLocalDateTime();
@ -603,7 +615,7 @@ final public class VisualizationPanel extends BorderPane {
* callback that disabled date/times outside the span of the current case. * callback that disabled date/times outside the span of the current case.
*/ */
private class LocalDateDisabler implements Callback<LocalDateTimePicker.LocalDateTimeRange, Void> { private class LocalDateDisabler implements Callback<LocalDateTimePicker.LocalDateTimeRange, Void> {
@Override @Override
public Void call(LocalDateTimePicker.LocalDateTimeRange viewedRange) { public Void call(LocalDateTimePicker.LocalDateTimeRange viewedRange) {
startPicker.disabledLocalDateTimes().clear(); startPicker.disabledLocalDateTimes().clear();
@ -613,7 +625,7 @@ final public class VisualizationPanel extends BorderPane {
Interval spanningInterval = filteredEvents.getSpanningInterval(); Interval spanningInterval = filteredEvents.getSpanningInterval();
long spanStartMillis = spanningInterval.getStartMillis(); long spanStartMillis = spanningInterval.getStartMillis();
long spaneEndMillis = spanningInterval.getEndMillis(); long spaneEndMillis = spanningInterval.getEndMillis();
LocalDate rangeStartLocalDate = viewedRange.getStartLocalDateTime().toLocalDate(); LocalDate rangeStartLocalDate = viewedRange.getStartLocalDateTime().toLocalDate();
LocalDate rangeEndLocalDate = viewedRange.getEndLocalDateTime().toLocalDate().plusDays(1); LocalDate rangeEndLocalDate = viewedRange.getEndLocalDateTime().toLocalDate().plusDays(1);
//iterate over days of the displayed range and disable ones not in spanning interval //iterate over days of the displayed range and disable ones not in spanning interval
@ -641,11 +653,11 @@ final public class VisualizationPanel extends BorderPane {
* picker to reset if invalid info was entered * picker to reset if invalid info was entered
*/ */
private final LocalDateTimeTextField picker; private final LocalDateTimeTextField picker;
LocalDateTimeValidator(LocalDateTimeTextField picker) { LocalDateTimeValidator(LocalDateTimeTextField picker) {
this.picker = picker; this.picker = picker;
} }
@Override @Override
public Boolean call(LocalDateTime param) { public Boolean call(LocalDateTime param) {
long epochMilli = localDateTimeToEpochMilli(param); long epochMilli = localDateTimeToEpochMilli(param);
@ -660,15 +672,16 @@ final public class VisualizationPanel extends BorderPane {
} }
} }
} }
private class Refresh extends Action { private class Refresh extends Action {
@NbBundle.Messages({"VisualizationPanel.refresh=refresh"}) @NbBundle.Messages({"VisualizationPanel.refresh=refresh"})
Refresh() { Refresh() {
super(Bundle.VisualizationPanel_refresh()); super(Bundle.VisualizationPanel_refresh());
setGraphic(new ImageView(REFRESH)); setGraphic(new ImageView(REFRESH));
setEventHandler(actionEvent -> filteredEvents.refresh()); setEventHandler(actionEvent -> filteredEvents.refresh());
disabledProperty().bind(needsRefresh.not());
} }
} }
} }