mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-19 11:07:43 +00:00
Merge pull request #2066 from millmanorama/TL-multiple-images-same-name
distinguish datasource filters by datasource id and not displayname in…
This commit is contained in:
commit
ba4ab7e0dd
@ -68,10 +68,12 @@ public abstract class AbstractFilter implements Filter {
|
|||||||
return "[" + (isSelected() ? "x" : " ") + "]"; // NON-NLS
|
return "[" + (isSelected() ? "x" : " ") + "]"; // NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isActive() {
|
public boolean isActive() {
|
||||||
return activeProperty.get();
|
return activeProperty().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public BooleanBinding activeProperty() {
|
public BooleanBinding activeProperty() {
|
||||||
return activeProperty;
|
return activeProperty;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.timeline.filters;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javafx.beans.Observable;
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
@ -31,12 +30,8 @@ import javafx.collections.ObservableList;
|
|||||||
* implementations can decide how to combine the sub-filters.
|
* implementations can decide how to combine the sub-filters.
|
||||||
*
|
*
|
||||||
* a {@link CompoundFilter} uses listeners to enforce the following
|
* a {@link CompoundFilter} uses listeners to enforce the following
|
||||||
* relationships between it and its sub-filters:
|
* relationships between it and its sub-filters: if all of a compound filter's
|
||||||
* <ol>
|
* sub-filters become un-selected, un-select the compound filter.
|
||||||
* <le>if a filter becomes inactive disable all of its subfilters</le>
|
|
||||||
* <le>if a sub-filter changes active state set the parent filter active if any
|
|
||||||
* of its sub-filters are active.</le>
|
|
||||||
* </ol>
|
|
||||||
*/
|
*/
|
||||||
public abstract class CompoundFilter<SubFilterType extends Filter> extends AbstractFilter {
|
public abstract class CompoundFilter<SubFilterType extends Filter> extends AbstractFilter {
|
||||||
|
|
||||||
@ -57,30 +52,21 @@ public abstract class CompoundFilter<SubFilterType extends Filter> extends Abstr
|
|||||||
public CompoundFilter(List<SubFilterType> subFilters) {
|
public CompoundFilter(List<SubFilterType> subFilters) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
//listen to changes in list of subfilters and add active state listener to newly added filters
|
//listen to changes in list of subfilters
|
||||||
this.subFilters.addListener((ListChangeListener.Change<? extends SubFilterType> c) -> {
|
this.subFilters.addListener((ListChangeListener.Change<? extends SubFilterType> change) -> {
|
||||||
while (c.next()) {
|
while (change.next()) {
|
||||||
addSubFilterListeners(c.getAddedSubList());
|
//add a listener to the selected property of each added subfilter
|
||||||
|
change.getAddedSubList().forEach(addedSubFilter -> {
|
||||||
|
//if a subfilter's selected property changes...
|
||||||
|
addedSubFilter.selectedProperty().addListener(selectedProperty -> {
|
||||||
|
//set this compound filter selected af any of the subfilters are selected.
|
||||||
|
setSelected(getSubFilters().parallelStream().anyMatch(Filter::isSelected));
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.subFilters.setAll(subFilters);
|
|
||||||
|
|
||||||
this.selectedProperty().addListener(activeProperty -> {
|
|
||||||
getSubFilters().forEach(subFilter -> subFilter.setDisabled(isActive() == false));
|
|
||||||
});
|
|
||||||
this.disabledProperty().addListener(activeProperty -> {
|
|
||||||
getSubFilters().forEach(subFilter -> subFilter.setDisabled(isActive() == false));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addSubFilterListeners(List<? extends SubFilterType> newSubfilters) {
|
this.subFilters.setAll(subFilters);
|
||||||
for (SubFilterType sf : newSubfilters) {
|
|
||||||
//if a subfilter changes active state
|
|
||||||
sf.selectedProperty().addListener((Observable observable) -> {
|
|
||||||
//set this filter acttive af any of the subfilters are active.
|
|
||||||
setSelected(getSubFilters().parallelStream().anyMatch(Filter::isSelected));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static <SubFilterType extends Filter> boolean areSubFiltersEqual(final CompoundFilter<SubFilterType> oneFilter, final CompoundFilter<SubFilterType> otherFilter) {
|
static <SubFilterType extends Filter> boolean areSubFiltersEqual(final CompoundFilter<SubFilterType> oneFilter, final CompoundFilter<SubFilterType> otherFilter) {
|
||||||
|
@ -43,7 +43,7 @@ public class DataSourceFilter extends AbstractFilter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
synchronized public DataSourceFilter copyOf() {
|
synchronized public DataSourceFilter copyOf() {
|
||||||
DataSourceFilter filterCopy = new DataSourceFilter(getDisplayName(), getDataSourceID());
|
DataSourceFilter filterCopy = new DataSourceFilter(getDataSourceName(), getDataSourceID());
|
||||||
filterCopy.setSelected(isSelected());
|
filterCopy.setSelected(isSelected());
|
||||||
filterCopy.setDisabled(isDisabled());
|
filterCopy.setDisabled(isDisabled());
|
||||||
return filterCopy;
|
return filterCopy;
|
||||||
@ -51,7 +51,7 @@ public class DataSourceFilter extends AbstractFilter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
return dataSourceName;
|
return getDataSourceName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.timeline.filters;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.binding.BooleanBinding;
|
||||||
import javafx.beans.value.ObservableBooleanValue;
|
import javafx.beans.value.ObservableBooleanValue;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
|
||||||
@ -29,19 +30,23 @@ import org.openide.util.NbBundle;
|
|||||||
*/
|
*/
|
||||||
public class DataSourcesFilter extends UnionFilter<DataSourceFilter> {
|
public class DataSourcesFilter extends UnionFilter<DataSourceFilter> {
|
||||||
|
|
||||||
|
//keep references to the overridden properties so they don't get GC'd
|
||||||
|
private final BooleanBinding activePropertyOverride;
|
||||||
|
private final BooleanBinding disabledPropertyOverride;
|
||||||
|
|
||||||
public DataSourcesFilter() {
|
public DataSourcesFilter() {
|
||||||
setSelected(false);
|
disabledPropertyOverride = Bindings.or(super.disabledProperty(), Bindings.size(getSubFilters()).lessThanOrEqualTo(1));
|
||||||
|
activePropertyOverride = super.activeProperty().and(Bindings.not(disabledPropertyOverride));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataSourcesFilter copyOf() {
|
public DataSourcesFilter copyOf() {
|
||||||
final DataSourcesFilter filterCopy = new DataSourcesFilter();
|
final DataSourcesFilter filterCopy = new DataSourcesFilter();
|
||||||
|
//add a copy of each subfilter
|
||||||
|
getSubFilters().forEach(dataSourceFilter -> filterCopy.addSubFilter(dataSourceFilter.copyOf()));
|
||||||
|
//these need to happen after the listeners fired by adding the subfilters
|
||||||
filterCopy.setSelected(isSelected());
|
filterCopy.setSelected(isSelected());
|
||||||
filterCopy.setDisabled(isDisabled());
|
filterCopy.setDisabled(isDisabled());
|
||||||
//add a copy of each subfilter
|
|
||||||
getSubFilters().forEach(dataSourceFilter ->
|
|
||||||
filterCopy.addSubFilter(dataSourceFilter.copyOf())
|
|
||||||
);
|
|
||||||
|
|
||||||
return filterCopy;
|
return filterCopy;
|
||||||
}
|
}
|
||||||
@ -65,13 +70,6 @@ public class DataSourcesFilter extends UnionFilter<DataSourceFilter> {
|
|||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSubFilter(DataSourceFilter dataSourceFilter) {
|
|
||||||
super.addSubFilter(dataSourceFilter);
|
|
||||||
if (getSubFilters().size() > 1) {
|
|
||||||
setSelected(Boolean.TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
@ -97,7 +95,12 @@ public class DataSourcesFilter extends UnionFilter<DataSourceFilter> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ObservableBooleanValue disabledProperty() {
|
public ObservableBooleanValue disabledProperty() {
|
||||||
return Bindings.or(super.disabledProperty(), Bindings.size(getSubFilters()).lessThanOrEqualTo(1));
|
return disabledPropertyOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BooleanBinding activeProperty() {
|
||||||
|
return activePropertyOverride;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,11 +25,16 @@ import javafx.collections.FXCollections;
|
|||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for Filters
|
* Interface for Filters. Filters are given to the EventDB who interpretes them
|
||||||
|
* a appropriately for all db queries. Since the filters are primarily
|
||||||
|
* configured in the UI, this interface provides selected, disabled and active
|
||||||
|
* (selected and not disabled) properties.
|
||||||
*/
|
*/
|
||||||
public interface Filter {
|
public interface Filter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* get a filter that is the intersection of the given filters
|
||||||
|
*
|
||||||
* @param filters a set of filters to intersect
|
* @param filters a set of filters to intersect
|
||||||
*
|
*
|
||||||
* @return a filter that is the intersection of the given filters
|
* @return a filter that is the intersection of the given filters
|
||||||
@ -39,50 +44,101 @@ public interface Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* get a filter that is the intersection of the given filters
|
||||||
|
*
|
||||||
* @param filters a set of filters to intersect
|
* @param filters a set of filters to intersect
|
||||||
*
|
*
|
||||||
* @return a filter that is the intersection of the given filters
|
* @return a filter that is the intersection of the given filters
|
||||||
*/
|
*/
|
||||||
public static IntersectionFilter<Filter> intersect(Filter[] filters) {
|
public static IntersectionFilter<Filter> intersect(Filter[] filters) {
|
||||||
return new IntersectionFilter<>(FXCollections.observableArrayList(filters));
|
return intersect(FXCollections.observableArrayList(filters));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* since filters have mutable state (active) and are observed in various
|
* since filters have mutable state (selected/disabled/active) and are
|
||||||
* places, we need a mechanism to copy the current state to keep in history.
|
* observed in various places, we need a mechanism to copy the current state
|
||||||
|
* to keep in the history.
|
||||||
*
|
*
|
||||||
* Concrete subtasks should implement this in a way that preserves the
|
* Concrete sub classes should implement this in a way that preserves the
|
||||||
* active state and any subfilters.
|
* state and any sub-filters.
|
||||||
*
|
*
|
||||||
* @return a copy of this filter.
|
* @return a copy of this filter.
|
||||||
*/
|
*/
|
||||||
Filter copyOf();
|
Filter copyOf();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the display name of this filter
|
||||||
|
*
|
||||||
|
* @return a name for this filter to show in the UI
|
||||||
|
*/
|
||||||
String getDisplayName();
|
String getDisplayName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a representation of this filter (and it's state) as a HTML string
|
||||||
|
*
|
||||||
|
* @return a html representation of this filter
|
||||||
|
*/
|
||||||
String getHTMLReportString();
|
String getHTMLReportString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get an Ascii representation of this filter's selected state: ie [x] for
|
||||||
|
* selected or [ ] for not selected
|
||||||
|
*
|
||||||
|
* @return an Ascii representation of this filter's selected state
|
||||||
|
*/
|
||||||
String getStringCheckBox();
|
String getStringCheckBox();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is this filter selected
|
||||||
|
*
|
||||||
|
* @return true if this filter is selected
|
||||||
|
*/
|
||||||
boolean isSelected();
|
boolean isSelected();
|
||||||
|
|
||||||
void setSelected(Boolean act);
|
/**
|
||||||
|
* set this filter selected
|
||||||
|
*
|
||||||
|
* @param selected true to selecte, false to un-select
|
||||||
|
*/
|
||||||
|
void setSelected(Boolean selected);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* observable selected property
|
||||||
|
*
|
||||||
|
* @return the observable selected property for this filter
|
||||||
|
*/
|
||||||
SimpleBooleanProperty selectedProperty();
|
SimpleBooleanProperty selectedProperty();
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* TODO: disabled state only affects the state of the checkboxes in the ui
|
* set the filter disabled
|
||||||
* and not the actual filters and shouldn't be implemented here, but it was
|
|
||||||
* too hard to figure out how it should be implemented without intruding on
|
|
||||||
* the ui-ignorant filters
|
|
||||||
*/
|
*/
|
||||||
void setDisabled(Boolean act);
|
void setDisabled(Boolean act);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* observable disabled property
|
||||||
|
*
|
||||||
|
* @return the observable disabled property for this filter
|
||||||
|
*/
|
||||||
ObservableBooleanValue disabledProperty();
|
ObservableBooleanValue disabledProperty();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is this filter disabled
|
||||||
|
*
|
||||||
|
* @return true if this filter is disabled
|
||||||
|
*/
|
||||||
boolean isDisabled();
|
boolean isDisabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is this filter active (selected and not disabled)
|
||||||
|
*
|
||||||
|
* @return true if this filter is active
|
||||||
|
*/
|
||||||
boolean isActive();
|
boolean isActive();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* observable active property
|
||||||
|
*
|
||||||
|
* @return the observable active property for this filter
|
||||||
|
*/
|
||||||
BooleanBinding activeProperty();
|
BooleanBinding activeProperty();
|
||||||
}
|
}
|
||||||
|
@ -42,12 +42,12 @@ public class HashHitsFilter extends UnionFilter<HashSetFilter> {
|
|||||||
@Override
|
@Override
|
||||||
public HashHitsFilter copyOf() {
|
public HashHitsFilter copyOf() {
|
||||||
HashHitsFilter filterCopy = new HashHitsFilter();
|
HashHitsFilter filterCopy = new HashHitsFilter();
|
||||||
|
//add a copy of each subfilter
|
||||||
|
this.getSubFilters().forEach(hashSetFilter -> filterCopy.addSubFilter(hashSetFilter.copyOf()));
|
||||||
|
//these need to happen after the listeners fired by adding the subfilters
|
||||||
filterCopy.setSelected(isSelected());
|
filterCopy.setSelected(isSelected());
|
||||||
filterCopy.setDisabled(isDisabled());
|
filterCopy.setDisabled(isDisabled());
|
||||||
//add a copy of each subfilter
|
|
||||||
this.getSubFilters().forEach(hashSetFilter ->
|
|
||||||
filterCopy.addSubFilter(hashSetFilter.copyOf())
|
|
||||||
);
|
|
||||||
return filterCopy;
|
return filterCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2015 Basis Technology Corp.
|
* Copyright 2015-16 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -122,4 +122,8 @@ public class RootFilter extends IntersectionFilter<Filter> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TypeFilter getTypeFilter() {
|
||||||
|
return typeFilter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,12 +44,12 @@ public class TagsFilter extends UnionFilter<TagNameFilter> {
|
|||||||
@Override
|
@Override
|
||||||
public TagsFilter copyOf() {
|
public TagsFilter copyOf() {
|
||||||
TagsFilter filterCopy = new TagsFilter();
|
TagsFilter filterCopy = new TagsFilter();
|
||||||
|
//add a copy of each subfilter
|
||||||
|
getSubFilters().forEach(tagNameFilter -> filterCopy.addSubFilter(tagNameFilter.copyOf()));
|
||||||
|
//these need to happen after the listeners fired by adding the subfilters
|
||||||
filterCopy.setSelected(isSelected());
|
filterCopy.setSelected(isSelected());
|
||||||
filterCopy.setDisabled(isDisabled());
|
filterCopy.setDisabled(isDisabled());
|
||||||
//add a copy of each subfilter
|
|
||||||
getSubFilters().forEach(tagNameFilter ->
|
|
||||||
filterCopy.addSubFilter(tagNameFilter.copyOf())
|
|
||||||
);
|
|
||||||
return filterCopy;
|
return filterCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,13 +101,11 @@ public class TypeFilter extends UnionFilter<TypeFilter> {
|
|||||||
public TypeFilter copyOf() {
|
public TypeFilter copyOf() {
|
||||||
//make a nonrecursive copy of this filter
|
//make a nonrecursive copy of this filter
|
||||||
final TypeFilter filterCopy = new TypeFilter(eventType, false);
|
final TypeFilter filterCopy = new TypeFilter(eventType, false);
|
||||||
|
//add a copy of each subfilter
|
||||||
|
getSubFilters().forEach(typeFilter -> filterCopy.addSubFilter(typeFilter.copyOf(), comparator));
|
||||||
|
//these need to happen after the listeners fired by adding the subfilters
|
||||||
filterCopy.setSelected(isSelected());
|
filterCopy.setSelected(isSelected());
|
||||||
filterCopy.setDisabled(isDisabled());
|
filterCopy.setDisabled(isDisabled());
|
||||||
//add a copy of each subfilter
|
|
||||||
getSubFilters().forEach(typeFilter ->
|
|
||||||
filterCopy.addSubFilter(typeFilter.copyOf(), comparator)
|
|
||||||
);
|
|
||||||
|
|
||||||
return filterCopy;
|
return filterCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-15 Basis Technology Corp.
|
* Copyright 2013-16 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -44,12 +44,10 @@ import org.sleuthkit.autopsy.timeline.TimeLineController;
|
|||||||
import org.sleuthkit.autopsy.timeline.VisualizationMode;
|
import org.sleuthkit.autopsy.timeline.VisualizationMode;
|
||||||
import org.sleuthkit.autopsy.timeline.actions.ResetFilters;
|
import org.sleuthkit.autopsy.timeline.actions.ResetFilters;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel;
|
||||||
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.RootEventType;
|
|
||||||
import org.sleuthkit.autopsy.timeline.filters.AbstractFilter;
|
import org.sleuthkit.autopsy.timeline.filters.AbstractFilter;
|
||||||
import org.sleuthkit.autopsy.timeline.filters.DescriptionFilter;
|
import org.sleuthkit.autopsy.timeline.filters.DescriptionFilter;
|
||||||
import org.sleuthkit.autopsy.timeline.filters.Filter;
|
import org.sleuthkit.autopsy.timeline.filters.Filter;
|
||||||
import org.sleuthkit.autopsy.timeline.filters.RootFilter;
|
import org.sleuthkit.autopsy.timeline.filters.RootFilter;
|
||||||
import org.sleuthkit.autopsy.timeline.filters.TypeFilter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The FXML controller for the filter ui.
|
* The FXML controller for the filter ui.
|
||||||
@ -86,7 +84,11 @@ final public class FilterSetPanel extends BorderPane {
|
|||||||
private final FilteredEventsModel filteredEvents;
|
private final FilteredEventsModel filteredEvents;
|
||||||
private final TimeLineController controller;
|
private final TimeLineController controller;
|
||||||
|
|
||||||
private final ObservableMap<String, Boolean> expansionMap = FXCollections.observableHashMap();
|
/**
|
||||||
|
* map from filter to its expansion state in the ui, used to restore the
|
||||||
|
* expansion state as we navigate back and forward in the history
|
||||||
|
*/
|
||||||
|
private final ObservableMap<Filter, Boolean> expansionMap = FXCollections.observableHashMap();
|
||||||
private double dividerPosition;
|
private double dividerPosition;
|
||||||
|
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
@ -114,7 +116,8 @@ final public class FilterSetPanel extends BorderPane {
|
|||||||
legendColumn.setCellValueFactory(cellDataFeatures -> cellDataFeatures.getValue().valueProperty());
|
legendColumn.setCellValueFactory(cellDataFeatures -> cellDataFeatures.getValue().valueProperty());
|
||||||
legendColumn.setCellFactory(col -> new LegendCell(this.controller));
|
legendColumn.setCellFactory(col -> new LegendCell(this.controller));
|
||||||
|
|
||||||
expansionMap.put(new TypeFilter(RootEventType.getInstance()).getDisplayName(), true);
|
//type is the only filter expanded initialy
|
||||||
|
expansionMap.put(controller.getEventsModel().getFilter().getTypeFilter(), true);
|
||||||
|
|
||||||
this.filteredEvents.eventTypeZoomProperty().addListener((Observable observable) -> applyFilters());
|
this.filteredEvents.eventTypeZoomProperty().addListener((Observable observable) -> applyFilters());
|
||||||
this.filteredEvents.descriptionLODProperty().addListener((Observable observable1) -> applyFilters());
|
this.filteredEvents.descriptionLODProperty().addListener((Observable observable1) -> applyFilters());
|
||||||
|
@ -1,6 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
package org.sleuthkit.autopsy.timeline.ui.filtering;
|
||||||
|
|
||||||
import javafx.beans.Observable;
|
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.MapChangeListener;
|
import javafx.collections.MapChangeListener;
|
||||||
import javafx.collections.ObservableMap;
|
import javafx.collections.ObservableMap;
|
||||||
@ -14,46 +31,68 @@ import org.sleuthkit.autopsy.timeline.filters.Filter;
|
|||||||
final public class FilterTreeItem extends TreeItem<Filter> {
|
final public class FilterTreeItem extends TreeItem<Filter> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* recursively construct a tree of treeitems to parallel the filter tree of
|
* recursively construct a tree of TreeItems to parallel the filter tree of
|
||||||
* the given filter
|
* the given filter
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @param f the filter for this item. if f has sub-filters, tree items will
|
* @param filter the filter for this item. if f has sub-filters, tree items
|
||||||
* be made for them added added to the children of this
|
* will be made for them added added to the children of this
|
||||||
* FilterTreeItem
|
* FilterTreeItem
|
||||||
*/
|
*/
|
||||||
public FilterTreeItem(Filter f, ObservableMap<String, Boolean> expansionMap) {
|
public FilterTreeItem(Filter filter, ObservableMap<Filter, Boolean> expansionMap) {
|
||||||
super(f);
|
super(filter);
|
||||||
|
|
||||||
expansionMap.addListener((MapChangeListener.Change<? extends String, ? extends Boolean> change) -> {
|
//listen to changes in the expansion map, and update expansion state of filter object
|
||||||
if (change.getKey() == f.getDisplayName()) {
|
expansionMap.addListener((MapChangeListener.Change<? extends Filter, ? extends Boolean> change) -> {
|
||||||
|
if (change.getKey().equals(filter)) {
|
||||||
setExpanded(expansionMap.get(change.getKey()));
|
setExpanded(expansionMap.get(change.getKey()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (expansionMap.get(f.getDisplayName()) != null) {
|
if (expansionMap.containsKey(filter)) {
|
||||||
setExpanded(expansionMap.get(f.getDisplayName()));
|
setExpanded(expansionMap.get(filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
expandedProperty().addListener((Observable observable) -> {
|
//keep expanion map upto date if user expands/collapses filter
|
||||||
expansionMap.put(f.getDisplayName(), isExpanded());
|
expandedProperty().addListener(expandedProperty -> expansionMap.put(filter, isExpanded()));
|
||||||
});
|
|
||||||
|
|
||||||
if (f instanceof CompoundFilter<?>) {
|
//if the filter is a compound filter, add its subfilters to the tree
|
||||||
CompoundFilter<?> compoundFilter = (CompoundFilter<?>) f;
|
if (filter instanceof CompoundFilter<?>) {
|
||||||
|
final CompoundFilter<?> compoundFilter = (CompoundFilter<?>) filter;
|
||||||
|
|
||||||
for (Filter subFilter : compoundFilter.getSubFilters()) {
|
//add all sub filters
|
||||||
getChildren().add(new FilterTreeItem(subFilter, expansionMap));
|
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) -> {
|
compoundFilter.getSubFilters().addListener((ListChangeListener.Change<? extends Filter> c) -> {
|
||||||
while (c.next()) {
|
while (c.next()) {
|
||||||
for (Filter subfFilter : c.getAddedSubList()) {
|
for (Filter subfFilter : c.getAddedSubList()) {
|
||||||
setExpanded(true);
|
setExpanded(true); //emphasize new filters by expanding parent to make sure they are visible
|
||||||
getChildren().add(new FilterTreeItem(subfFilter, expansionMap));
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user