diff --git a/Core/src/org/sleuthkit/autopsy/timeline/events/type/RootEventType.java b/Core/src/org/sleuthkit/autopsy/timeline/events/type/RootEventType.java index 79716db2f7..dd6955fe37 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/events/type/RootEventType.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/events/type/RootEventType.java @@ -59,6 +59,9 @@ public class RootEventType implements EventType { private static class RootEventTypeHolder { private static final RootEventType INSTANCE = new RootEventType(); + + private RootEventTypeHolder() { + } } @Override @@ -76,8 +79,6 @@ public class RootEventType implements EventType { return Arrays.asList(BaseTypes.values()); } - - @Override public String getIconBase() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/AbstractFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/AbstractFilter.java index 4e4f122f24..f9c945a997 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/AbstractFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/AbstractFilter.java @@ -13,7 +13,6 @@ import javafx.beans.property.SimpleBooleanProperty; public abstract class AbstractFilter implements Filter { private final SimpleBooleanProperty active = new SimpleBooleanProperty(true); - private final SimpleBooleanProperty disabled = new SimpleBooleanProperty(false); @Override @@ -42,7 +41,7 @@ public abstract class AbstractFilter implements Filter { } @Override - public boolean isdisabled() { + public boolean isDisabled() { return disabled.get(); } @@ -50,4 +49,7 @@ public abstract class AbstractFilter implements Filter { public String getStringCheckBox() { return "[" + (isActive() ? "x" : " ") + "]"; } + + + } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/Filter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/Filter.java index df07d23ffa..4392fd68cd 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/Filter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/Filter.java @@ -76,6 +76,5 @@ public interface Filter { SimpleBooleanProperty getDisabledProperty(); - boolean isdisabled(); - + boolean isDisabled(); } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/HideKnownFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/HideKnownFilter.java index 86c36ce5fe..0742a91cbe 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/HideKnownFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/HideKnownFilter.java @@ -37,7 +37,7 @@ public class HideKnownFilter extends AbstractFilter { public HideKnownFilter copyOf() { HideKnownFilter hideKnownFilter = new HideKnownFilter(); hideKnownFilter.setActive(isActive()); - hideKnownFilter.setDisabled(isdisabled()); + hideKnownFilter.setDisabled(isDisabled()); return hideKnownFilter; } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/IntersectionFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/IntersectionFilter.java index b11b0f53b7..5af67c3483 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/IntersectionFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/IntersectionFilter.java @@ -10,15 +10,15 @@ import javafx.collections.ObservableList; /** Intersection(And) filter */ public class IntersectionFilter extends CompoundFilter { - + public IntersectionFilter(ObservableList subFilters) { super(subFilters); } - + public IntersectionFilter() { super(FXCollections.observableArrayList()); } - + @Override public IntersectionFilter copyOf() { IntersectionFilter filter = new IntersectionFilter(FXCollections.observableArrayList( @@ -26,20 +26,22 @@ public class IntersectionFilter extends CompoundFilter { .map(Filter::copyOf) .collect(Collectors.toList()))); filter.setActive(isActive()); - filter.setDisabled(isdisabled()); + filter.setDisabled(isDisabled()); return filter; } - + @Override public String getDisplayName() { - return "Intersection"; + return "Intersection" + getSubFilters().stream() + .map(Filter::getDisplayName) + .collect(Collectors.joining(",", "[", "]")); } - + @Override public String getHTMLReportString() { return getSubFilters().stream().filter(Filter::isActive).map(Filter::getHTMLReportString).collect(Collectors.joining("
  • ", "
    • ", "
    ")); } - + @Override public boolean equals(Object obj) { if (obj == null) { @@ -49,11 +51,11 @@ public class IntersectionFilter extends CompoundFilter { return false; } final IntersectionFilter other = (IntersectionFilter) obj; - + if (isActive() != other.isActive()) { return false; } - + for (int i = 0; i < getSubFilters().size(); i++) { if (getSubFilters().get(i).equals(other.getSubFilters().get(i)) == false) { return false; @@ -61,7 +63,7 @@ public class IntersectionFilter extends CompoundFilter { } return true; } - + @Override public int hashCode() { int hash = 7; diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/TextFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/TextFilter.java index 44a38c30e9..6d7db2ca0e 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/TextFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/TextFilter.java @@ -56,7 +56,7 @@ public class TextFilter extends AbstractFilter { synchronized public TextFilter copyOf() { TextFilter textFilter = new TextFilter(getText()); textFilter.setActive(isActive()); - textFilter.setDisabled(isdisabled()); + textFilter.setDisabled(isDisabled()); return textFilter; } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java index 0306e463d9..80f5d1edcb 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java @@ -42,7 +42,7 @@ public class TypeFilter extends UnionFilter { private TypeFilter(EventType et, boolean recursive) { super(FXCollections.observableArrayList()); this.eventType = et; - + if (recursive) { // add subfilters for each subtype for (EventType subType : et.getSubTypes()) { this.getSubFilters().add(new TypeFilter(subType)); @@ -57,11 +57,11 @@ public class TypeFilter extends UnionFilter { public TypeFilter(EventType et) { this(et, true); } - + public EventType getEventType() { return eventType; } - + @Override public String getDisplayName() { return eventType == RootEventType.getInstance() ? "Event Type Filter" : eventType.getDisplayName(); @@ -76,21 +76,21 @@ public class TypeFilter extends UnionFilter { public Image getFXImage() { return eventType.getFXImage(); } - + @Override public TypeFilter copyOf() { //make a nonrecursive copy of this filter final TypeFilter typeFilter = new TypeFilter(eventType, false); typeFilter.setActive(isActive()); - typeFilter.setDisabled(isdisabled()); + typeFilter.setDisabled(isDisabled()); //add a copy of each subfilter this.getSubFilters().forEach((Filter t) -> { typeFilter.getSubFilters().add(t.copyOf()); }); - + return typeFilter; } - + @Override public String getHTMLReportString() { String string = getEventType().getDisplayName() + getStringCheckBox(); @@ -99,7 +99,7 @@ public class TypeFilter extends UnionFilter { } return string; } - + @Override public boolean equals(Object obj) { if (obj == null) { @@ -109,15 +109,15 @@ public class TypeFilter extends UnionFilter { return false; } final TypeFilter other = (TypeFilter) obj; - + if (isActive() != other.isActive()) { return false; } - + if (this.eventType != other.eventType) { return false; } - + for (int i = 0; i < getSubFilters().size(); i++) { if (getSubFilters().get(i).equals(other.getSubFilters().get(i)) == false) { return false; @@ -125,12 +125,12 @@ public class TypeFilter extends UnionFilter { } return true; } - + @Override public int hashCode() { int hash = 7; hash = 67 * hash + Objects.hashCode(this.eventType); return hash; } - + } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java index ee1c507ed5..22ba4ca113 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java @@ -20,6 +20,9 @@ package org.sleuthkit.autopsy.timeline.ui.filtering; import javafx.application.Platform; import javafx.beans.Observable; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableMap; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; @@ -67,6 +70,8 @@ public class FilterSetPanel extends BorderPane implements TimeLineView { private TimeLineController controller; + private final ObservableMap expansionMap = FXCollections.observableHashMap(); + @FXML void initialize() { assert applyButton != null : "fx:id=\"applyButton\" was not injected: check your FXML file 'FilterSetPanel.fxml'."; @@ -138,6 +143,7 @@ public class FilterSetPanel extends BorderPane implements TimeLineView { public FilterSetPanel() { FXMLConstructor.construct(this, "FilterSetPanel.fxml"); + expansionMap.put("Event Type Filter", Boolean.TRUE); } @Override @@ -152,16 +158,14 @@ public class FilterSetPanel extends BorderPane implements TimeLineView { @Override public void setModel(FilteredEventsModel filteredEvents) { this.filteredEvents = filteredEvents; - refresh(); - this.filteredEvents.filter().addListener((Observable o) -> { refresh(); }); } private void refresh() { - filterTreeTable.setRoot(new FilterTreeItem(this.filteredEvents.filter().get().copyOf())); + filterTreeTable.setRoot(new FilterTreeItem(this.filteredEvents.filter().get().copyOf(), expansionMap)); } /** @@ -171,23 +175,29 @@ public class FilterSetPanel extends BorderPane implements TimeLineView { private static class FilterCheckBoxCell extends TreeTableCell { private final CheckBox checkBox = new CheckBox(); + private SimpleBooleanProperty activeProperty; @Override protected void updateItem(AbstractFilter item, boolean empty) { super.updateItem(item, empty); Platform.runLater(() -> { + if (activeProperty != null) { + checkBox.selectedProperty().unbindBidirectional(activeProperty); + } + checkBox.disableProperty().unbind(); if (item == null) { setText(null); setGraphic(null); - checkBox.selectedProperty().unbind(); - checkBox.disableProperty().unbind(); + } else { setText(item.getDisplayName()); - checkBox.selectedProperty().bindBidirectional(item.getActiveProperty()); + activeProperty = item.getActiveProperty(); + checkBox.selectedProperty().bindBidirectional(activeProperty); checkBox.disableProperty().bind(item.getDisabledProperty()); setGraphic(checkBox); } }); } + } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterTreeItem.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterTreeItem.java index 2302099939..fa294f7c1d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterTreeItem.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterTreeItem.java @@ -1,5 +1,8 @@ package org.sleuthkit.autopsy.timeline.ui.filtering; +import javafx.beans.Observable; +import javafx.collections.MapChangeListener; +import javafx.collections.ObservableMap; import javafx.scene.control.TreeItem; import org.sleuthkit.autopsy.timeline.filters.CompoundFilter; import org.sleuthkit.autopsy.timeline.filters.Filter; @@ -16,15 +19,28 @@ public class FilterTreeItem extends TreeItem { * be made for them added added to the children of this * FilterTreeItem */ - public FilterTreeItem(Filter f) { + public FilterTreeItem(Filter f, ObservableMap expansionMap) { super(f); - setExpanded(true); + + expansionMap.addListener((MapChangeListener.Change change) -> { + if (change.getKey() == f.getDisplayName()) { + setExpanded(expansionMap.get(change.getKey())); + } + }); + + if (expansionMap.get(f.getDisplayName()) != null) { + setExpanded(expansionMap.get(f.getDisplayName())); + } + + expandedProperty().addListener((Observable observable) -> { + expansionMap.put(f.getDisplayName(), isExpanded()); + }); if (f instanceof CompoundFilter) { CompoundFilter cf = (CompoundFilter) f; for (Filter af : cf.getSubFilters()) { - getChildren().add(new FilterTreeItem(af)); + getChildren().add(new FilterTreeItem(af, expansionMap)); } } }