Autopsy  4.19.3
Graphical digital forensics platform for The Sleuth Kit and other tools.
ZoomSettingsPane.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2013-18 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.zooming;
20 
21 import java.lang.reflect.InvocationTargetException;
22 import java.util.function.Function;
23 import java.util.logging.Level;
24 import javafx.application.Platform;
25 import javafx.beans.InvalidationListener;
26 import javafx.beans.binding.BooleanBinding;
27 import javafx.beans.property.ReadOnlyObjectProperty;
28 import javafx.fxml.FXML;
29 import javafx.scene.control.Label;
30 import javafx.scene.control.Slider;
31 import javafx.scene.control.TitledPane;
32 import javafx.util.StringConverter;
33 import org.controlsfx.control.Notifications;
34 import org.openide.util.NbBundle;
41 import org.sleuthkit.datamodel.TimelineEvent;
42 import org.sleuthkit.datamodel.TskCoreException;
43 import org.sleuthkit.datamodel.TimelineEventType;
44 import org.sleuthkit.datamodel.TimelineLevelOfDetail;
45 
52 public class ZoomSettingsPane extends TitledPane {
53 
54  private static final Logger logger = Logger.getLogger(ZoomSettingsPane.class.getName());
55 
56  @FXML
57  private Label zoomLabel;
58 
59  @FXML
60  private Label descrLODLabel;
61  @FXML
62  private Slider descrLODSlider;
63 
64  @FXML
65  private Label typeZoomLabel;
66  @FXML
67  private Slider typeZoomSlider;
68 
69  @FXML
70  private Label timeUnitLabel;
71  @FXML
72  private Slider timeUnitSlider;
73 
75  private final EventsModel filteredEvents;
76 
82  public ZoomSettingsPane(TimeLineController controller) {
83  this.controller = controller;
84  this.filteredEvents = controller.getEventsModel();
85  FXMLConstructor.construct(this, "ZoomSettingsPane.fxml"); // NON-NLS
86  }
87 
88  @NbBundle.Messages({
89  "ZoomSettingsPane.descrLODLabel.text=Description Detail:",
90  "ZoomSettingsPane.typeZoomLabel.text=Event Type:",
91  "ZoomSettingsPane.timeUnitLabel.text=Time Units:",
92  "ZoomSettingsPane.zoomLabel.text=Zoom"})
93  public void initialize() {
94  zoomLabel.setText(Bundle.ZoomSettingsPane_zoomLabel_text());
95 
96  typeZoomSlider.setMin(1); //don't show ROOT_TYPE
97  typeZoomSlider.setMax(TimelineEventType.HierarchyLevel.values().length - 1);
98  configureSliderListeners(typeZoomSlider,
99  controller::pushEventTypeZoom,
100  filteredEvents.eventTypesHierarchyLevelProperty(),
101  TimelineEventType.HierarchyLevel.class,
102  TimelineEventType.HierarchyLevel::ordinal,
103  Function.identity());
104  typeZoomLabel.setText(Bundle.ZoomSettingsPane_typeZoomLabel_text());
105 
106  descrLODSlider.setMax(TimelineLevelOfDetail.values().length - 1);
107  configureSliderListeners(descrLODSlider,
108  controller::pushDescrLOD,
109  filteredEvents.descriptionLODProperty(),
110  TimelineLevelOfDetail.class,
111  TimelineLevelOfDetail::ordinal,
112  Function.identity());
113  descrLODLabel.setText(Bundle.ZoomSettingsPane_descrLODLabel_text());
114  //the description slider is only usefull in the detail view
115  descrLODSlider.disableProperty().bind(controller.viewModeProperty().isEqualTo(ViewMode.COUNTS));
116 
124  timeUnitSlider.setMax(TimeUnits.values().length - 2);
125  configureSliderListeners(timeUnitSlider,
126  controller::pushTimeUnit,
127  filteredEvents.timeRangeProperty(),
128  TimeUnits.class,
129  //for the purposes of this slider we want the TimeUnit one bigger than RangeDivision indicates
130  modelTimeRange -> RangeDivision.getRangeDivision(modelTimeRange, TimeLineController.getJodaTimeZone()).getPeriodSize().ordinal() - 1,
131  index -> index + 1); //compensate for the -1 above when mapping to the Enum whose displayName will be shown at index
132  timeUnitLabel.setText(Bundle.ZoomSettingsPane_timeUnitLabel_text());
133 
134  //hide the whole panel in list mode
135  BooleanBinding notListMode = controller.viewModeProperty().isNotEqualTo(ViewMode.LIST);
136  visibleProperty().bind(notListMode);
137  managedProperty().bind(notListMode);
138 
139  }
140 
178  @NbBundle.Messages({"ZoomSettingsPane.sliderChange.errorText=Error responding to slider value change."})
179 
180  private <DriverType, EnumType extends Enum<EnumType>> void configureSliderListeners(
181  Slider slider,
182  CheckedConsumer<EnumType> sliderValueConsumer,
183  ReadOnlyObjectProperty<DriverType> modelProperty,
184  Class<EnumType> enumClass,
185  Function<DriverType, Integer> driverValueMapper,
186  Function<Integer, Integer> labelIndexMapper) {
187 
188  //set the tick labels to the enum displayNames
189  slider.setLabelFormatter(new EnumSliderLabelFormatter<>(enumClass, labelIndexMapper));
190 
191  //make a listener to responds to slider value changes (by updating the view)
192  final InvalidationListener sliderListener = observable -> {
193  //only process event if the slider value is not changing (user has released slider thumb)
194  if (slider.isValueChanging() == false) {
195  //convert slider value to EnumType and pass to consumer
196  EnumType sliderValueAsEnum = enumClass.getEnumConstants()[Math.round((float) slider.getValue())];
197  try {
198  sliderValueConsumer.accept(sliderValueAsEnum);
199  } catch (TskCoreException exception) {
200  logger.log(Level.SEVERE, "Error responding to slider value change.", exception);
201  Notifications.create().owner(getScene().getWindow())
202  .text(Bundle.ZoomSettingsPane_sliderChange_errorText())
203  .showError();
204  }
205  }
206  };
207  //attach listener
208  slider.valueProperty().addListener(sliderListener);
209  slider.valueChangingProperty().addListener(sliderListener);
210 
211  //set intial value of slider
212  slider.setValue(driverValueMapper.apply(modelProperty.get()));
213 
214  //handle changes in the model property
215  modelProperty.addListener(modelProp -> {
216  //remove listener to avoid circular updates
217  slider.valueProperty().removeListener(sliderListener);
218  slider.valueChangingProperty().removeListener(sliderListener);
219 
220  Platform.runLater(() -> {
221  //sync value of slider to model property value
222  slider.setValue(driverValueMapper.apply(modelProperty.get()));
223 
224  //reattach listener
225  slider.valueProperty().addListener(sliderListener);
226  slider.valueChangingProperty().addListener(sliderListener);
227  });
228  });
229  }
230 
239  static private class EnumSliderLabelFormatter<EnumType extends Enum<EnumType>> extends StringConverter<Double> {
240 
244  private final Class<EnumType> clazz;
250  private final Function<Integer, Integer> indexAdjsuter;
251 
252  EnumSliderLabelFormatter(Class<EnumType> enumClass, Function<Integer, Integer> indexMapper) {
253  this.clazz = enumClass;
254  this.indexAdjsuter = indexMapper;
255  }
256 
257  @Override
258  public String toString(Double dbl) {
259  /* Get the displayName of the EnumType whose index is the given dbl
260  * after it has been narrowed and then adjusted. At one point there
261  * was an interface, DisplayNameProvider, but that was inappropriate
262  * to put in TSK only to support these sliders, so now we use
263  * reflection instead.
264  */
265  EnumType enumConstant = clazz.getEnumConstants()[indexAdjsuter.apply(dbl.intValue())];
266  try {
267  return (String) clazz.getMethod("getDisplayName", (Class<?>[]) null).invoke(enumConstant, (Object[]) null);
268  } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
269  return enumConstant.toString();
270  }
271  }
272 
273  @Override
274  public Double fromString(String string) {
275  throw new UnsupportedOperationException("This method should not be used. This EnumSliderLabelFormatter is being used in an unintended way.");
276  }
277  }
278 
284  @FunctionalInterface
285  private interface CheckedConsumer<T> {
286 
287  void accept(T input) throws TskCoreException;
288  }
289 }
final ReadOnlyObjectWrapper< TimelineEventType.HierarchyLevel > eventTypesHierarchyLevelProperty
final ReadOnlyObjectWrapper< Interval > timeRangeProperty
synchronized ReadOnlyObjectProperty< ViewMode > viewModeProperty()
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
synchronized ReadOnlyObjectProperty< TimelineLevelOfDetail > descriptionLODProperty()
static void construct(Node node, String fxmlFileName)
static RangeDivision getRangeDivision(Interval timeRange, DateTimeZone timeZone)

Copyright © 2012-2022 Basis Technology. Generated on: Mon Nov 28 2022
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.