install actions/buttons lazily

This commit is contained in:
jmillman 2015-11-20 11:57:04 -05:00
parent 5c6714b2f3
commit 5c3adb549e
5 changed files with 68 additions and 62 deletions

View File

@ -348,7 +348,7 @@ public final class FilteredEventsModel {
* range and pass the requested filter, using the given aggregation
* to control the grouping of events
*/
public List<EventStripe> getEventClusters(ZoomParams params) {
public List<EventStripe> getEventStripes(ZoomParams params) {
return repo.getEventStripes(params);
}

View File

@ -30,9 +30,7 @@ import java.util.stream.Collectors;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
@ -104,7 +102,7 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
protected final EventDetailsChart chart;
final SimpleObjectProperty<DescriptionLoD> descLOD = new SimpleObjectProperty<>();
final SimpleObjectProperty<DescriptionVisibility> descVisibility = new SimpleObjectProperty<>(DescriptionVisibility.SHOWN);
final SimpleObjectProperty<DescriptionVisibility> descVisibility = new SimpleObjectProperty<>();
protected final BundleType eventBundle;
protected final ParentNodeType parentNode;
@ -150,9 +148,13 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
setAlignment(Pos.TOP_LEFT);
setPrefHeight(USE_COMPUTED_SIZE);
heightProperty().addListener(heightProp -> {
chart.requestChartLayout();
});
/*
* This triggers the layout when a mousover causes the action buttons to
* interesect with another node, forcing it down.
*/
heightProperty().addListener(heightProp -> chart.requestChartLayout());
setMaxHeight(USE_PREF_SIZE);
setMinWidth(USE_PREF_SIZE);
setMaxWidth(USE_PREF_SIZE);
@ -176,11 +178,7 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
//set up mouse hover effect and tooltip
setOnMouseEntered((MouseEvent e) -> {
/*
* defer tooltip content creation till needed, this had a
* surprisingly large impact on speed of loading the chart
*/
installTooltip();
Tooltip.uninstall(chart, AbstractVisualizationPane.getDefaultTooltip());
showHoverControls(true);
toFront();
@ -194,11 +192,8 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
}
});
descVisibility.addListener((ObservableValue<? extends DescriptionVisibility> observable, DescriptionVisibility oldValue, DescriptionVisibility newValue) -> {
setDescriptionVisibiltiyImpl(newValue);
});
setDescriptionVisibiltiyImpl(DescriptionVisibility.SHOWN);
descVisibility.addListener(observable -> setDescriptionVisibiltiyImpl(descVisibility.get()));
descVisibility.set(DescriptionVisibility.SHOWN); //trigger listener for initial value
}
final DescriptionLoD getDescriptionLoD() {
@ -215,6 +210,17 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
: 0;
}
/**
* install whatever buttons are visible on hover for this node. likes
* tooltips, this had a surprisingly large impact on speed of loading the
* chart
*/
abstract void installActionButtons();
/**
* defer tooltip content creation till needed, this had a surprisingly large
* impact on speed of loading the chart
*/
@NbBundle.Messages({"# {0} - counts",
"# {1} - event type",
"# {2} - description",
@ -307,12 +313,11 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
Effect dropShadow = dropShadowMap.computeIfAbsent(getEventType(),
eventType -> new DropShadow(-10, eventType.getColor()));
setEffect(showControls ? dropShadow : null);
installTooltip();
enableTooltip(showControls);
if (parentNode != null) {
parentNode.enableTooltip(false);
parentNode.showHoverControls(false);
}
}
final EventType getEventType() {
@ -366,12 +371,15 @@ public abstract class EventBundleNodeBase<BundleType extends EventBundle<ParentT
void animateTo(double xLeft, double yTop) {
if (timeline != null) {
timeline.stop();
chart.requestChartLayout();
}
timeline = new Timeline(new KeyFrame(Duration.millis(100),
new KeyValue(layoutXProperty(), xLeft),
new KeyValue(layoutYProperty(), yTop))
);
timeline.setOnFinished(finished -> Platform.runLater(chart::requestChartLayout));
timeline.setOnFinished(finished -> chart.requestChartLayout());
timeline.play();
}
}

View File

@ -18,16 +18,15 @@
*/
package org.sleuthkit.autopsy.timeline.ui.detailview;
import com.google.common.collect.Lists;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import static java.util.Objects.nonNull;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.stream.Collectors;
import javafx.beans.binding.Bindings;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
@ -71,8 +70,20 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
private static final Image MINUS = new Image("/org/sleuthkit/autopsy/timeline/images/minus-button.png"); // NON-NLS //NOI18N
private final Border clusterBorder = new Border(new BorderStroke(evtColor.deriveColor(0, 1, 1, .4), BorderStrokeStyle.SOLID, CORNER_RADII_1, CLUSTER_BORDER_WIDTHS));
final Button plusButton = ActionUtils.createButton(new ExpandClusterAction(), ActionUtils.ActionTextBehavior.HIDE);
final Button minusButton = ActionUtils.createButton(new CollapseClusterAction(), ActionUtils.ActionTextBehavior.HIDE);
private Button plusButton;
private Button minusButton;
@Override
void installActionButtons() {
if (plusButton == null) {
plusButton = ActionUtils.createButton(new ExpandClusterAction(), ActionUtils.ActionTextBehavior.HIDE);
minusButton = ActionUtils.createButton(new CollapseClusterAction(), ActionUtils.ActionTextBehavior.HIDE);
configureLoDButton(plusButton);
configureLoDButton(minusButton);
infoHBox.getChildren().addAll(minusButton, plusButton);
}
}
public EventClusterNode(EventDetailsChart chart, EventCluster eventCluster, EventStripeNode parentNode) {
super(chart, eventCluster, parentNode);
@ -87,11 +98,8 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
setCursor(Cursor.HAND);
setOnMouseClicked(new MouseClickHandler());
configureLoDButton(plusButton);
configureLoDButton(minusButton);
setAlignment(Pos.CENTER_LEFT);
infoHBox.getChildren().addAll(minusButton, plusButton);
getChildren().addAll(subNodePane, infoHBox);
}
@ -99,6 +107,7 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
@Override
void showHoverControls(final boolean showControls) {
super.showHoverControls(showControls);
installActionButtons();
show(plusButton, showControls);
show(minusButton, showControls);
}
@ -141,10 +150,7 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
@NbBundle.Messages(value = "EventStripeNode.loggedTask.name=Load sub clusters")
private synchronized void loadSubBundles(DescriptionLoD.RelativeDetail relativeDetail) {
chart.setCursor(Cursor.WAIT);
chart.getEventStripes().removeIf(bundle ->
subNodes.stream().anyMatch(subNode ->
bundle.equals(subNode.getEventStripe()))
);
chart.getEventStripes().removeAll(Lists.transform(subNodes, EventStripeNode::getEventStripe));
subNodes.clear();
/*
@ -169,29 +175,22 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
@Override
protected Collection<EventStripe> call() throws Exception {
Collection<EventStripe> bundles = null;
Collection<EventStripe> bundles;
DescriptionLoD next = loadedDescriptionLoD;
do {
loadedDescriptionLoD = next;
if (loadedDescriptionLoD == getEventBundle().getDescriptionLoD()) {
return Collections.emptySet();
}
bundles = eventsModel.getEventClusters(zoomParams.withDescrLOD(loadedDescriptionLoD)).stream()
.collect(Collectors.toMap(EventStripe::getDescription, //key
eventStripe -> eventStripe.withParent(getEventCluster()), //value
EventStripe::merge) //merge method
).values();
bundles = eventsModel.getEventStripes(zoomParams.withDescrLOD(loadedDescriptionLoD));
next = loadedDescriptionLoD.withRelativeDetail(relativeDetail);
} while (bundles.size() == 1 && nonNull(next));
// return list of AbstractEventStripeNodes representing sub-bundles
return bundles;
}
@Override
protected void succeeded() {
try {
Collection<EventStripe> bundles = get();
@ -203,7 +202,6 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
chart.getEventStripes().addAll(bundles);
subNodes.addAll(bundles.stream()
.map(EventClusterNode.this::createStripeNode)
.sorted(Comparator.comparing(EventStripeNode::getStartMillis))
.collect(Collectors.toList()));
subNodePane.getChildren().setAll(subNodes);
getChildren().setAll(new VBox(infoHBox, subNodePane));
@ -303,9 +301,8 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
super(Bundle.ExpandClusterAction_text());
setGraphic(new ImageView(PLUS));
setEventHandler((ActionEvent t) -> {
final DescriptionLoD next = descLOD.get().moreDetailed();
if (next != null) {
setEventHandler(actionEvent -> {
if (descLOD.get().moreDetailed() != null) {
loadSubBundles(DescriptionLoD.RelativeDetail.MORE);
}
});
@ -320,9 +317,8 @@ final public class EventClusterNode extends EventBundleNodeBase<EventCluster, Ev
super(Bundle.CollapseClusterAction_text());
setGraphic(new ImageView(MINUS));
setEventHandler((ActionEvent t) -> {
final DescriptionLoD previous = descLOD.get().lessDetailed();
if (previous != null) {
setEventHandler(actionEvent -> {
if (descLOD.get().lessDetailed() != null) {
loadSubBundles(DescriptionLoD.RelativeDetail.LESS);
}
});

View File

@ -493,9 +493,7 @@ public final class EventDetailsChart extends XYChart<DateTime, EventStripe> impl
localMax = Math.max(yTop + h, localMax);
if ((xLeft != bundleNode.getLayoutX()) || (yTop != bundleNode.getLayoutY())) {
// bundleNode.relocate(xLeft, yTop);
// requestChartLayout();
// //animate node to new position
//animate node to new position
bundleNode.animateTo(xLeft, yTop);
}
}
@ -517,7 +515,7 @@ public final class EventDetailsChart extends XYChart<DateTime, EventStripe> impl
@Override
public void requestChartLayout() {
super.requestChartLayout(); //To change body of generated methods, choose Tools | Templates.
super.requestChartLayout();
}
private double getXForEpochMillis(Long millis) {
@ -647,9 +645,7 @@ public final class EventDetailsChart extends XYChart<DateTime, EventStripe> impl
DescriptionFilter descriptionFilter = getController().getQuickHideFilters().stream()
.filter(testFilter::equals)
.findFirst().orElseGet(() -> {
testFilter.selectedProperty().addListener((Observable observable) -> {
requestChartLayout();
});
testFilter.selectedProperty().addListener(observable -> requestChartLayout());
getController().getQuickHideFilters().add(testFilter);
return testFilter;
});

View File

@ -42,7 +42,7 @@ import static org.sleuthkit.autopsy.timeline.ui.detailview.EventBundleNodeBase.c
final public class EventStripeNode extends EventBundleNodeBase<EventStripe, EventCluster, EventClusterNode> {
private static final Logger LOGGER = Logger.getLogger(EventStripeNode.class.getName());
final Button hideButton;
private Button hideButton;
/**
* Pane that contains EventStripeNodes for any 'subevents' if they are
* displayed
@ -53,16 +53,22 @@ final public class EventStripeNode extends EventBundleNodeBase<EventStripe, Even
// private final HBox clustersHBox = new HBox();
private final ImageView eventTypeImageView = new ImageView();
@Override
void installActionButtons() {
if (hideButton == null) {
hideButton = ActionUtils.createButton(chart.new HideDescriptionAction(getDescription(), eventBundle.getDescriptionLoD()),
ActionUtils.ActionTextBehavior.HIDE);
configureLoDButton(hideButton);
infoHBox.getChildren().add(hideButton);
}
}
public EventStripeNode(EventDetailsChart chart, EventStripe eventStripe, EventClusterNode parentNode) {
super(chart, eventStripe, parentNode);
setMinHeight(48);
EventDetailsChart.HideDescriptionAction hideClusterAction = chart.new HideDescriptionAction(getDescription(), eventBundle.getDescriptionLoD());
hideButton = ActionUtils.createButton(hideClusterAction, ActionUtils.ActionTextBehavior.HIDE);
configureLoDButton(hideButton);
infoHBox.getChildren().add(hideButton);
//setup description label
eventTypeImageView.setImage(getEventType().getFXImage());
descrLabel.setPrefWidth(USE_COMPUTED_SIZE);
@ -83,6 +89,7 @@ final public class EventStripeNode extends EventBundleNodeBase<EventStripe, Even
@Override
void showHoverControls(final boolean showControls) {
super.showHoverControls(showControls);
installActionButtons();
show(hideButton, showControls);
}
@ -178,5 +185,4 @@ final public class EventStripeNode extends EventBundleNodeBase<EventStripe, Even
}
}
}