19 package org.sleuthkit.autopsy.timeline.ui.detailview.tree;
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.ListChangeListener;
29 import javafx.fxml.FXML;
30 import javafx.scene.control.ComboBox;
31 import javafx.scene.control.Label;
32 import javafx.scene.control.ListCell;
33 import javafx.scene.control.SelectionMode;
34 import javafx.scene.control.Tooltip;
35 import javafx.scene.control.TreeCell;
36 import javafx.scene.control.TreeItem;
37 import javafx.scene.control.TreeView;
38 import javafx.scene.image.ImageView;
39 import javafx.scene.input.MouseButton;
40 import javafx.scene.input.MouseEvent;
41 import javafx.scene.layout.BorderPane;
42 import javafx.scene.layout.StackPane;
43 import javafx.scene.paint.Color;
44 import javafx.scene.shape.Rectangle;
45 import org.apache.commons.lang3.StringUtils;
46 import org.controlsfx.control.action.ActionUtils;
47 import org.openide.util.NbBundle;
90 for (EventBundle<?> bundle : c.getAddedSubList()) {
91 getRoot().insert(bundle);
93 for (EventBundle<?> bundle : c.getRemoved()) {
94 getRoot().remove(bundle);
102 eventsTree.getSelectionModel().clearSelection();
104 eventsTree.getSelectionModel().select(
getRoot().findTreeItemForEvent(eventBundleNode.getEventBundle()));
111 return (RootItem) eventsTree.getRoot();
115 private
void setRoot() {
116 RootItem root =
new RootItem(TreeComparator.Type.reversed().thenComparing(sortByBox.getSelectionModel().getSelectedItem()));
120 eventsTree.setRoot(root);
125 @NbBundle.Messages(
"EventsTree.Label.text=Sort By:")
127 assert sortByBox != null :
"fx:id=\"sortByBox\" was not injected: check your FXML file 'NavPanel.fxml'.";
129 sortByBox.getItems().setAll(Arrays.asList(TreeComparator.Description, TreeComparator.Count));
130 sortByBox.getSelectionModel().select(TreeComparator.Description);
131 sortByBox.setCellFactory(listView ->
new TreeComparatorCell());
132 sortByBox.setButtonCell(
new TreeComparatorCell());
133 sortByBox.getSelectionModel().selectedItemProperty().addListener((Observable o) -> {
134 getRoot().resort(TreeComparator.Type.reversed().thenComparing(sortByBox.getSelectionModel().getSelectedItem()),
true);
136 eventsTree.setShowRoot(
false);
138 eventsTree.setCellFactory(treeView ->
new EventBundleTreeCell());
139 eventsTree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
141 eventsTreeLabel.setText(Bundle.EventsTree_Label_text());
150 private static final double HIDDEN_MULTIPLIER = .6;
151 private final Rectangle rect =
new Rectangle(24, 24);
152 private final ImageView imageView =
new ImageView();
154 SimpleBooleanProperty hidden =
new SimpleBooleanProperty(
false);
157 rect.setArcHeight(5);
159 rect.setStrokeWidth(2);
164 super.updateItem(item, empty);
165 if (item == null || empty) {
169 setContextMenu(null);
172 filterStateChangeListener = (filterState) -> updateHiddenState(item);
174 while (listChange.next()) {
175 deRegisterListeners(listChange.getRemoved());
176 registerListeners(listChange.getAddedSubList(), item);
178 updateHiddenState(item);
182 if (getTreeItem() instanceof EventTypeTreeItem) {
188 TreeItem<EventBundle<?>> parent = getTreeItem().getParent();
189 if (parent != null && parent.getValue() != null && (parent instanceof EventDescriptionTreeItem)) {
190 text = StringUtils.substringAfter(text, parent.getValue().getDescription());
194 setTooltip(
new Tooltip(text));
196 setGraphic(
new StackPane(rect, imageView));
197 updateHiddenState(item);
198 if (getTreeItem() instanceof EventDescriptionTreeItem) {
199 setOnMouseClicked((MouseEvent event) -> {
200 if (event.getButton() == MouseButton.SECONDARY) {
211 setOnMouseClicked(null);
219 filter.activeProperty().addListener(filterStateChangeListener);
225 if (Objects.nonNull(filterStateChangeListener)) {
227 filter.activeProperty().removeListener(filterStateChangeListener);
233 TreeItem<EventBundle<?>> treeItem = getTreeItem();
237 .anyMatch(filter -> filter.getDescription().equals(item.
getDescription())));
239 if (treeItem != null) {
240 treeItem.setExpanded(
false);
242 setTextFill(Color.gray(0, HIDDEN_MULTIPLIER));
243 imageView.setOpacity(HIDDEN_MULTIPLIER);
244 rect.setStroke(item.
getEventType().
getColor().deriveColor(0, HIDDEN_MULTIPLIER, 1, HIDDEN_MULTIPLIER));
245 rect.setFill(item.
getEventType().
getColor().deriveColor(0, HIDDEN_MULTIPLIER, HIDDEN_MULTIPLIER, 0.1));
247 setTextFill(Color.BLACK);
248 imageView.setOpacity(1);
258 protected void updateItem(TreeComparator item,
boolean empty) {
259 super.updateItem(item, empty);
260 if (empty || item == null) {
263 setText(item.getDisplayName());
Action newHideDescriptionAction(String description, DescriptionLoD descriptionLoD)
void updateHiddenState(EventBundle<?> item)
ComboBox< TreeComparator > sortByBox
TreeView< EventBundle<?> > eventsTree
InvalidationListener filterStateChangeListener
void registerListeners(Collection<?extends DescriptionFilter > filters, EventBundle<?> item)
void updateItem(EventBundle<?> item, boolean empty)
ObservableList< NodeType > getSelectedNodes()
void deRegisterListeners(Collection<?extends DescriptionFilter > filters)
void updateItem(TreeComparator item, boolean empty)
DetailViewPane detailViewPane
ObservableList< EventStripe > getEventStripes()
EventsTree(TimeLineController controller)
void setDetailViewPane(DetailViewPane detailViewPane)
static void construct(Node node, String fxmlFileName)
void setSelectionModel(MultipleSelectionModel< TreeItem< EventBundle<?>>> selectionModel)
DescriptionLoD getDescriptionLoD()
ObservableList< DescriptionFilter > getQuickHideFilters()
final TimeLineController controller
Action newUnhideDescriptionAction(String description, DescriptionLoD descriptionLoD)