Autopsy  4.19.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
EventsTree.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2013-18 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.timeline.ui.detailview.tree;
20 
21 import com.google.common.collect.ImmutableList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.Objects;
25 import javafx.beans.InvalidationListener;
26 import javafx.beans.Observable;
27 import javafx.beans.property.SimpleBooleanProperty;
28 import javafx.collections.FXCollections;
29 import javafx.collections.ListChangeListener;
30 import javafx.collections.ObservableList;
31 import javafx.fxml.FXML;
32 import javafx.scene.control.ComboBox;
33 import javafx.scene.control.Label;
34 import javafx.scene.control.ListCell;
35 import javafx.scene.control.SelectionMode;
36 import javafx.scene.control.Tooltip;
37 import javafx.scene.control.TreeCell;
38 import javafx.scene.control.TreeItem;
39 import javafx.scene.control.TreeView;
40 import javafx.scene.image.Image;
41 import javafx.scene.image.ImageView;
42 import javafx.scene.input.MouseButton;
43 import javafx.scene.input.MouseEvent;
44 import javafx.scene.layout.BorderPane;
45 import javafx.scene.layout.StackPane;
46 import javafx.scene.paint.Color;
47 import javafx.scene.shape.Rectangle;
48 import org.apache.commons.lang3.StringUtils;
49 import org.controlsfx.control.action.Action;
50 import org.controlsfx.control.action.ActionUtils;
51 import org.openide.util.NbBundle;
61 
67 final public class EventsTree extends BorderPane {
68 
70 
72 
73  @FXML
74  private TreeView<DetailViewEvent> eventsTree;
75 
76  @FXML
77  private Label eventsTreeLabel;
78 
79  @FXML
80  private ComboBox<TreeComparator> sortByBox;
81  private final ObservableList<DetailViewEvent> selectedEvents = FXCollections.observableArrayList();
82 
83  public EventsTree(TimeLineController controller) {
84  this.controller = controller;
85  FXMLConstructor.construct(this, "EventsTree.fxml"); // NON-NLS
86  }
87 
88  public void setDetailViewPane(DetailViewPane detailViewPane) {
89  this.detailViewPane = detailViewPane;
90 
91  detailViewPane.getAllNestedEvents().addListener((ListChangeListener.Change<? extends DetailViewEvent> change) -> {
92  //on jfx thread
93  while (change.next()) {
94  change.getRemoved().forEach(getRoot()::remove);
95  change.getAddedSubList().forEach(getRoot()::insert);
96  }
97  });
98 
99  setRoot();
100 
101  detailViewPane.getSelectedEvents().addListener((Observable observable) -> {
102  eventsTree.getSelectionModel().clearSelection();
103  detailViewPane.getSelectedEvents().forEach(event -> {
104  eventsTree.getSelectionModel().select(getRoot().findTreeItemForEvent(event));
105  });
106  });
107 
108  }
109 
110  private RootItem getRoot() {
111  return (RootItem) eventsTree.getRoot();
112  }
113 
115  private void setRoot() {
116  RootItem root = new RootItem(TreeComparator.Type.reversed().thenComparing(sortByBox.getSelectionModel().getSelectedItem()));
117  detailViewPane.getAllNestedEvents().forEach(root::insert);
118  eventsTree.setRoot(root);
119  }
120 
121  @FXML
122  @NbBundle.Messages("EventsTree.Label.text=Sort By:")
123  void initialize() {
124  assert sortByBox != null : "fx:id=\"sortByBox\" was not injected: check your FXML file 'NavPanel.fxml'."; // NON-NLS
125 
126  sortByBox.getItems().setAll(Arrays.asList(TreeComparator.Description, TreeComparator.Count));
127  sortByBox.getSelectionModel().select(TreeComparator.Description);
128  sortByBox.setCellFactory(listView -> new TreeComparatorCell());
129  sortByBox.setButtonCell(new TreeComparatorCell());
130  sortByBox.getSelectionModel().selectedItemProperty().addListener(selectedItemProperty -> {
131  getRoot().sort(TreeComparator.Type.reversed().thenComparing(sortByBox.getSelectionModel().getSelectedItem()), true);
132  });
133 
134  eventsTree.setShowRoot(false);
135  eventsTree.setCellFactory(treeView -> new EventTreeCell());
136  eventsTree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
137 
138  eventsTree.getSelectionModel().getSelectedItems().addListener((ListChangeListener.Change<? extends TreeItem<DetailViewEvent>> change) -> {
139  while (change.next()) {
140  change.getRemoved().stream()
141  .filter(Objects::nonNull)
142  .map(TreeItem<DetailViewEvent>::getValue)
143  .filter(Objects::nonNull)
144  .forEach(selectedEvents::remove);
145  change.getAddedSubList().stream()
146  .filter(Objects::nonNull)
147  .map(TreeItem<DetailViewEvent>::getValue)
148  .filter(Objects::nonNull)
149  .forEach(selectedEvents::add);
150  }
151  });
152 
153  eventsTreeLabel.setText(Bundle.EventsTree_Label_text());
154  }
155 
156  public ObservableList<DetailViewEvent> getSelectedEvents() {
157  return selectedEvents;
158  }
159 
164  private class EventTreeCell extends TreeCell<DetailViewEvent> {
165 
166  private static final double HIDDEN_MULTIPLIER = .6;
167  private final Rectangle rect = new Rectangle(24, 24);
168  private final ImageView imageView = new ImageView();
169  private InvalidationListener filterStateChangeListener;
170  private final SimpleBooleanProperty hidden = new SimpleBooleanProperty(false);
171 
172  EventTreeCell() {
173  rect.setArcHeight(5);
174  rect.setArcWidth(5);
175  rect.setStrokeWidth(2);
176  }
177 
178  @Override
179  protected void updateItem(DetailViewEvent item, boolean empty) {
180  super.updateItem(item, empty);
181  if (empty) {
182  setText(null);
183  setTooltip(null);
184  setGraphic(null);
185  deRegisterListeners(controller.getQuickHideFilters());
186  } else {
187  EventsTreeItem treeItem = (EventsTreeItem) getTreeItem();
188  String text = treeItem.getDisplayText();
189  setText(text);
190  setTooltip(new Tooltip(text));
191 
192  imageView.setImage(new Image(getImagePath(treeItem.getEventType())));
193  setGraphic(new StackPane(rect, imageView));
194  updateHiddenState(treeItem);
195  deRegisterListeners(controller.getQuickHideFilters());
196 
197  if (item != null) {
198  filterStateChangeListener = (filterState) -> updateHiddenState(treeItem);
199  controller.getQuickHideFilters().addListener((ListChangeListener.Change<? extends FilterState<DescriptionFilter>> listChange) -> {
200  while (listChange.next()) {
201  deRegisterListeners(listChange.getRemoved());
202  registerListeners(listChange.getAddedSubList(), item);
203  }
204  updateHiddenState(treeItem);
205  });
206  registerListeners(controller.getQuickHideFilters(), item);
207  setOnMouseClicked((MouseEvent event) -> {
208  if (event.getButton() == MouseButton.SECONDARY) {
209  Action action = hidden.get()
210  ? detailViewPane.newUnhideDescriptionAction(item.getDescription(), item.getDescriptionLevel())
211  : detailViewPane.newHideDescriptionAction(item.getDescription(), item.getDescriptionLevel());
212 
213  ActionUtils.createContextMenu(ImmutableList.of(action))
214  .show(this, event.getScreenX(), event.getScreenY());
215  }
216  });
217  } else {
218  setOnMouseClicked(null);
219  }
220  }
221  }
222 
223  private void registerListeners(Collection<? extends FilterState<DescriptionFilter>> filters, DetailViewEvent item) {
224  for (FilterState<DescriptionFilter> filter : filters) {
225  if (filter.getFilter().getDescription().equals(item.getDescription())) {
226  filter.activeProperty().addListener(filterStateChangeListener);
227  }
228  }
229  }
230 
231  private void deRegisterListeners(Collection<? extends FilterState<DescriptionFilter>> filters) {
232  if (Objects.nonNull(filterStateChangeListener)) {
233  for (FilterState<DescriptionFilter> filter : filters) {
234  filter.activeProperty().removeListener(filterStateChangeListener);
235  }
236  }
237  }
238 
239  private void updateHiddenState(EventsTreeItem treeItem) {
240  DetailViewEvent event = treeItem.getValue();
241  hidden.set(event != null && controller.getQuickHideFilters().stream().
243  .anyMatch(filter -> StringUtils.equalsIgnoreCase(filter.getFilter().getDescription(), event.getDescription())));
244  Color color = getColor(treeItem.getEventType());
245  if (hidden.get()) {
246  treeItem.setExpanded(false);
247  setTextFill(Color.gray(0, HIDDEN_MULTIPLIER));
248  imageView.setOpacity(HIDDEN_MULTIPLIER);
249  rect.setStroke(color.deriveColor(0, HIDDEN_MULTIPLIER, 1, HIDDEN_MULTIPLIER));
250  rect.setFill(color.deriveColor(0, HIDDEN_MULTIPLIER, HIDDEN_MULTIPLIER, 0.1));
251  } else {
252  setTextFill(Color.BLACK);
253  imageView.setOpacity(1);
254  rect.setStroke(color);
255  rect.setFill(color.deriveColor(0, 1, 1, 0.1));
256  }
257  }
258  }
259 
263  static private class TreeComparatorCell extends ListCell<TreeComparator> {
264 
265  @Override
266  protected void updateItem(TreeComparator item, boolean empty) {
267  super.updateItem(item, empty);
268  if (empty || item == null) {
269  setText(null);
270  } else {
271  setText(item.getDisplayName());
272  }
273  }
274  }
275 }
Action newUnhideDescriptionAction(String description, TimelineLevelOfDetail descriptionLoD)
void registerListeners(Collection<?extends FilterState< DescriptionFilter >> filters, DetailViewEvent item)
ObservableList< DetailViewEvent > getSelectedEvents()
void setDetailViewPane(DetailViewPane detailViewPane)
Definition: EventsTree.java:88
ObservableList< DescriptionFilterState > getQuickHideFilters()
Action newHideDescriptionAction(String description, TimelineLevelOfDetail descriptionLoD)
static String getImagePath(TimelineEventType type)
void deRegisterListeners(Collection<?extends FilterState< DescriptionFilter >> filters)
final ObservableList< DetailViewEvent > selectedEvents
Definition: EventsTree.java:81
static void construct(Node node, String fxmlFileName)
static Color getColor(TimelineEventType type)

Copyright © 2012-2021 Basis Technology. Generated on: Thu Sep 30 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.