/*
* Autopsy Forensic Browser
*
* Copyright 2014-16 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.timeline.ui.filtering;
import javafx.collections.ListChangeListener;
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;
/**
* A TreeItem for a filter.
*/
final public class FilterTreeItem extends TreeItem<Filter> {
/**
* recursively construct a tree of TreeItems to parallel the filter tree of
* the given filter
*
*
* @param filter the filter for this item. if f has sub-filters, tree
* items will be made for them added added to the
* children of this FilterTreeItem
* @param expansionMap
*/
public FilterTreeItem(Filter filter, ObservableMap<Filter, Boolean> expansionMap) {
super(filter);
//listen to changes in the expansion map, and update expansion state of filter object
expansionMap.addListener((MapChangeListener.Change<? extends Filter, ? extends Boolean> change) -> {
if (change.getKey().equals(filter)) {
setExpanded(expansionMap.get(change.getKey()));
}
});
if (expansionMap.containsKey(filter)) {
setExpanded(expansionMap.get(filter));
}
//keep expanion map upto date if user expands/collapses filter
expandedProperty().addListener(expandedProperty -> expansionMap.put(filter, isExpanded()));
//if the filter is a compound filter, add its subfilters to the tree
if (filter instanceof CompoundFilter<?>) {
final CompoundFilter<?> compoundFilter = (CompoundFilter<?>) filter;
//add all sub filters
compoundFilter.getSubFilters().forEach(subFilter -> getChildren().add(new FilterTreeItem(subFilter, expansionMap)));
//listen to changes in sub filters and keep tree in sync
compoundFilter.getSubFilters().addListener((ListChangeListener.Change<? extends Filter> c) -> {
while (c.next()) {
for (Filter subfFilter : c.getAddedSubList()) {
setExpanded(true); //emphasize new filters by expanding parent to make sure they are visible
getChildren().add(new FilterTreeItem(subfFilter, expansionMap));
}
}
});
/*
* 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.
*/
compoundFilter.activeProperty().addListener(activeProperty -> {
disableSubFiltersIfNotActive(compoundFilter);
});
disableSubFiltersIfNotActive(compoundFilter);
}
}
/**
* disable the sub-filters of the given compound filter if it is not active
*
* @param compoundFilter the compound filter
*/
static private void disableSubFiltersIfNotActive(CompoundFilter<?> compoundFilter) {
boolean inactive = compoundFilter.isActive() == false;
compoundFilter.getSubFilters().forEach(subFilter -> subFilter.setDisabled(inactive));
}
}