Autopsy  4.19.3
Graphical digital forensics platform for The Sleuth Kit and other tools.
FilterSetPanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2013-2019 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.timeline.ui.filtering;
20 
21 import java.util.Arrays;
22 import javafx.application.Platform;
23 import javafx.beans.InvalidationListener;
24 import javafx.beans.binding.Bindings;
25 import javafx.collections.FXCollections;
26 import javafx.collections.ObservableMap;
27 import javafx.event.EventHandler;
28 import javafx.fxml.FXML;
29 import javafx.scene.control.Button;
30 import javafx.scene.control.Cell;
31 import javafx.scene.control.ListCell;
32 import javafx.scene.control.ListView;
33 import javafx.scene.control.SplitPane;
34 import javafx.scene.control.TitledPane;
35 import javafx.scene.control.TreeTableColumn;
36 import javafx.scene.control.TreeTableView;
37 import javafx.scene.image.Image;
38 import javafx.scene.image.ImageView;
39 import javafx.scene.input.KeyEvent;
40 import javafx.scene.layout.BorderPane;
41 import org.controlsfx.control.action.Action;
42 import org.controlsfx.control.action.ActionUtils;
43 import org.openide.util.NbBundle;
51 
58 final public class FilterSetPanel extends BorderPane {
59 
60  private static final Image TICK = new Image("org/sleuthkit/autopsy/timeline/images/tick.png"); //NON-NLS
61 
62  @FXML
63  private Button applyButton;
64 
65  @FXML
66  private Button defaultButton;
67 
68  @FXML
69  private TreeTableView<FilterState<?>> filterTreeTable;
70 
71  @FXML
72  private TreeTableColumn< FilterState< ?>, FilterState<?>> treeColumn;
73 
74  @FXML
75  private TreeTableColumn<FilterState<?>, FilterState<?>> legendColumn;
76 
77  @FXML
78  private ListView<DescriptionFilterState> hiddenDescriptionsListView;
79  @FXML
80  private TitledPane hiddenDescriptionsPane;
81  @FXML
82  private SplitPane splitPane;
83 
84  private final EventsModel filteredEvents;
86 
91  private final ObservableMap< Object, Boolean> expansionMap = FXCollections.observableHashMap();
92  private double dividerPosition;
93 
94  @NbBundle.Messages({
95  "FilterSetPanel.defaultButton.text=Reset",
96  "FilsetSetPanel.hiddenDescriptionsPane.displayName=Hidden Descriptions"})
97  @FXML
98  void initialize() {
99  assert applyButton != null : "fx:id=\"applyButton\" was not injected: check your FXML file 'FilterSetPanel.fxml'."; // NON-NLS
100 
101  ActionUtils.configureButton(new ApplyFiltersAction(), applyButton);
102  ActionUtils.configureButton(new ResetFilters(Bundle.FilterSetPanel_defaultButton_text(), controller), defaultButton);
103 
104  hiddenDescriptionsPane.setText(Bundle.FilsetSetPanel_hiddenDescriptionsPane_displayName());
105  //remove column headers via css.
106  filterTreeTable.getStylesheets().addAll(FilterSetPanel.class.getResource("FilterTable.css").toExternalForm()); // NON-NLS
107 
108  //use row factory as hook to attach context menus to.
109  filterTreeTable.setRowFactory(ttv -> new FilterTreeTableRow());
110 
111  //configure tree column to show name of filter and checkbox
112  treeColumn.setCellValueFactory(cellDataFeatures -> cellDataFeatures.getValue().valueProperty());
113  treeColumn.setCellFactory(col -> new FilterCheckBoxCellFactory<>().forTreeTable(col));
114 
115  //configure legend column to show legend (or othe supplamantal ui, eg, text field for text filter)
116  legendColumn.setCellValueFactory(cellDataFeatures -> cellDataFeatures.getValue().valueProperty());
117  legendColumn.setCellFactory(col -> new LegendCell(this.controller));
118 
119  //type is the only filter expanded initialy
120  expansionMap.put(filteredEvents.getEventFilterState().getFilter(), true);
121  expansionMap.put(filteredEvents.getEventFilterState().getEventTypeFilterState().getFilter(), true);
122  expansionMap.put(filteredEvents.getEventFilterState().getDataSourcesFilterState().getFilter(), true);
123  expansionMap.put(filteredEvents.getEventFilterState().getFileTypesFilterState().getFilter(), true);
124 
125  InvalidationListener applyFiltersListener = observable -> applyFilters();
126 
127  filteredEvents.eventTypesHierarchyLevelProperty().addListener(applyFiltersListener);
128  filteredEvents.descriptionLODProperty().addListener(applyFiltersListener);
129  filteredEvents.timeRangeProperty().addListener(applyFiltersListener);
130 
131  filteredEvents.eventFilterProperty().addListener(observable -> refreshFilterUI());
132  refreshFilterUI();
133 
134  hiddenDescriptionsListView.setItems(controller.getQuickHideFilters());
135  hiddenDescriptionsListView.setCellFactory(listView -> getNewDescriptionFilterListCell());
136 
137  //show and hide the "hidden descriptions" panel depending on the current view mode
138  controller.viewModeProperty().addListener(observable -> {
139  switch (controller.getViewMode()) {
140  case COUNTS:
141  case LIST:
142  //hide for counts and lists, but remember divider position
143  dividerPosition = splitPane.getDividerPositions()[0];
144  splitPane.setDividerPositions(1);
145  hiddenDescriptionsPane.setExpanded(false);
146  hiddenDescriptionsPane.setCollapsible(false);
147  hiddenDescriptionsPane.setDisable(true);
148  break;
149  case DETAIL:
150  //show and restore divider position.
151  splitPane.setDividerPositions(dividerPosition);
152  hiddenDescriptionsPane.setDisable(false);
153  hiddenDescriptionsPane.setCollapsible(true);
154  hiddenDescriptionsPane.setExpanded(true);
155  hiddenDescriptionsPane.setCollapsible(false);
156  break;
157  default:
158  throw new UnsupportedOperationException("Unknown ViewMode: " + controller.getViewMode());
159  }
160  });
161 
162  //Block the default treetable keyboard events.
163  filterTreeTable.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() {
164  @Override
165  public void handle(KeyEvent event) {
166  event.consume();
167  }
168  });
169  }
170 
171  public FilterSetPanel(TimeLineController controller) {
172  this.controller = controller;
173  this.filteredEvents = controller.getEventsModel();
174  FXMLConstructor.construct(this, "FilterSetPanel.fxml"); // NON-NLS
175  }
176 
177  private void refreshFilterUI() {
178  Platform.runLater(()
179  -> filterTreeTable.setRoot(new FilterTreeItem(filteredEvents.eventFilterProperty().get().copyOf(), expansionMap)));
180  }
181 
182  private void applyFilters() {
183  Platform.runLater(() -> {
184  controller.pushFilters(((RootFilterState) filterTreeTable.getRoot().getValue().copyOf()));
185  });
186  }
187 
188  private ListCell<DescriptionFilterState> getNewDescriptionFilterListCell() {
189  final ListCell<DescriptionFilterState> cell = new FilterCheckBoxCellFactory< DescriptionFilterState>().forList();
190  cell.itemProperty().addListener(itemProperty -> {
191  if (cell.getItem() == null) {
192  cell.setContextMenu(null);
193  } else {
194  cell.setContextMenu(ActionUtils.createContextMenu(Arrays.asList(
195  new RemoveDescriptionFilterAction(controller, cell))
196  ));
197  }
198  });
199  return cell;
200  }
201 
202  @NbBundle.Messages({"FilterSetPanel.applyButton.text=Apply",
203  "FilterSetPanel.applyButton.longText=(Re)Apply filters"})
204  private class ApplyFiltersAction extends Action {
205 
207  super(Bundle.FilterSetPanel_applyButton_text());
208  setLongText(Bundle.FilterSetPanel_applyButton_longText());
209  setGraphic(new ImageView(TICK));
210  setEventHandler(actionEvent -> applyFilters());
211  }
212  }
213 
214  @NbBundle.Messages({
215  "FilterSetPanel.hiddenDescriptionsListView.unhideAndRemove=Unhide and remove from list",
216  "FilterSetPanel.hiddenDescriptionsListView.remove=Remove from list",})
217  private static class RemoveDescriptionFilterAction extends Action {
218 
219  private static final Image SHOW = new Image("/org/sleuthkit/autopsy/timeline/images/eye--plus.png"); // NON-NLS
220 
221  RemoveDescriptionFilterAction(TimeLineController controller, Cell<DescriptionFilterState> cell) {
222  super(actionEvent -> controller.getQuickHideFilters().remove(cell.getItem()));
223  setGraphic(new ImageView(SHOW));
224  textProperty().bind(
225  Bindings.when(cell.getItem().selectedProperty())
226  .then(Bundle.FilterSetPanel_hiddenDescriptionsListView_unhideAndRemove())
227  .otherwise(Bundle.FilterSetPanel_hiddenDescriptionsListView_remove()));
228  }
229  }
230 }
final ReadOnlyObjectWrapper< TimelineEventType.HierarchyLevel > eventTypesHierarchyLevelProperty
synchronized RootFilterState getEventFilterState()
ListCell< DescriptionFilterState > getNewDescriptionFilterListCell()
CompoundFilterState< FileTypeFilter, FileTypesFilter > getFileTypesFilterState()
ListView< DescriptionFilterState > hiddenDescriptionsListView
TreeTableColumn< FilterState< ?>, FilterState<?> > treeColumn
final ReadOnlyObjectWrapper< Interval > timeRangeProperty
CompoundFilterState< EventTypeFilter, EventTypeFilter > getEventTypeFilterState()
synchronized void pushFilters(RootFilterState filter)
synchronized ReadOnlyObjectProperty< ViewMode > viewModeProperty()
ObservableList< DescriptionFilterState > getQuickHideFilters()
synchronized ReadOnlyObjectProperty< TimelineLevelOfDetail > descriptionLODProperty()
CompoundFilterState< DataSourceFilter, DataSourcesFilter > getDataSourcesFilterState()
final ObservableMap< Object, Boolean > expansionMap
static void construct(Node node, String fxmlFileName)
synchronized ReadOnlyObjectProperty< RootFilterState > eventFilterProperty()
TreeTableColumn< FilterState<?>, FilterState<?> > legendColumn

Copyright © 2012-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.