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 d2502bc405..2a5d69b3d3 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterTreeItem.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterTreeItem.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.timeline.ui.filtering; +import javafx.beans.InvalidationListener; +import javafx.beans.Observable; import javafx.collections.ListChangeListener; import javafx.collections.ObservableMap; import javafx.scene.control.TreeItem; @@ -71,6 +73,15 @@ final public class FilterTreeItem extends TreeItem> { } } }); + + compoundFilter.selectedProperty().addListener(new InvalidationListener() { + @Override + public void invalidated(Observable observable) { + if (compoundFilter.isSelected()) { + setExpanded(true); + } + } + }); } } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/CompoundFilterStateImpl.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/CompoundFilterStateImpl.java index 323da8abd3..2fb8cc9685 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/CompoundFilterStateImpl.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/CompoundFilterStateImpl.java @@ -33,28 +33,41 @@ class CompoundFilterStateImpl> subFilterStates = FXCollections.observableArrayList(); - CompoundFilterStateImpl(C delegate) { - super(delegate); - - delegate.getSubFilters().forEach(this::addSubFilterState); - delegate.getSubFilters().addListener((ListChangeListener.Change change) -> { + /** + * A constructor that automatically makes sub FilterStates for all the + * subfilters of the given compound filter. + * + * @param filter The CompoundFilter this will represent the state of. + */ + CompoundFilterStateImpl(C filter) { + super(filter); + filter.getSubFilters().forEach(this::addSubFilterState); + filter.getSubFilters().addListener((ListChangeListener.Change change) -> { while (change.next()) { change.getAddedSubList().forEach(CompoundFilterStateImpl.this::addSubFilterState); } }); - /* - * enforce the following relationship between a compound filter and its - * subfilters: if a compound filter's active property changes, disable - * the subfilters if the compound filter is not active. - */ - activeProperty().addListener(activeProperty -> disableSubFiltersIfNotActive()); - disableSubFiltersIfNotActive(); + + configureListeners(); } - CompoundFilterStateImpl(C delegate, Collection> subFilterStates) { - super(delegate); - + /** + * A constructor that doesn't make subfilter states automatically, but + * instead uses the given collection of sub filter states. Designed + * primarily for use when making a copy of an existing filterstate tree. + * + * @param filter The CompoundFilter this will represent the state + * of. + * @param subFilterStates The filter states to use as the sub filter states. + */ + CompoundFilterStateImpl(C filter, Collection> subFilterStates) { + super(filter); subFilterStates.forEach(this::addSubFilterState); + + configureListeners(); + } + + private void configureListeners() { /* * enforce the following relationship between a compound filter and its * subfilters: if a compound filter's active property changes, disable @@ -62,6 +75,12 @@ class CompoundFilterStateImpl disableSubFiltersIfNotActive()); disableSubFiltersIfNotActive(); + selectedProperty().addListener(selectedProperty -> { + if (isSelected() && getSubFilterStates().stream().noneMatch(FilterState::isSelected)) { + getSubFilterStates().forEach(subFilterState -> subFilterState.setSelected(true)); + } + }); + } /** diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/DefaultFilterState.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/DefaultFilterState.java index 374c0dd4c2..90ab7cf47a 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/DefaultFilterState.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/datamodel/DefaultFilterState.java @@ -32,10 +32,10 @@ import org.sleuthkit.datamodel.timeline.TimelineFilter; */ public class DefaultFilterState implements FilterState { - private final FilterType delegate; + private final FilterType filter; - public DefaultFilterState(FilterType delegate) { - this.delegate = delegate; + public DefaultFilterState(FilterType filter) { + this.filter = filter; } private final SimpleBooleanProperty selected = new SimpleBooleanProperty(false); @@ -84,21 +84,21 @@ public class DefaultFilterState implements Fi @Override public String getDisplayName() { - return delegate.getDisplayName(); + return filter.getDisplayName(); } - + @Override public DefaultFilterState copyOf() { @SuppressWarnings("unchecked") - DefaultFilterState copy = new DefaultFilterState<>((FilterType) delegate.copyOf()); - copy.setSelected(isSelected( )); + DefaultFilterState copy = new DefaultFilterState<>((FilterType) filter.copyOf()); + copy.setSelected(isSelected()); copy.setDisabled(isDisabled()); return copy; } @Override public FilterType getFilter() { - return delegate; + return filter; } @Override