diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/History.java b/Core/src/org/sleuthkit/autopsy/coreutils/History.java index 50abf7e5cf..b9f3de0073 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/History.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/History.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.coreutils; -import java.util.Objects; import javafx.beans.property.Property; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyBooleanWrapper; diff --git a/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java b/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java index 6b19122c8d..35d8a25c5d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/db/EventDB.java @@ -1076,6 +1076,7 @@ public class EventDB { + "\n GROUP BY interval, " + typeColumn + " , " + descriptionColumn // NON-NLS + "\n ORDER BY min(time)"; // NON-NLS + System.out.println(query); // perform query and map results to AggregateEvent objects List events = new ArrayList<>(); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java index 175edbf1fd..297b0a3a1b 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java @@ -89,6 +89,4 @@ public abstract class CompoundFilter extends Abstr } return true; } - - } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/DescriptionFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/DescriptionFilter.java index edf7cba479..719e53f61d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/DescriptionFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/DescriptionFilter.java @@ -48,7 +48,7 @@ public class DescriptionFilter extends AbstractFilter { @Override public String getDisplayName() { - return getFilterMode().getDisplayName() + " Description"; + return getFilterMode().getDisplayName() + " " + getDescription(); } @Override @@ -86,10 +86,6 @@ public class DescriptionFilter extends AbstractFilter { } } - public boolean test(String t) { - return (filterMode == FilterMode.INCLUDE) == getDescription().equals(t); - } - @Override public int hashCode() { int hash = 7; diff --git a/Core/src/org/sleuthkit/autopsy/timeline/images/eye--minus.png b/Core/src/org/sleuthkit/autopsy/timeline/images/eye--minus.png new file mode 100644 index 0000000000..08b048eae3 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/timeline/images/eye--minus.png differ diff --git a/Core/src/org/sleuthkit/autopsy/timeline/images/eye--plus.png b/Core/src/org/sleuthkit/autopsy/timeline/images/eye--plus.png new file mode 100644 index 0000000000..4ad653156f Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/timeline/images/eye--plus.png differ diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualization.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualization.java index 6d6fb8fb2e..993f61501e 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualization.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/AbstractVisualization.java @@ -304,7 +304,7 @@ public abstract class AbstractVisualization & T //x-positions (pixels) of the current branch and leaf labels double leafLabelX = 0; - if (dateTime.branch.equals("")) { + if (dateTime.branch.isEmpty()) { //if there is only one part to the date (ie only year), just add a label for each tick for (Axis.TickMark t : tickMarks) { assignLeafLabel(new TwoPartDateTime(getTickMarkLabel(t.getValue())).leaf, diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/AbstractDetailViewNode.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/AbstractDetailViewNode.java index 794e474960..b079cb3698 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/AbstractDetailViewNode.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/AbstractDetailViewNode.java @@ -85,7 +85,7 @@ public abstract class AbstractDetailViewNode< T extends EventBundle, S extends A static final Image HASH_PIN = new Image("/org/sleuthkit/autopsy/images/hashset_hits.png"); static final Image PLUS = new Image("/org/sleuthkit/autopsy/timeline/images/plus-button.png"); // NON-NLS static final Image MINUS = new Image("/org/sleuthkit/autopsy/timeline/images/minus-button.png"); // NON-NLS - static final Image HIDE = new Image("/org/sleuthkit/autopsy/timeline/images/funnel.png"); // NON-NLS + static final Image TAG = new Image("/org/sleuthkit/autopsy/images/green-tag-icon-16.png"); // NON-NLS static final CornerRadii CORNER_RADII = new CornerRadii(3); /** @@ -166,9 +166,9 @@ public abstract class AbstractDetailViewNode< T extends EventBundle, S extends A private final Region spacer = new Region(); - private final CollapseClusterAction collapseClusterAction; + private final CollapseBundleAction collapseClusterAction; private final ExpandClusterAction expandClusterAction; - private final HideClusterAction hideClusterAction; + private final EventDetailChart.HideBundleAction hideClusterAction; public AbstractDetailViewNode(EventDetailChart chart, T bundle, S parentEventNode) { this.eventBundle = bundle; @@ -186,7 +186,7 @@ public abstract class AbstractDetailViewNode< T extends EventBundle, S extends A show(tagIV, false); } - hideClusterAction = new HideClusterAction(); + hideClusterAction = chart.new HideBundleAction(getEventBundle()); hideButton = ActionUtils.createButton(hideClusterAction, ActionUtils.ActionTextBehavior.HIDE); configureLODButton(hideButton); @@ -194,7 +194,7 @@ public abstract class AbstractDetailViewNode< T extends EventBundle, S extends A plusButton = ActionUtils.createButton(expandClusterAction, ActionUtils.ActionTextBehavior.HIDE); configureLODButton(plusButton); - collapseClusterAction = new CollapseClusterAction(); + collapseClusterAction = new CollapseBundleAction(); minusButton = ActionUtils.createButton(collapseClusterAction, ActionUtils.ActionTextBehavior.HIDE); configureLODButton(minusButton); @@ -545,9 +545,9 @@ public abstract class AbstractDetailViewNode< T extends EventBundle, S extends A } } - private class CollapseClusterAction extends Action { + private class CollapseBundleAction extends Action { - CollapseClusterAction() { + CollapseBundleAction() { super("Collapse"); setGraphic(new ImageView(MINUS)); @@ -561,20 +561,4 @@ public abstract class AbstractDetailViewNode< T extends EventBundle, S extends A } } - private class HideClusterAction extends Action { - - HideClusterAction() { - super("Hide"); - setGraphic(new ImageView(HIDE)); - setEventHandler((ActionEvent t) -> { - DescriptionFilter descriptionFilter = new DescriptionFilter(getDescLOD(), getDescription(), DescriptionFilter.FilterMode.EXCLUDE); - chart.getBundleFilters().add(descriptionFilter); - RootFilter rootFilter = eventsModel.getFilter(); - rootFilter.getSubFilters().add(descriptionFilter); - chart.getController().pushFilters(rootFilter.copyOf()); - chart.setRequiresLayout(true); - chart.requestChartLayout(); - }); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java index 767891d9ef..d6f86ac543 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/DetailViewPane.java @@ -68,10 +68,10 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.TimeLineController; +import org.sleuthkit.autopsy.timeline.datamodel.EventBundle; import org.sleuthkit.autopsy.timeline.datamodel.EventCluster; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType; -import org.sleuthkit.autopsy.timeline.filters.DescriptionFilter; import org.sleuthkit.autopsy.timeline.ui.AbstractVisualization; import org.sleuthkit.autopsy.timeline.ui.countsview.CountsViewPane; import org.sleuthkit.autopsy.timeline.ui.detailview.tree.NavTreeNode; @@ -243,8 +243,8 @@ public class DetailViewPane extends AbstractVisualization getBundleFilters() { - return chart.getBundleFilters(); + public ObservableList getQuickHideMasks() { + return chart.getQuickHideMasks(); } @Override @@ -301,11 +301,12 @@ public class DetailViewPane extends AbstractVisualization { - if (isCancelled() == false) { + + if (isCancelled() == false) { + Platform.runLater(() -> { setCursor(Cursor.WAIT); - } - }); + }); + } updateProgress(-1, 1); updateMessage(NbBundle.getMessage(this.getClass(), "DetailViewPane.loggedTask.preparing")); @@ -315,6 +316,7 @@ public class DetailViewPane extends AbstractVisualization { @@ -336,12 +338,11 @@ public class DetailViewPane extends AbstractVisualization xyData = new BarChart.Data<>(new DateTime(e.getSpan().getStartMillis()), e); - - Platform.runLater(() -> { - if (isCancelled() == false) { + if (isCancelled() == false) { + Platform.runLater(() -> { getSeries(e.getEventType()).getData().add(xyData); - } - }); + }); + } } Platform.runLater(() -> { @@ -485,4 +486,11 @@ public class DetailViewPane extends AbstractVisualization implements TimeLineChart { + static final Image HIDE = new Image("/org/sleuthkit/autopsy/timeline/images/eye--minus.png"); // NON-NLS + static final Image SHOW = new Image("/org/sleuthkit/autopsy/timeline/images/eye--plus.png"); // NON-NLS + private static final int PROJECTED_LINE_Y_OFFSET = 5; private static final int PROJECTED_LINE_STROKE_WIDTH = 5; @@ -203,7 +206,7 @@ public final class EventDetailChart extends XYChart impl */ private final SimpleDoubleProperty truncateWidth = new SimpleDoubleProperty(200.0); private final SimpleBooleanProperty alternateLayout = new SimpleBooleanProperty(true); - private ObservableList bundleFilters = FXCollections.observableArrayList(); + private ObservableList quickHideMasks = FXCollections.observableArrayList(); EventDetailChart(DateAxis dateAxis, final Axis verticalAxis, ObservableList> selectedNodes) { super(dateAxis, verticalAxis); @@ -499,8 +502,8 @@ public final class EventDetailChart extends XYChart impl shownPartition = bundleStream .map(nodeMap::get) .sorted(Comparator.comparing(AbstractDetailViewNode::getStartMillis)) - .collect(Collectors.partitioningBy(node -> getBundleFilters().stream() - .allMatch(filter -> filter.test(node.getDescription())))); + .collect(Collectors.partitioningBy(node -> getQuickHideMasks().stream() + .anyMatch(mask -> mask.equals(node.getDescription())))); layoutNodesHelper(shownPartition.get(false), shownPartition.get(true), minY); minY = maxY.get(); @@ -508,9 +511,9 @@ public final class EventDetailChart extends XYChart impl } else { shownPartition = nodeMap.values().stream() .sorted(Comparator.comparing(AbstractDetailViewNode::getStartMillis)) - .collect(Collectors.partitioningBy(node -> getBundleFilters().stream() - .allMatch(filter -> filter.test(node.getDescription())))); - layoutNodesHelper(shownPartition.get(false), shownPartition.get(true), 0); + .collect(Collectors.partitioningBy(node -> getQuickHideMasks().stream() + .anyMatch(mask -> mask.equals(node.getDescription())))); + layoutNodesHelper(shownPartition.get(true), shownPartition.get(false), 0); } setCursor(null); requiresLayout = false; @@ -756,8 +759,8 @@ public final class EventDetailChart extends XYChart impl return alternateLayout; } - ObservableList getBundleFilters() { - return bundleFilters; + ObservableList getQuickHideMasks() { + return quickHideMasks; } private class DetailIntervalSelector extends IntervalSelector { @@ -798,4 +801,36 @@ public final class EventDetailChart extends XYChart impl void applySelectionEffect(DetailViewNode c1, Boolean selected) { c1.applySelectionEffect(selected); } + + public class HideBundleAction extends Action { + + /** + * + * @param description the value of description + */ + public HideBundleAction(final EventBundle bundle) { + super("Hide"); + setGraphic(new ImageView(HIDE)); + setEventHandler((ActionEvent t) -> { + getQuickHideMasks().add(bundle.getDescription()); + filteredEvents.getFilter().getSubFilters().add(new DescriptionFilter(bundle.getDescriptionLOD(), bundle.getDescription(), DescriptionFilter.FilterMode.EXCLUDE)); + setRequiresLayout(true); + requestChartLayout(); + }); + } + } + + public class UnhideBundleAction extends Action { + + public UnhideBundleAction(String description) { + + super("Unhide"); + setGraphic(new ImageView(SHOW)); + setEventHandler((ActionEvent t) -> { + getQuickHideMasks().removeAll(description); + setRequiresLayout(true); + requestChartLayout(); + }); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/tree/NavPanel.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/tree/NavPanel.java index 160050bcf0..9fdea6af2f 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/tree/NavPanel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/tree/NavPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.timeline.ui.detailview.tree; +import com.google.common.collect.ImmutableList; import java.util.Arrays; import java.util.Comparator; import javafx.application.Platform; @@ -36,13 +37,13 @@ import javafx.scene.layout.BorderPane; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; +import org.controlsfx.control.action.ActionUtils; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.timeline.FXMLConstructor; import org.sleuthkit.autopsy.timeline.TimeLineController; import org.sleuthkit.autopsy.timeline.TimeLineView; import org.sleuthkit.autopsy.timeline.datamodel.EventCluster; import org.sleuthkit.autopsy.timeline.datamodel.FilteredEventsModel; -import org.sleuthkit.autopsy.timeline.filters.DescriptionFilter; import org.sleuthkit.autopsy.timeline.ui.detailview.DetailViewNode; import org.sleuthkit.autopsy.timeline.ui.detailview.DetailViewPane; @@ -144,30 +145,35 @@ public class NavPanel extends BorderPane implements TimeLineView { ImageView imageView = new ImageView(item.getType().getFXImage()); setGraphic(new StackPane(rect, imageView)); - detailViewPane.getBundleFilters().addListener((Observable observable) -> { - asdasd(item, rect, imageView); + detailViewPane.getQuickHideMasks().addListener((Observable observable) -> { + configureHiddenState(item, rect, imageView); }); - asdasd(item, rect, imageView); + configureHiddenState(item, rect, imageView); } else { setText(null); setTooltip(null); setGraphic(null); + setContextMenu(null); } + } - private void asdasd(NavTreeNode item, Rectangle rect, ImageView imageView) { - if (detailViewPane.getBundleFilters().stream().allMatch((DescriptionFilter t) -> t.test(item.getDescription())) == false) { + private void configureHiddenState(NavTreeNode item, Rectangle rect, ImageView imageView) { + if (detailViewPane.getQuickHideMasks().stream().anyMatch(mask -> mask.equals(item.getDescription()))) { setTextFill(Color.gray(0, .6)); imageView.setOpacity(.6); rect.setStroke(item.getType().getColor().deriveColor(0, .6, 1, .6)); rect.setFill(item.getType().getColor().deriveColor(0, .6, .6, 0.1)); + setContextMenu(ActionUtils.createContextMenu(ImmutableList.of(detailViewPane.newUnhideBundleAction(item.getDescription())))); } else { setTextFill(Color.BLACK); imageView.setOpacity(1); rect.setStroke(item.getType().getColor()); rect.setFill(item.getType().getColor().deriveColor(0, 1, 1, 0.1)); +// setContextMenu(ActionUtils.createContextMenu(ImmutableList.of(detailViewPane.newHideBundleAction(item.getDescription())))); } } } + } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/tree/RootItem.java b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/tree/RootItem.java index cb15a0b622..818a053823 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/tree/RootItem.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/detailview/tree/RootItem.java @@ -22,7 +22,6 @@ import java.util.Comparator; import java.util.HashMap; import java.util.Map; import javafx.application.Platform; -import javafx.collections.FXCollections; import javafx.scene.control.TreeItem; import org.sleuthkit.autopsy.timeline.datamodel.EventCluster; import org.sleuthkit.autopsy.timeline.datamodel.EventBundle; @@ -69,8 +68,7 @@ class RootItem extends NavTreeItem { Platform.runLater(() -> { synchronized (getChildren()) { getChildren().add(newTreeItem); - - FXCollections.sort(getChildren(), TreeComparator.Type); + getChildren().sort(TreeComparator.Type); } }); } else { 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 31e8a6e50b..491bc86803 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/ui/filtering/FilterSetPanel.java @@ -89,7 +89,7 @@ final public class FilterSetPanel extends BorderPane implements TimeLineView { assert applyButton != null : "fx:id=\"applyButton\" was not injected: check your FXML file 'FilterSetPanel.fxml'."; // NON-NLS applyButton.setOnAction(e -> { - controller.pushFilters((RootFilter) filterTreeTable.getRoot().getValue().copyOf()); + controller.pushFilters((RootFilter) filterTreeTable.getRoot().getValue()); }); applyButton.setText(Bundle.FilterSetPanel_applyButton_text()); defaultButton.setText(Bundle.FilterSetPanel_defaultButton_text()); @@ -173,7 +173,6 @@ final public class FilterSetPanel extends BorderPane implements TimeLineView { @Override public void setModel(FilteredEventsModel filteredEvents) { this.filteredEvents = filteredEvents; - filteredEvents.registerForEvents(this); refresh(); this.filteredEvents.filterProperty().addListener((Observable o) -> { refresh(); @@ -182,7 +181,7 @@ final public class FilterSetPanel extends BorderPane implements TimeLineView { private void refresh() { Platform.runLater(() -> { - filterTreeTable.setRoot(new FilterTreeItem(filteredEvents.getFilter().copyOf(), expansionMap)); + filterTreeTable.setRoot(new FilterTreeItem(filteredEvents.getFilter(), expansionMap)); }); } }