Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
DateAxis.java
Go to the documentation of this file.
1 /*
2  * The MIT License (MIT)
3  *
4  * Copyright (c) 2013, Christian Schudt
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  *
25  *
26  */
27 package org.sleuthkit.autopsy.timeline.ui.detailview;
28 
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.List;
32 import javafx.beans.property.ObjectProperty;
33 import javafx.beans.property.ObjectPropertyBase;
34 import javafx.beans.property.ReadOnlyDoubleProperty;
35 import javafx.beans.property.ReadOnlyDoubleWrapper;
36 import javafx.scene.chart.Axis;
37 import org.joda.time.DateTime;
38 import org.joda.time.Interval;
41 
52 final class DateAxis extends Axis<DateTime> {
53 
54  private ObjectProperty<DateTime> lowerBound = new ObjectPropertyBase<DateTime>(new DateTime(0)) {
55  @Override
56  protected void invalidated() {
57  if (!isAutoRanging()) {
58  invalidateRange();
59  requestAxisLayout();
60  }
61  }
62 
63  @Override
64  public Object getBean() {
65  return DateAxis.this;
66  }
67 
68  @Override
69  public String getName() {
70  return "lowerBound"; // NON-NLS
71  }
72  };
73 
79  private DateTime maxDate;
80 
86  private DateTime minDate;
87 
88  private RangeDivision rangeDivisionInfo;
89 
90  private final ReadOnlyDoubleWrapper tickSpacing = new ReadOnlyDoubleWrapper();
91 
92  private final ObjectProperty<DateTime> upperBound = new ObjectPropertyBase<DateTime>(new DateTime(1)) {
93  @Override
94  protected void invalidated() {
95  if (!isAutoRanging()) {
96  invalidateRange();
97  requestAxisLayout();
98  }
99  }
100 
101  @Override
102  public Object getBean() {
103  return DateAxis.this;
104  }
105 
106  @Override
107  public String getName() {
108  return "upperBound"; // NON-NLS
109  }
110  };
111 
116  DateAxis() {
117  setTickLabelGap(0);
118  setAutoRanging(false);
119  setTickLabelsVisible(false);
120  setTickLength(0);
121  setTickMarkVisible(false);
122  }
123 
124  @Override
125  public double getDisplayPosition(DateTime date) {
126  final double length = -200 + (getSide().isHorizontal() ? getWidth() : getHeight());
127 
128  // Get the difference between the max and min date.
129  double diff = getUpperBound().getMillis() - getLowerBound().getMillis();
130 
131  // Get the actual range of the visible area.
132  // The minimal date should start at the zero position, that's why we subtract it.
133  double range = length - getZeroPosition();
134 
135  // Then get the difference from the actual date to the min date and divide it by the total difference.
136  // We get a value between 0 and 1, if the date is within the min and max date.
137  double d = (date.getMillis() - getLowerBound().getMillis()) / diff;
138 
139  // Multiply this percent value with the range and add the zero offset.
140  if (getSide().isVertical()) {
141  return getHeight() - d * range + getZeroPosition();
142  } else {
143  return d * range + getZeroPosition();
144  }
145  }
146 
154  public DateTime getLowerBound() {
155  return lowerBound.get();
156  }
157 
165  public void setLowerBound(DateTime date) {
166  lowerBound.set(date);
167  }
168 
176  public DateTime getUpperBound() {
177  return upperBound.get();
178  }
179 
187  public void setUpperBound(DateTime date) {
188  upperBound.set(date);
189  }
190 
191  @Override
192  public DateTime getValueForDisplay(double displayPosition) {
193  final double length = - 200 + (getSide().isHorizontal() ? getWidth() : getHeight());
194 
195  // Get the difference between the max and min date.
196  double diff = getUpperBound().getMillis() - getLowerBound().getMillis();
197 
198  // Get the actual range of the visible area.
199  // The minimal date should start at the zero position, that's why we subtract it.
200  double range = length - getZeroPosition();
201 
202  if (getSide().isVertical()) {
203  // displayPosition = getHeight() - ((date - lowerBound) / diff) * range + getZero
204  // date = displayPosition - getZero - getHeight())/range * diff + lowerBound
205  return new DateTime((long) ((displayPosition - getZeroPosition() - getHeight()) / -range * diff + getLowerBound().getMillis()), TimeLineController.getJodaTimeZone());
206  } else {
207  // displayPosition = ((date - lowerBound) / diff) * range + getZero
208  // date = displayPosition - getZero)/range * diff + lowerBound
209  return new DateTime((long) ((displayPosition - getZeroPosition()) / range * diff + getLowerBound().getMillis()), TimeLineController.getJodaTimeZone());
210  }
211  }
212 
213  @Override
214  public double getZeroPosition() {
215  return 0;
216  }
217 
218  @Override
219  public void invalidateRange(List<DateTime> list) {
220  super.invalidateRange(list);
221 
222  Collections.sort(list);
223  if (list.isEmpty()) {
224  minDate = maxDate = new DateTime();
225  } else if (list.size() == 1) {
226  minDate = maxDate = list.get(0);
227  } else if (list.size() > 1) {
228  minDate = list.get(0);
229  maxDate = list.get(list.size() - 1);
230  }
231  }
232 
233  @Override
234  public boolean isValueOnAxis(DateTime date) {
235  return date.getMillis() > getLowerBound().getMillis() && date.getMillis() < getUpperBound().getMillis();
236  }
237 
238  @Override
239  public double toNumericValue(DateTime date) {
240  return date.getMillis();
241  }
242 
243  @Override
244  public DateTime toRealValue(double v) {
245  return new DateTime((long) v);
246  }
247 
248  @Override
249  protected Interval autoRange(double length) {
250  if (isAutoRanging()) {
251  return new Interval(minDate, maxDate);
252  } else {
253  if (getLowerBound() == null || getUpperBound() == null) {
254  return null;
255  }
256  return getRange();
257  }
258  }
259 
260  @Override
261  protected List<DateTime> calculateTickValues(double length, Object range) {
262  List<DateTime> tickDates = new ArrayList<>();
263  if (range == null) {
264  return tickDates;
265  }
266  rangeDivisionInfo = RangeDivision.getRangeDivision((Interval) range, TimeLineController.getJodaTimeZone());
267  final DateTime lowerBound1 = getLowerBound();
268  final DateTime upperBound1 = getUpperBound();
269 
270  if (lowerBound1 == null || upperBound1 == null) {
271  return tickDates;
272  }
273  DateTime lower = lowerBound1.withZone(TimeLineController.getJodaTimeZone());
274  DateTime upper = upperBound1.withZone(TimeLineController.getJodaTimeZone());
275 
276  DateTime current = lower;
277  // Loop as long we exceeded the upper bound.
278  while (current.isBefore(upper)) {
279  tickDates.add(current);
280  current = current.plus(rangeDivisionInfo.getPeriodSize().toUnitPeriod());//.add(interval.interval, interval.amount);
281  }
282 
283  // At last add the upper bound.
284  tickDates.add(upper);
285 
286  // If there are at least three dates, check if the gap between the lower date and the second date is at least half the gap of the second and third date.
287  // Do the same for the upper bound.
288  // If gaps between dates are to small, remove one of them.
289  // This can occur, e.g. if the lower bound is 25.12.2013 and years are shown. Then the next year shown would be 2014 (01.01.2014) which would be too narrow to 25.12.2013.
290  if (tickDates.size() > 2) {
291  DateTime secondDate = tickDates.get(1);
292  DateTime thirdDate = tickDates.get(2);
293  DateTime lastDate = tickDates.get(tickDates.size() - 2);
294  DateTime previousLastDate = tickDates.get(tickDates.size() - 3);
295 
296  // If the second date is too near by the lower bound, remove it.
297  if (secondDate.getMillis() - lower.getMillis() < (thirdDate.getMillis() - secondDate.getMillis()) / 2) {
298  tickDates.remove(lower);
299  }
300 
301  // If difference from the upper bound to the last date is less than the half of the difference of the previous two dates,
302  // we better remove the last date, as it comes to close to the upper bound.
303  if (upper.getMillis() - lastDate.getMillis() < (lastDate.getMillis() - previousLastDate.getMillis()) / 2) {
304  tickDates.remove(lastDate);
305  }
306  }
307 
308  if (tickDates.size() >= 2) {
309  tickSpacing.set(getDisplayPosition(tickDates.get(1)) - getDisplayPosition(tickDates.get(0)));
310  } else if (tickDates.size() >= 4) {
311  tickSpacing.set(getDisplayPosition(tickDates.get(2)) - getDisplayPosition(tickDates.get(1)));
312  }
313  return tickDates;
314  }
315 
316  @Override
317  protected Interval getRange() {
318  return new Interval(getLowerBound(), getUpperBound());
319  }
320 
321  @Override
322  protected String getTickMarkLabel(DateTime date) {
323  return rangeDivisionInfo.getTickFormatter().print(date);
324  }
325 
331  @Override
332  protected void setRange(Object range, boolean animating) {
333  rangeDivisionInfo = RangeDivision.getRangeDivision((Interval) range, TimeLineController.getJodaTimeZone());
334  setLowerBound(new DateTime(rangeDivisionInfo.getLowerBound(), TimeLineController.getJodaTimeZone()));
335  setUpperBound(new DateTime(rangeDivisionInfo.getUpperBound(), TimeLineController.getJodaTimeZone()));
336  }
337 
338  ReadOnlyDoubleProperty getTickSpacing() {
339  return tickSpacing.getReadOnlyProperty();
340  }
341 }

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