19 package org.sleuthkit.autopsy.timeline.ui.detailview;
 
   21 import java.util.List;
 
   22 import java.util.concurrent.ExecutionException;
 
   23 import java.util.stream.Collectors;
 
   24 import javafx.application.Platform;
 
   25 import javafx.beans.property.SimpleObjectProperty;
 
   26 import javafx.event.EventHandler;
 
   27 import javafx.geometry.Insets;
 
   28 import javafx.geometry.Pos;
 
   29 import javafx.scene.Cursor;
 
   30 import javafx.scene.control.Button;
 
   31 import javafx.scene.control.ContextMenu;
 
   32 import javafx.scene.control.Label;
 
   33 import javafx.scene.control.OverrunStyle;
 
   34 import javafx.scene.control.Tooltip;
 
   35 import javafx.scene.effect.DropShadow;
 
   36 import javafx.scene.image.Image;
 
   37 import javafx.scene.image.ImageView;
 
   38 import javafx.scene.input.MouseButton;
 
   39 import javafx.scene.input.MouseEvent;
 
   40 import javafx.scene.layout.Background;
 
   41 import javafx.scene.layout.BackgroundFill;
 
   42 import javafx.scene.layout.Border;
 
   43 import javafx.scene.layout.BorderPane;
 
   44 import javafx.scene.layout.BorderStroke;
 
   45 import javafx.scene.layout.BorderStrokeStyle;
 
   46 import javafx.scene.layout.BorderWidths;
 
   47 import javafx.scene.layout.CornerRadii;
 
   48 import javafx.scene.layout.HBox;
 
   49 import javafx.scene.layout.Pane;
 
   50 import javafx.scene.layout.Priority;
 
   51 import javafx.scene.layout.Region;
 
   52 import javafx.scene.layout.StackPane;
 
   53 import javafx.scene.paint.Color;
 
   54 import org.apache.commons.lang3.StringUtils;
 
   55 import org.joda.time.DateTime;
 
   56 import org.joda.time.Interval;
 
   57 import org.openide.util.Exceptions;
 
   58 import org.openide.util.NbBundle;
 
   72     private final static Image 
PLUS = 
new Image(
"/org/sleuthkit/autopsy/timeline/images/plus-button.png"); 
 
   73     private final static Image 
MINUS = 
new Image(
"/org/sleuthkit/autopsy/timeline/images/minus-button.png"); 
 
   75     private static final CornerRadii 
CORNER_RADII = 
new CornerRadii(3);
 
   78     private static final Border 
selectionBorder = 
new Border(
new BorderStroke(Color.BLACK, BorderStrokeStyle.SOLID, CORNER_RADII, 
new BorderWidths(2)));
 
  109     private final SimpleObjectProperty<ContextMenu> 
contextMenu = 
new SimpleObjectProperty<>();
 
  115     private final Button 
