mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 10:17:41 +00:00
more cleanup and simplification of code for only new style clustering
This commit is contained in:
parent
41110ae0b5
commit
eb0c72b43a
@ -15,7 +15,6 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import org.joda.time.DateTime;
|
||||
import org.python.google.common.base.Objects;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
||||
import org.sleuthkit.autopsy.timeline.zooming.DescriptionLOD;
|
||||
@ -141,13 +140,4 @@ public final class EventStripe implements EventBundle {
|
||||
public Iterable<Range<Long>> getRanges() {
|
||||
return spans.asRanges();
|
||||
}
|
||||
|
||||
public DateTime getEnd() {
|
||||
return spanMap.get(getStartMillis()).getSpan().getStart();
|
||||
}
|
||||
|
||||
public DateTime getStart() {
|
||||
return spanMap.get(getEndMillis()).getSpan().getStart();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
Timeline.ui.detailview.tooltip.text={0}\nRight-click to remove.\nRight-drag to reposition.
|
||||
AggregateEventNode.installTooltip.text={0} {1} events\n{2}\nbetween\t{3}\nand \t{4}
|
||||
AggregateEventNode.loggedTask.name=Load sub events
|
||||
DetailViewPane.loggedTask.name=Update Details
|
||||
DetailViewPane.loggedTask.preparing=preparing
|
||||
DetailViewPane.loggedTask.queryDb=querying db
|
||||
|
@ -150,11 +150,11 @@ public class DetailViewPane extends AbstractVisualization<DateTime, EventCluster
|
||||
|
||||
highlightedNodes.addListener((ListChangeListener.Change<? extends EventStripeNode> change) -> {
|
||||
while (change.next()) {
|
||||
change.getAddedSubList().forEach(aeNode -> {
|
||||
aeNode.applyHighlightEffect(true);
|
||||
change.getAddedSubList().forEach(node -> {
|
||||
node.applyHighlightEffect(true);
|
||||
});
|
||||
change.getRemoved().forEach(aeNode -> {
|
||||
aeNode.applyHighlightEffect(false);
|
||||
change.getRemoved().forEach(node -> {
|
||||
node.applyHighlightEffect(false);
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -357,7 +357,7 @@ public class DetailViewPane extends AbstractVisualization<DateTime, EventCluster
|
||||
|
||||
@Override
|
||||
protected void applySelectionEffect(EventStripeNode c1, Boolean selected) {
|
||||
chart.applySelectionEffect(c1, selected);
|
||||
c1.applySelectionEffect(selected);
|
||||
}
|
||||
|
||||
private class DetailViewSettingsPane extends HBox {
|
||||
@ -478,7 +478,5 @@ public class DetailViewPane extends AbstractVisualization<DateTime, EventCluster
|
||||
hiddenRadioMenuItem.setText(NbBundle.getMessage(this.getClass(), "DetailViewPane.hiddenRadioMenuItem.text"));
|
||||
hiddenRadio.setText(NbBundle.getMessage(this.getClass(), "DetailViewPane.hiddenRadio.text"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -732,8 +732,4 @@ public final class EventDetailChart extends XYChart<DateTime, EventCluster> impl
|
||||
protected void requestChartLayout() {
|
||||
super.requestChartLayout();
|
||||
}
|
||||
|
||||
void applySelectionEffect(EventStripeNode c1, Boolean selected) {
|
||||
c1.applySelectionEffect(selected);
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,33 @@
|
||||
/*
|
||||
* 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.
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.timeline.ui.detailview;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import static java.util.Objects.nonNull;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Insets;
|
||||
@ -44,33 +54,23 @@ import javafx.scene.layout.BorderWidths;
|
||||
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;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.controlsfx.control.action.Action;
|
||||
import org.controlsfx.control.action.ActionUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Interval;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.ColorUtilities;
|
||||
import org.sleuthkit.autopsy.coreutils.LoggedTask;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.timeline.TimeLineController;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.EventCluster;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.EventStripe;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.TimeLineEvent;
|
||||
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
|
||||
import org.sleuthkit.autopsy.timeline.filters.DescriptionFilter;
|
||||
import org.sleuthkit.autopsy.timeline.filters.RootFilter;
|
||||
import org.sleuthkit.autopsy.timeline.filters.TypeFilter;
|
||||
import org.sleuthkit.autopsy.timeline.zooming.DescriptionLOD;
|
||||
import org.sleuthkit.autopsy.timeline.zooming.EventTypeZoomLevel;
|
||||
import org.sleuthkit.autopsy.timeline.zooming.ZoomParams;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
@ -79,9 +79,77 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
*/
|
||||
final public class EventStripeNode extends StackPane {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(EventStripeNode.class.getName());
|
||||
private static final Image HASH_PIN = new Image("/org/sleuthkit/autopsy/images/hashset_hits.png"); //NOI18N
|
||||
private static final Image PLUS = new Image("/org/sleuthkit/autopsy/timeline/images/plus-button.png"); // NON-NLS //NOI18N
|
||||
private static final Image MINUS = new Image("/org/sleuthkit/autopsy/timeline/images/minus-button.png"); // NON-NLS //NOI18N
|
||||
private static final Image TAG = new Image("/org/sleuthkit/autopsy/images/green-tag-icon-16.png"); // NON-NLS //NOI18N
|
||||
|
||||
private static final CornerRadii CORNER_RADII = new CornerRadii(3);
|
||||
|
||||
/**
|
||||
* the border to apply when this node is selected
|
||||
*/
|
||||
private static final Border SELECTION_BORDER = new Border(new BorderStroke(Color.BLACK, BorderStrokeStyle.SOLID, CORNER_RADII, new BorderWidths(2)));
|
||||
|
||||
static void configureLoDButton(Button b) {
|
||||
b.setMinSize(16, 16);
|
||||
b.setMaxSize(16, 16);
|
||||
b.setPrefSize(16, 16);
|
||||
show(b, false);
|
||||
}
|
||||
|
||||
static void show(Node b, boolean show) {
|
||||
b.setVisible(show);
|
||||
b.setManaged(show);
|
||||
}
|
||||
|
||||
private final HBox rangesHBox = new HBox();
|
||||
private final EventStripe eventStripe;
|
||||
private Tooltip tooltip;
|
||||
private final Map<EventType, DropShadow> dropShadowMap = new HashMap<>();
|
||||
final Color evtColor;
|
||||
|
||||
private final EventStripeNode parentNode;
|
||||
private DescriptionVisibility descrVis;
|
||||
|
||||
/**
|
||||
* Pane that contains AggregateEventNodes of any 'subevents' if they are
|
||||
* displayed
|
||||
*
|
||||
* //TODO: move more of the control of subnodes/events here and out of
|
||||
* EventDetail Chart
|
||||
*/
|
||||
private final Pane subNodePane = new Pane();
|
||||
|
||||
/**
|
||||
* The ImageView used to show the icon for this node's event's type
|
||||
*/
|
||||
private final ImageView eventTypeImageView = new ImageView();
|
||||
|
||||
/**
|
||||
* The label used to display this node's event's description
|
||||
*/
|
||||
final Label descrLabel = new Label();
|
||||
|
||||
/**
|
||||
* The label used to display this node's event count
|
||||
*/
|
||||
final Label countLabel = new Label();
|
||||
|
||||
private final EventDetailChart chart;
|
||||
private final SleuthkitCase sleuthkitCase;
|
||||
|
||||
private final FilteredEventsModel eventsModel;
|
||||
|
||||
private final Button plusButton;
|
||||
private final Button minusButton;
|
||||
|
||||
private final SimpleObjectProperty<DescriptionLOD> descLOD = new SimpleObjectProperty<>();
|
||||
final HBox header;
|
||||
|
||||
private final CollapseClusterAction collapseClusterAction;
|
||||
private final ExpandClusterAction expandClusterAction;
|
||||
|
||||
public EventStripeNode(EventDetailChart chart, EventStripe eventStripe, EventStripeNode parentEventNode) {
|
||||
this.eventStripe = eventStripe;
|
||||
@ -101,14 +169,13 @@ final public class EventStripeNode extends StackPane {
|
||||
|
||||
expandClusterAction = new ExpandClusterAction();
|
||||
plusButton = ActionUtils.createButton(expandClusterAction, ActionUtils.ActionTextBehavior.HIDE);
|
||||
configureLODButton(plusButton);
|
||||
configureLoDButton(plusButton);
|
||||
|
||||
collapseClusterAction = new CollapseClusterAction();
|
||||
minusButton = ActionUtils.createButton(collapseClusterAction, ActionUtils.ActionTextBehavior.HIDE);
|
||||
configureLODButton(minusButton);
|
||||
configureLoDButton(minusButton);
|
||||
|
||||
HBox.setHgrow(spacer, Priority.ALWAYS);
|
||||
header = new HBox(getDescrLabel(), getCountLabel(), hashIV, tagIV, minusButton, plusButton);
|
||||
header = new HBox(5, descrLabel, countLabel, hashIV, tagIV, minusButton, plusButton);
|
||||
|
||||
header.setMinWidth(USE_PREF_SIZE);
|
||||
header.setPadding(new Insets(2, 5, 2, 5));
|
||||
@ -134,7 +201,7 @@ final public class EventStripeNode extends StackPane {
|
||||
setMinHeight(24);
|
||||
setPrefHeight(USE_COMPUTED_SIZE);
|
||||
setMaxHeight(USE_PREF_SIZE);
|
||||
setOnMouseClicked(new EventMouseHandler());
|
||||
setOnMouseClicked(new MouseHandler());
|
||||
|
||||
//set up mouse hover effect and tooltip
|
||||
setOnMouseEntered((MouseEvent e) -> {
|
||||
@ -151,10 +218,10 @@ final public class EventStripeNode extends StackPane {
|
||||
|
||||
setBackground(new Background(new BackgroundFill(evtColor.deriveColor(0, 1, 1, .1), CORNER_RADII, Insets.EMPTY)));
|
||||
|
||||
setLayoutX(getChart().getXAxis().getDisplayPosition(new DateTime(eventStripe.getStartMillis())) - getLayoutXCompensation());
|
||||
setLayoutX(chart.getXAxis().getDisplayPosition(new DateTime(eventStripe.getStartMillis())) - getLayoutXCompensation());
|
||||
|
||||
minWidthProperty().bind(rangesHBox.widthProperty());
|
||||
final VBox internalVBox = new VBox(header, getSubNodePane());
|
||||
final VBox internalVBox = new VBox(header, subNodePane);
|
||||
internalVBox.setAlignment(Pos.CENTER_LEFT);
|
||||
|
||||
for (Range<Long> range : eventStripe.getRanges()) {
|
||||
@ -176,10 +243,9 @@ final public class EventStripeNode extends StackPane {
|
||||
void showDescriptionLoDControls(final boolean showControls) {
|
||||
DropShadow dropShadow = dropShadowMap.computeIfAbsent(getEventType(),
|
||||
eventType -> new DropShadow(10, eventType.getColor()));
|
||||
getSpanFillNode().setEffect(showControls ? dropShadow : null);
|
||||
rangesHBox.setEffect(showControls ? dropShadow : null);
|
||||
show(minusButton, showControls);
|
||||
show(plusButton, showControls);
|
||||
show(getSpacer(), showControls);
|
||||
}
|
||||
|
||||
public void setSpanWidths(List<Double> spanWidths) {
|
||||
@ -196,93 +262,73 @@ final public class EventStripeNode extends StackPane {
|
||||
return eventStripe;
|
||||
}
|
||||
|
||||
HBox getSpanFillNode() {
|
||||
return rangesHBox;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param showSpans the value of showSpans
|
||||
*/
|
||||
void showSpans(final boolean showSpans) {
|
||||
rangesHBox.setVisible(showSpans);
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"# {0} - counts",
|
||||
"# {1} - event type",
|
||||
"# {2} - description",
|
||||
"# {3} - start date/time",
|
||||
"# {4} - end date/time",
|
||||
"EventStripeNode.tooltip.text={0} {1} events\n{2}\nbetween\t{3}\nand \t{4}"})
|
||||
synchronized void installTooltip() {
|
||||
//TODO: all this work should probably go on a background thread...
|
||||
if (tooltip == null) {
|
||||
HashMap<String, Long> hashSetCounts = new HashMap<>();
|
||||
if (!getStripe().getEventIDsWithHashHits().isEmpty()) {
|
||||
hashSetCounts = new HashMap<>();
|
||||
try {
|
||||
for (TimeLineEvent tle : getEventsModel().getEventsById(getStripe().getEventIDsWithHashHits())) {
|
||||
Set<String> hashSetNames = getSleuthkitCase().getAbstractFileById(tle.getFileID()).getHashSetNames();
|
||||
for (String hashSetName : hashSetNames) {
|
||||
hashSetCounts.merge(hashSetName, 1L, Long::sum);
|
||||
Task<String> tooltTipTask = new Task<String>() {
|
||||
|
||||
@Override
|
||||
protected String call() throws Exception {
|
||||
HashMap<String, Long> hashSetCounts = new HashMap<>();
|
||||
if (!getStripe().getEventIDsWithHashHits().isEmpty()) {
|
||||
hashSetCounts = new HashMap<>();
|
||||
try {
|
||||
for (TimeLineEvent tle : eventsModel.getEventsById(getStripe().getEventIDsWithHashHits())) {
|
||||
Set<String> hashSetNames = sleuthkitCase.getAbstractFileById(tle.getFileID()).getHashSetNames();
|
||||
for (String hashSetName : hashSetNames) {
|
||||
hashSetCounts.merge(hashSetName, 1L, Long::sum);
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error getting hashset hit info for event.", ex);
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error getting hashset hit info for event.", ex);
|
||||
|
||||
Map<String, Long> tagCounts = new HashMap<>();
|
||||
if (getEventStripe().getEventIDsWithTags().isEmpty() == false) {
|
||||
tagCounts.putAll(eventsModel.getTagCountsByTagName(getEventStripe().getEventIDsWithTags()));
|
||||
}
|
||||
|
||||
String hashSetCountsString = hashSetCounts.entrySet().stream()
|
||||
.map((Map.Entry<String, Long> t) -> t.getKey() + " : " + t.getValue())
|
||||
.collect(Collectors.joining("\n"));
|
||||
String tagCountsString = tagCounts.entrySet().stream()
|
||||
.map((Map.Entry<String, Long> t) -> t.getKey() + " : " + t.getValue())
|
||||
.collect(Collectors.joining("\n"));
|
||||
return Bundle.EventStripeNode_tooltip_text(getEventStripe().getEventIDs().size(), getEventStripe().getEventType(), getEventStripe().getDescription(),
|
||||
TimeLineController.getZonedFormatter().print(getEventStripe().getStartMillis()),
|
||||
TimeLineController.getZonedFormatter().print(getEventStripe().getEndMillis() + 1000))
|
||||
+ (hashSetCountsString.isEmpty() ? "" : "\n\nHash Set Hits\n" + hashSetCountsString)
|
||||
+ (tagCountsString.isEmpty() ? "" : "\n\nTags\n" + tagCountsString);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Long> tagCounts = new HashMap<>();
|
||||
if (getEventStripe().getEventIDsWithTags().isEmpty() == false) {
|
||||
tagCounts.putAll(getEventsModel().getTagCountsByTagName(getEventStripe().getEventIDsWithTags()));
|
||||
}
|
||||
|
||||
String hashSetCountsString = hashSetCounts.entrySet().stream()
|
||||
.map((Map.Entry<String, Long> t) -> t.getKey() + " : " + t.getValue())
|
||||
.collect(Collectors.joining("\n"));
|
||||
String tagCountsString = tagCounts.entrySet().stream()
|
||||
.map((Map.Entry<String, Long> t) -> t.getKey() + " : " + t.getValue())
|
||||
.collect(Collectors.joining("\n"));
|
||||
|
||||
tooltip = new Tooltip(
|
||||
NbBundle.getMessage(this.getClass(), "AggregateEventNode.installTooltip.text",
|
||||
getEventStripe().getEventIDs().size(), getEventStripe().getEventType(), getEventStripe().getDescription(),
|
||||
getEventStripe().getStart().toString(TimeLineController.getZonedFormatter()),
|
||||
getEventStripe().getEnd().toString(TimeLineController.getZonedFormatter()))
|
||||
+ (hashSetCountsString.isEmpty() ? "" : "\n\nHash Set Hits\n" + hashSetCountsString)
|
||||
+ (tagCountsString.isEmpty() ? "" : "\n\nTags\n" + tagCountsString)
|
||||
);
|
||||
Tooltip.install(this, tooltip);
|
||||
@Override
|
||||
protected void succeeded() {
|
||||
super.succeeded();
|
||||
try {
|
||||
tooltip = new Tooltip(get());
|
||||
Tooltip.install(this, tooltip);
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Tooltip generation failed.", ex);
|
||||
Tooltip.uninstall(this, tooltip);
|
||||
tooltip = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
chart.getController().monitorTask(tooltTipTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EventStripeNode getNodeForBundle(EventStripe cluster) {
|
||||
return new EventStripeNode(getChart(), cluster, this);
|
||||
EventStripeNode getNodeForBundle(EventStripe cluster) {
|
||||
return new EventStripeNode(chart, cluster, this);
|
||||
}
|
||||
|
||||
static final Image HASH_PIN = new Image("/org/sleuthkit/autopsy/images/hashset_hits.png");
|
||||
static final Image PLUS = new Image("/org/sleuthkit/autopsy/timeline/images/plus-button.png"); // NON-NLS
|
||||
static final Image MINUS = new Image("/org/sleuthkit/autopsy/timeline/images/minus-button.png"); // NON-NLS
|
||||
static final Image TAG = new Image("/org/sleuthkit/autopsy/images/green-tag-icon-16.png"); // NON-NLS
|
||||
static final CornerRadii CORNER_RADII = new CornerRadii(3);
|
||||
/**
|
||||
* the border to apply when this node is 'selected'
|
||||
*/
|
||||
static final Border selectionBorder = new Border(new BorderStroke(Color.BLACK, BorderStrokeStyle.SOLID, CORNER_RADII, new BorderWidths(2)));
|
||||
private static final Logger LOGGER = Logger.getLogger(EventStripeNode.class
|
||||
.getName());
|
||||
|
||||
static void configureLODButton(Button b) {
|
||||
b.setMinSize(16, 16);
|
||||
b.setMaxSize(16, 16);
|
||||
b.setPrefSize(16, 16);
|
||||
show(b, false);
|
||||
}
|
||||
|
||||
static void show(Node b, boolean show) {
|
||||
b.setVisible(show);
|
||||
b.setManaged(show);
|
||||
}
|
||||
private final Map<EventType, DropShadow> dropShadowMap = new HashMap<>();
|
||||
final Color evtColor;
|
||||
|
||||
private final EventStripeNode parentNode;
|
||||
private DescriptionVisibility descrVis;
|
||||
|
||||
EventType getEventType() {
|
||||
return eventStripe.getEventType();
|
||||
}
|
||||
@ -295,83 +341,13 @@ final public class EventStripeNode extends StackPane {
|
||||
return eventStripe.getStartMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pane that contains AggregateEventNodes of any 'subevents' if they are
|
||||
* displayed
|
||||
*
|
||||
* //TODO: move more of the control of subnodes/events here and out of
|
||||
* EventDetail Chart
|
||||
*/
|
||||
private final Pane subNodePane = new Pane();
|
||||
|
||||
Pane getSubNodePane() {
|
||||
return subNodePane;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ImageView used to show the icon for this node's event's type
|
||||
*/
|
||||
private final ImageView eventTypeImageView = new ImageView();
|
||||
|
||||
/**
|
||||
* The label used to display this node's event's description
|
||||
*/
|
||||
final Label descrLabel = new Label();
|
||||
|
||||
/**
|
||||
* The label used to display this node's event count
|
||||
*/
|
||||
final Label countLabel = new Label();
|
||||
|
||||
private final EventDetailChart chart;
|
||||
private final SleuthkitCase sleuthkitCase;
|
||||
|
||||
SleuthkitCase getSleuthkitCase() {
|
||||
return sleuthkitCase;
|
||||
}
|
||||
|
||||
FilteredEventsModel getEventsModel() {
|
||||
return eventsModel;
|
||||
}
|
||||
private final FilteredEventsModel eventsModel;
|
||||
|
||||
private final Button plusButton;
|
||||
private final Button minusButton;
|
||||
|
||||
private final SimpleObjectProperty<DescriptionLOD> descLOD = new SimpleObjectProperty<>();
|
||||
final HBox header;
|
||||
|
||||
Region getSpacer() {
|
||||
return spacer;
|
||||
}
|
||||
|
||||
private final Region spacer = new Region();
|
||||
|
||||
private final CollapseClusterAction collapseClusterAction;
|
||||
private final ExpandClusterAction expandClusterAction;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<EventStripeNode> getSubNodes() {
|
||||
public List<EventStripeNode> getSubNodes() {
|
||||
return subNodePane.getChildrenUnmodifiable().stream()
|
||||
.map(t -> (EventStripeNode) t)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* apply the 'effect' to visually indicate selection
|
||||
*
|
||||
* @param applied true to apply the selection 'effect', false to remove it
|
||||
*/
|
||||
public void applySelectionEffect(boolean applied) {
|
||||
Platform.runLater(() -> {
|
||||
if (applied) {
|
||||
setBorder(selectionBorder);
|
||||
} else {
|
||||
setBorder(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* make a new filter intersecting the global filter with description and
|
||||
* type filters to restrict sub-clusters
|
||||
@ -389,7 +365,16 @@ final public class EventStripeNode extends StackPane {
|
||||
* @param w the maximum width the description label should have
|
||||
*/
|
||||
public void setDescriptionWidth(double w) {
|
||||
getDescrLabel().setMaxWidth(w);
|
||||
descrLabel.setMaxWidth(w);
|
||||
}
|
||||
|
||||
/**
|
||||
* apply the 'effect' to visually indicate selection
|
||||
*
|
||||
* @param applied true to apply the selection 'effect', false to remove it
|
||||
*/
|
||||
public void applySelectionEffect(boolean applied) {
|
||||
setBorder(applied ? SELECTION_BORDER : null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -399,45 +384,17 @@ final public class EventStripeNode extends StackPane {
|
||||
*/
|
||||
public synchronized void applyHighlightEffect(boolean applied) {
|
||||
if (applied) {
|
||||
getDescrLabel().setStyle("-fx-font-weight: bold;"); // NON-NLS
|
||||
getSpanFillNode().setBackground(new Background(new BackgroundFill(getEventType().getColor().deriveColor(0, 1, 1, .3), CORNER_RADII, Insets.EMPTY)));
|
||||
descrLabel.setStyle("-fx-font-weight: bold;"); // NON-NLS
|
||||
rangesHBox.setBackground(new Background(new BackgroundFill(getEventType().getColor().deriveColor(0, 1, 1, .3), CORNER_RADII, Insets.EMPTY)));
|
||||
setBackground(new Background(new BackgroundFill(getEventType().getColor().deriveColor(0, 1, 1, .2), CORNER_RADII, Insets.EMPTY)));
|
||||
} else {
|
||||
getDescrLabel().setStyle("-fx-font-weight: normal;"); // NON-NLS
|
||||
getSpanFillNode().setBackground(new Background(new BackgroundFill(getEventType().getColor().deriveColor(0, 1, 1, .1), CORNER_RADII, Insets.EMPTY)));
|
||||
descrLabel.setStyle("-fx-font-weight: normal;"); // NON-NLS
|
||||
rangesHBox.setBackground(new Background(new BackgroundFill(getEventType().getColor().deriveColor(0, 1, 1, .1), CORNER_RADII, Insets.EMPTY)));
|
||||
setBackground(new Background(new BackgroundFill(getEventType().getColor().deriveColor(0, 1, 1, .1), CORNER_RADII, Insets.EMPTY)));
|
||||
}
|
||||
}
|
||||
|
||||
String getDisplayedDescription() {
|
||||
return getDescrLabel().getText();
|
||||
}
|
||||
|
||||
Button getPlusButton() {
|
||||
return plusButton;
|
||||
}
|
||||
|
||||
Button getMinusButton() {
|
||||
return minusButton;
|
||||
}
|
||||
|
||||
public final Label getDescrLabel() {
|
||||
return descrLabel;
|
||||
}
|
||||
|
||||
final public Label getCountLabel() {
|
||||
return countLabel;
|
||||
}
|
||||
|
||||
public EventStripeNode getParentNode() {
|
||||
return parentNode;
|
||||
}
|
||||
|
||||
public final EventDetailChart getChart() {
|
||||
return chart;
|
||||
}
|
||||
|
||||
public DescriptionLOD getDescLOD() {
|
||||
private DescriptionLOD getDescriptionLoD() {
|
||||
return descLOD.get();
|
||||
}
|
||||
|
||||
@ -447,15 +404,16 @@ final public class EventStripeNode extends StackPane {
|
||||
* @param requestedDescrLoD
|
||||
* @param expand
|
||||
*/
|
||||
private synchronized void loadSubBundles(DescriptionLOD.RelativeDetail relativeDetail) {
|
||||
@NbBundle.Messages(value = "EventStripeNode.loggedTask.name=Load sub clusters")
|
||||
private synchronized void loadSubBundles(DescriptionLOD.RelativeDetail relativeDetail) {
|
||||
subNodePane.getChildren().clear();
|
||||
if (descLOD.get().withRelativeDetail(relativeDetail) == eventStripe.getDescriptionLOD()) {
|
||||
descLOD.set(eventStripe.getDescriptionLOD());
|
||||
showSpans(true);
|
||||
rangesHBox.setVisible(true);
|
||||
chart.setRequiresLayout(true);
|
||||
chart.requestChartLayout();
|
||||
} else {
|
||||
showSpans(false);
|
||||
rangesHBox.setVisible(false);
|
||||
|
||||
// make new ZoomParams to query with
|
||||
final RootFilter subClusterFilter = getSubClusterFilter();
|
||||
@ -466,16 +424,16 @@ final public class EventStripeNode extends StackPane {
|
||||
*/
|
||||
final Interval subClusterSpan = new Interval(eventStripe.getStartMillis(), eventStripe.getEndMillis() + 1000);
|
||||
final EventTypeZoomLevel eventTypeZoomLevel = eventsModel.eventTypeZoomProperty().get();
|
||||
final ZoomParams zoomParams = new ZoomParams(subClusterSpan, eventTypeZoomLevel, subClusterFilter, getDescLOD());
|
||||
final ZoomParams zoomParams = new ZoomParams(subClusterSpan, eventTypeZoomLevel, subClusterFilter, getDescriptionLoD());
|
||||
|
||||
LoggedTask<Set<EventStripeNode>> loggedTask = new LoggedTask<Set<EventStripeNode>>(
|
||||
NbBundle.getMessage(this.getClass(), "AggregateEventNode.loggedTask.name"), true) {
|
||||
EventStripeNode_loggedTask_name(), true) {
|
||||
private Collection<EventStripe> bundles;
|
||||
private volatile DescriptionLOD loadedDescriptionLoD = getDescLOD().withRelativeDetail(relativeDetail);
|
||||
private volatile DescriptionLOD loadedDescriptionLoD = getDescriptionLoD().withRelativeDetail(relativeDetail);
|
||||
private DescriptionLOD next = loadedDescriptionLoD;
|
||||
|
||||
@Override
|
||||
protected Set<EventStripeNode> call() throws Exception {
|
||||
protected Set<EventStripeNode> call() throws Exception {
|
||||
do {
|
||||
loadedDescriptionLoD = next;
|
||||
if (loadedDescriptionLoD == eventStripe.getDescriptionLOD()) {
|
||||
@ -497,14 +455,14 @@ final public class EventStripeNode extends StackPane {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void succeeded() {
|
||||
protected void succeeded() {
|
||||
chart.setCursor(Cursor.WAIT);
|
||||
try {
|
||||
Set<EventStripeNode> subBundleNodes = get();
|
||||
if (subBundleNodes.isEmpty()) {
|
||||
showSpans(true);
|
||||
rangesHBox.setVisible(true);
|
||||
} else {
|
||||
showSpans(false);
|
||||
rangesHBox.setVisible(false);
|
||||
}
|
||||
descLOD.set(loadedDescriptionLoD);
|
||||
//assign subNodes and request chart layout
|
||||
@ -523,8 +481,8 @@ final public class EventStripeNode extends StackPane {
|
||||
}
|
||||
}
|
||||
|
||||
double getLayoutXCompensation() {
|
||||
return (getParentNode() != null ? getParentNode().getLayoutXCompensation() : 0)
|
||||
private double getLayoutXCompensation() {
|
||||
return (parentNode != null ? parentNode.getLayoutXCompensation() : 0)
|
||||
+ getBoundsInParent().getMinX();
|
||||
}
|
||||
|
||||
@ -533,19 +491,19 @@ final public class EventStripeNode extends StackPane {
|
||||
final int size = eventStripe.getEventIDs().size();
|
||||
|
||||
switch (this.descrVis) {
|
||||
case COUNT_ONLY:
|
||||
descrLabel.setText("");
|
||||
countLabel.setText(String.valueOf(size));
|
||||
break;
|
||||
case HIDDEN:
|
||||
countLabel.setText("");
|
||||
descrLabel.setText("");
|
||||
break;
|
||||
case COUNT_ONLY:
|
||||
descrLabel.setText("");
|
||||
countLabel.setText(String.valueOf(size));
|
||||
break;
|
||||
default:
|
||||
case SHOWN:
|
||||
String description = eventStripe.getDescription();
|
||||
description = getParentNode() != null
|
||||
? " ..." + StringUtils.substringAfter(description, getParentNode().getDescription())
|
||||
description = parentNode != null
|
||||
? " ..." + StringUtils.substringAfter(description, parentNode.getDescription())
|
||||
: description;
|
||||
descrLabel.setText(description);
|
||||
countLabel.setText(((size == 1) ? "" : " (" + size + ")")); // NON-NLS
|
||||
@ -557,86 +515,118 @@ final public class EventStripeNode extends StackPane {
|
||||
return eventStripe;
|
||||
}
|
||||
|
||||
public Set<Long> getEventsIDs() {
|
||||
Set<Long> getEventsIDs() {
|
||||
return eventStripe.getEventIDs();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* event handler used for mouse events on {@link AggregateEventNode}s
|
||||
* event handler used for mouse events on {@link EventStripeNode}s
|
||||
*/
|
||||
private class EventMouseHandler implements EventHandler<MouseEvent> {
|
||||
private class MouseHandler implements EventHandler<MouseEvent> {
|
||||
|
||||
private ContextMenu contextMenu;
|
||||
private ContextMenu contextMenu;
|
||||
|
||||
@Override
|
||||
public void handle(MouseEvent t) {
|
||||
@Override
|
||||
public void handle(MouseEvent t) {
|
||||
|
||||
if (t.getButton() == MouseButton.PRIMARY) {
|
||||
t.consume();
|
||||
if (t.isShiftDown()) {
|
||||
if (chart.selectedNodes.contains(EventStripeNode.this) == false) {
|
||||
chart.selectedNodes.add(EventStripeNode.this);
|
||||
}
|
||||
} else if (t.isShortcutDown()) {
|
||||
chart.selectedNodes.removeAll(EventStripeNode.this);
|
||||
} else if (t.getClickCount() > 1) {
|
||||
final DescriptionLOD next = descLOD.get().moreDetailed();
|
||||
if (next != null) {
|
||||
loadSubBundles(DescriptionLOD.RelativeDetail.MORE);
|
||||
|
||||
}
|
||||
} else {
|
||||
chart.selectedNodes.setAll(EventStripeNode.this);
|
||||
if (t.getButton() == MouseButton.PRIMARY) {
|
||||
t.consume();
|
||||
if (t.isShiftDown()) {
|
||||
if (chart.selectedNodes.contains(EventStripeNode.this) == false) {
|
||||
chart.selectedNodes.add(EventStripeNode.this);
|
||||
}
|
||||
t.consume();
|
||||
} else if (t.getButton() == MouseButton.SECONDARY) {
|
||||
ContextMenu chartContextMenu = chart.getChartContextMenu(t);
|
||||
if (contextMenu == null) {
|
||||
contextMenu = new ContextMenu();
|
||||
contextMenu.setAutoHide(true);
|
||||
|
||||
contextMenu.getItems().add(ActionUtils.createMenuItem(expandClusterAction));
|
||||
contextMenu.getItems().add(ActionUtils.createMenuItem(collapseClusterAction));
|
||||
|
||||
contextMenu.getItems().add(new SeparatorMenuItem());
|
||||
contextMenu.getItems().addAll(chartContextMenu.getItems());
|
||||
}
|
||||
contextMenu.show(EventStripeNode.this, t.getScreenX(), t.getScreenY());
|
||||
t.consume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ExpandClusterAction extends Action {
|
||||
|
||||
ExpandClusterAction() {
|
||||
super("Expand");
|
||||
|
||||
setGraphic(new ImageView(PLUS));
|
||||
setEventHandler((ActionEvent t) -> {
|
||||
} else if (t.isShortcutDown()) {
|
||||
chart.selectedNodes.removeAll(EventStripeNode.this);
|
||||
} else if (t.getClickCount() > 1) {
|
||||
final DescriptionLOD next = descLOD.get().moreDetailed();
|
||||
if (next != null) {
|
||||
loadSubBundles(DescriptionLOD.RelativeDetail.MORE);
|
||||
|
||||
}
|
||||
});
|
||||
disabledProperty().bind(descLOD.isEqualTo(DescriptionLOD.FULL));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
chart.selectedNodes.setAll(EventStripeNode.this);
|
||||
}
|
||||
t.consume();
|
||||
} else if (t.getButton() == MouseButton.SECONDARY) {
|
||||
ContextMenu chartContextMenu = chart.getChartContextMenu(t);
|
||||
if (contextMenu == null) {
|
||||
contextMenu = new ContextMenu();
|
||||
contextMenu.setAutoHide(true);
|
||||
|
||||
private class CollapseClusterAction extends Action {
|
||||
contextMenu.getItems().add(ActionUtils.createMenuItem(expandClusterAction));
|
||||
contextMenu.getItems().add(ActionUtils.createMenuItem(collapseClusterAction));
|
||||
|
||||
CollapseClusterAction() {
|
||||
super("Collapse");
|
||||
|
||||
setGraphic(new ImageView(MINUS));
|
||||
setEventHandler((ActionEvent t) -> {
|
||||
final DescriptionLOD previous = descLOD.get().lessDetailed();
|
||||
if (previous != null) {
|
||||
loadSubBundles(DescriptionLOD.RelativeDetail.LESS);
|
||||
}
|
||||
});
|
||||
disabledProperty().bind(descLOD.isEqualTo(eventStripe.getDescriptionLOD()));
|
||||
contextMenu.getItems().add(new SeparatorMenuItem());
|
||||
contextMenu.getItems().addAll(chartContextMenu.getItems());
|
||||
}
|
||||
contextMenu.show(EventStripeNode.this, t.getScreenX(), t.getScreenY());
|
||||
t.consume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ExpandClusterAction extends Action {
|
||||
|
||||
@NbBundle.Messages("ExpandClusterAction.text=Expand")
|
||||
ExpandClusterAction() {
|
||||
super(Bundle.ExpandClusterAction_text());
|
||||
|
||||
setGraphic(new ImageView(PLUS));
|
||||
setEventHandler((ActionEvent t) -> {
|
||||
final DescriptionLOD next = descLOD.get().moreDetailed();
|
||||
if (next != null) {
|
||||
loadSubBundles(DescriptionLOD.RelativeDetail.MORE);
|
||||
|
||||
}
|
||||
});
|
||||
disabledProperty().bind(descLOD.isEqualTo(DescriptionLOD.FULL));
|
||||
}
|
||||
}
|
||||
|
||||
private class CollapseClusterAction extends Action {
|
||||
|
||||
@NbBundle.Messages("CollapseClusterAction.text=Collapse")
|
||||
CollapseClusterAction() {
|
||||
super(Bundle.CollapseClusterAction_text());
|
||||
|
||||
setGraphic(new ImageView(MINUS));
|
||||
setEventHandler((ActionEvent t) -> {
|
||||
final DescriptionLOD previous = descLOD.get().lessDetailed();
|
||||
if (previous != null) {
|
||||
loadSubBundles(DescriptionLOD.RelativeDetail.LESS);
|
||||
}
|
||||
});
|
||||
disabledProperty().bind(descLOD.isEqualTo(eventStripe.getDescriptionLOD()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user