From b290534f07829404e72692df15f3fd119273c7f8 Mon Sep 17 00:00:00 2001 From: jmillman Date: Wed, 23 Sep 2015 16:02:57 -0400 Subject: [PATCH] quick-hide/filter WIP 3 --- .../sleuthkit/autopsy/coreutils/History.java | 1 - .../autopsy/timeline/db/EventDB.java | 1 + .../timeline/filters/CompoundFilter.java | 2 - .../timeline/filters/DescriptionFilter.java | 6 +-- .../autopsy/timeline/images/eye--minus.png | Bin 0 -> 595 bytes .../autopsy/timeline/images/eye--plus.png | Bin 0 -> 661 bytes .../timeline/ui/AbstractVisualization.java | 2 +- .../ui/detailview/AbstractDetailViewNode.java | 30 +++-------- .../ui/detailview/DetailViewPane.java | 32 ++++++----- .../ui/detailview/EventDetailChart.java | 51 +++++++++++++++--- .../timeline/ui/detailview/tree/NavPanel.java | 18 ++++--- .../timeline/ui/detailview/tree/RootItem.java | 4 +- .../timeline/ui/filtering/FilterSetPanel.java | 5 +- 13 files changed, 88 insertions(+), 64 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/images/eye--minus.png create mode 100644 Core/src/org/sleuthkit/autopsy/timeline/images/eye--plus.png 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 0000000000000000000000000000000000000000..08b048eae310b10d71082f8edad7b081b79b98af GIT binary patch literal 595 zcmV-Z0<8UsP))U=I<(!Y-aX7<9>mi9o?H_F_AoLP-|H z4jl}~6vtoR_rvL6#}518BhI|{{l53}_jCy%=zqd>^#%y}Wnpw3+ygoY1OKA#C+L70 z_y~rM&N1Lg9xICSRM++GY&N@Tn&!1eqv7SGrfJh?G&(AkNcG_r_+$jk3I$2DBb8maYoJZW_OFc=IbmSqXXFbu&_ zES?BWI}p15NMI`AB+ zCf4iqZnfL(b?z9C$A1Nb!G5`1zNl8K7vb^v{T(4bJ(L`rG;P|h%(7N? zksjJjCUg*CEp!mX6%78ugHYL_SD6<<@ZcXH^f1|F6N?lSu~1OyVK)nzLJP&RAmY-) zDt2N!snUU!#|yklGG1}!`*B)`?XLgeCYLh z8Pu&(UmHGL$gOBJdZ$<{O8I<#$~4WfKp-G=yE+gk5@?KaR716-v9vtTpU19ityZh2 z>pCM8MPU?~%p)dAb4->mGn^G0=Bbu6q_v~Vd@L68;q--mzi+K8l}ce}6INEz*7wB3 zG&CAj80M*#G}vgK44zafm9b8zGv&gdf?zNRic*Hz*>je_<#K|<5&Uhii-DR?q~&ck z+n0L1J}8&VW+W0h?)7>{alN2v?;#Wt!Rz&5cMan4Gmti(!rjfKz2%qb&)Va+_vuu~ zz{DNhXf~VMxm@mhtyXJ`qR6}54xw6oBedIFAd2B1e!qX~UgLrN;)P3|Vx#;GY;a?6 z+hcIJ5imScj1eS^oJPixQ5rNC+%h}K`$6FJL?UtO`RWUG|MGx(*x-*~lRTI=-RpB# z<1>eIukveuH!v1QsMABlGMK(5&TKq;w?6|8RQr)GJc9)=@T%{z^&Jy$_0Iu-gNuNj v1N)Kxnid|R!PM==O+cYaVmRT1UjhsOT9g3B;L;7y00000NkvXXu0mjfDrh(C literal 0 HcmV?d00001 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)); }); } }