plusButton = 
new Button(null, 
new ImageView(PLUS)) {
 
  122     private final Button 
minusButton = 
new Button(null, 
new ImageView(MINUS)) {
 
  131     private SimpleObjectProperty<DescriptionLOD> 
descLOD = 
new SimpleObjectProperty<>();
 
  136         descLOD.set(event.
getLOD());
 
  139         final Region region = 
new Region();
 
  140         HBox.setHgrow(region, Priority.ALWAYS);
 
  141         final HBox hBox = 
new HBox(descrLabel, countLabel, region, minusButton, plusButton);
 
  142         hBox.setPrefWidth(USE_COMPUTED_SIZE);
 
  143         hBox.setMinWidth(USE_PREF_SIZE);
 
  144         hBox.setPadding(
new Insets(2, 5, 2, 5));
 
  145         hBox.setAlignment(Pos.CENTER_LEFT);
 
  147         minusButton.setVisible(
false);
 
  148         plusButton.setVisible(
false);
 
  149         minusButton.setManaged(
false);
 
  150         plusButton.setManaged(
false);
 
  151         final BorderPane borderPane = 
new BorderPane(subNodePane, hBox, null, null, null);
 
  152         BorderPane.setAlignment(subNodePane, Pos.TOP_LEFT);
 
  153         borderPane.setPrefWidth(USE_COMPUTED_SIZE);
 
  155         getChildren().addAll(spanRegion, borderPane);
 
  157         setAlignment(Pos.TOP_LEFT);
 
  159         minWidthProperty().bind(spanRegion.widthProperty());
 
  160         setPrefHeight(USE_COMPUTED_SIZE);
 
  161         setMaxHeight(USE_PREF_SIZE);
 
  164         subNodePane.setPrefHeight(USE_COMPUTED_SIZE);
 
  165         subNodePane.setMinHeight(USE_PREF_SIZE);
 
  166         subNodePane.setMinWidth(USE_PREF_SIZE);
 
  167         subNodePane.setMaxHeight(USE_PREF_SIZE);
 
  168         subNodePane.setMaxWidth(USE_PREF_SIZE);
 
  169         subNodePane.setPickOnBounds(
false);
 
  173         descrLabel.setGraphic(eventTypeImageView);
 
  174         descrLabel.setPrefWidth(USE_COMPUTED_SIZE);
 
  175         descrLabel.setTextOverrun(OverrunStyle.CENTER_ELLIPSIS);
 
  177         descrLabel.setMouseTransparent(
true);
 
  178         setDescriptionVisibility(chart.getDescrVisibility().get());
 
  181         final Color evtColor = 
event.getType().getColor();
 
  182         spanFill = 
new Background(
new BackgroundFill(evtColor.deriveColor(0, 1, 1, .1), 
CORNER_RADII, Insets.EMPTY));
 
  183         setBackground(
new Background(
new BackgroundFill(evtColor.deriveColor(0, 1, 1, .1), 
CORNER_RADII, Insets.EMPTY)));
 
  184         setCursor(Cursor.HAND);
 
  185         spanRegion.setStyle(
"-fx-border-width:2 0 2 2; -fx-border-radius: 2; -fx-border-color: " + 
ColorUtilities.
getRGBCode(evtColor) + 
";"); 
 
  186         spanRegion.setBackground(spanFill);
 
  189         setOnMouseEntered((MouseEvent e) -> {
 
  192             spanRegion.setEffect(
new DropShadow(10, evtColor));
 
  193             minusButton.setVisible(
true);
 
  194             plusButton.setVisible(
true);
 
  195             minusButton.setManaged(
true);
 
  196             plusButton.setManaged(
true);
 
  201         setOnMouseExited((MouseEvent e) -> {
 
  202             spanRegion.setEffect(null);
 
  203             minusButton.setVisible(
false);
 
  204             plusButton.setVisible(
false);
 
  205             minusButton.setManaged(
false);
 
  206             plusButton.setManaged(
false);
 
  213         minusButton.disableProperty().bind(descLOD.isEqualTo(event.
getLOD()));
 
  215         plusButton.setOnMouseClicked(e -> {
 
  222         minusButton.setOnMouseClicked(e -> {
 
  224             if (previous != null) {
 
  226                 descLOD.set(previous);
 
  233                 NbBundle.getMessage(
this.getClass(), 
"AggregateEventNode.installTooltip.text",
 
  254         spanRegion.setPrefWidth(w);
 
  255         spanRegion.setMaxWidth(w);
 
  256         spanRegion.setMinWidth(Math.max(2, w));
 
  264         descrLabel.setMaxWidth(w);
 
  268     final void setDescriptionVisibility(DescriptionVisibility descrVis) {
 
  270         final int size = 
event.getEventIDs().size();
 
  275                 descrLabel.setText(
"");
 
  276                 countLabel.setText(String.valueOf(size));
 
  279                 countLabel.setText(
"");
 
  280                 descrLabel.setText(
"");
 
  284                 String description = 
event.getDescription();
 
  285                 description = parentEventNode != null
 
  288                 descrLabel.setText(description);
 
  289                 countLabel.setText(((size == 1) ? 
"" : 
" (" + size + 
")")); 
 
  298     void applySelectionEffect(
final boolean applied) {
 
  299         Platform.runLater(() -> {
 
  301                 setBorder(selectionBorder);
 
  312     void applyHighlightEffect(
boolean applied) {
 
  315             descrLabel.setStyle(
"-fx-font-weight: bold;"); 
 
  316             spanFill = 
new Background(
new BackgroundFill(
getEvent().getType().getColor().deriveColor(0, 1, 1, .3), CORNER_RADII, Insets.EMPTY));
 
  317             spanRegion.setBackground(spanFill);
 
  318             setBackground(
new Background(
new BackgroundFill(
getEvent().getType().getColor().deriveColor(0, 1, 1, .2), CORNER_RADII, Insets.EMPTY)));
 
  320             descrLabel.setStyle(
"-fx-font-weight: normal;"); 
 
  321             spanFill = 
new Background(
new BackgroundFill(
getEvent().getType().getColor().deriveColor(0, 1, 1, .1), CORNER_RADII, Insets.EMPTY));
 
  322             spanRegion.setBackground(spanFill);
 
  323             setBackground(
new Background(
new BackgroundFill(
getEvent().getType().getColor().deriveColor(0, 1, 1, .1), CORNER_RADII, Insets.EMPTY)));
 
  327     String getDisplayedDescription() {
 
  328         return descrLabel.getText();
 
  331     double getLayoutXCompensation() {
 
  332         return (parentEventNode != null ? parentEventNode.getLayoutXCompensation() : 0)
 
  333                 + getBoundsInParent().getMinX();
 
  340         return contextMenu.get();
 
  347         this.contextMenu.set(contextMenu);
 
  357         if (newLOD == event.
getLOD()) {
 
  359             chart.setRequiresLayout(
true);
 
  368             final Interval span = 
event.getSpan().withEndMillis(event.
getSpan().getEndMillis() + 1000);
 
  372                     NbBundle.getMessage(this.getClass(), 
"AggregateEventNode.loggedTask.name"), 
true) {
 
  375                 protected List<AggregateEventNode> call() 
throws Exception {
 
  384                         subNode.setLayoutX(chart.getXAxis().getDisplayPosition(
new DateTime(t.
getSpan().getStartMillis())) - getLayoutXCompensation());
 
  386                     }).collect(Collectors.toList()); 
 
  390                 protected void succeeded() {
 
  392                         chart.setCursor(Cursor.WAIT);
 
  395                         setDescriptionVisibility(descrVis);
 
  396                         chart.setRequiresLayout(
true);
 
  398                         chart.setCursor(null);
 
  399                     } 
catch (InterruptedException | ExecutionException ex) {
 
  400                         Exceptions.printStackTrace(ex);
 
  415             if (t.getButton() == MouseButton.PRIMARY) {
 
  417                 if (t.isShiftDown()) {
 
  421                 } 
else if (t.isShortcutDown()) {
 
  423                 } 
else if (t.getClickCount() > 1) {
 
void setDescriptionWidth(double w)
 
static String getRGBCode(Color color)
 
List< AggregateEvent > getAggregatedEvents()
 
void setContextMenu(ContextMenu contextMenu)
 
void requestChartLayout()
 
static IntersectionFilter intersect(ObservableList< Filter > filters)
 
synchronized ReadOnlyObjectProperty< Filter > filter()
 
TimeLineController getController()
 
final ImageView eventTypeImageView
 
final EventDetailChart chart
 
final AggregateEvent event
 
DescriptionLOD previous()
 
final SimpleObjectProperty< ContextMenu > contextMenu
 
ContextMenu getContextMenu()
 
FilteredEventsModel getFilteredEvents()
 
synchronized void monitorTask(final Task<?> task)
 
DescriptionVisibility descrVis
 
final AggregateEventNode parentEventNode
 
void handle(MouseEvent t)
 
void setSpanWidth(double w)
 
void loadSubClusters(DescriptionLOD newLOD)
 
AggregateEventNode(final AggregateEvent event, AggregateEventNode parentEventNode, EventDetailChart chart)
 
SimpleObjectProperty< DescriptionLOD > descLOD
 
static final Border selectionBorder
 
synchronized ReadOnlyObjectProperty< EventTypeZoomLevel > eventTypeZoom()
 
AggregateEvent getEvent()
 
Set< Long > getEventIDs()
 
static final CornerRadii CORNER_RADII
 
static DateTimeFormatter getZonedFormatter()