27 package org.sleuthkit.autopsy.timeline.ui.detailview;
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;
52 final class DateAxis
extends Axis<DateTime> {
54 private ObjectProperty<DateTime> lowerBound =
new ObjectPropertyBase<DateTime>() {
56 protected void invalidated() {
57 if (!isAutoRanging()) {
64 public Object getBean() {
69 public String getName() {
79 private DateTime maxDate;
86 private DateTime minDate;
88 private RangeDivisionInfo rangeDivisionInfo;
90 private final ReadOnlyDoubleWrapper tickSpacing =
new ReadOnlyDoubleWrapper();
92 private final ObjectProperty<DateTime> upperBound =
new ObjectPropertyBase<DateTime>() {
94 protected void invalidated() {
95 if (!isAutoRanging()) {
102 public Object getBean() {
103 return DateAxis.this;
107 public String getName() {
115 setAutoRanging(
false);
119 public double getDisplayPosition(DateTime date) {
120 final double length = -200 + (getSide().isHorizontal() ? getWidth() : getHeight());
123 double diff = getUpperBound().getMillis() - getLowerBound().getMillis();
127 double range = length - getZeroPosition();
131 double d = (date.getMillis() - getLowerBound().getMillis()) / diff;
134 if (getSide().isVertical()) {
135 return getHeight() - d * range + getZeroPosition();
137 return d * range + getZeroPosition();
148 public final DateTime getLowerBound() {
149 return lowerBound.get();
159 public final void setLowerBound(DateTime date) {
160 lowerBound.set(date);
170 public final DateTime getUpperBound() {
171 return upperBound.get();
181 public final void setUpperBound(DateTime date) {
182 upperBound.set(date);
186 public DateTime getValueForDisplay(
double displayPosition) {
187 final double length = - 200 + (getSide().isHorizontal() ? getWidth() : getHeight());
190 double diff = getUpperBound().getMillis() - getLowerBound().getMillis();
194 double range = length - getZeroPosition();
196 if (getSide().isVertical()) {
199 return new DateTime((
long) ((displayPosition - getZeroPosition() - getHeight()) / -range * diff + getLowerBound().getMillis()), TimeLineController.getJodaTimeZone());
203 return new DateTime((
long) ((displayPosition - getZeroPosition()) / range * diff + getLowerBound().getMillis()), TimeLineController.getJodaTimeZone());
208 public double getZeroPosition() {
213 public void invalidateRange(List<DateTime> list) {
214 super.invalidateRange(list);
216 Collections.sort(list);
217 if (list.isEmpty()) {
218 minDate = maxDate =
new DateTime();
219 }
else if (list.size() == 1) {
220 minDate = maxDate = list.get(0);
221 }
else if (list.size() > 1) {
222 minDate = list.get(0);
223 maxDate = list.get(list.size() - 1);
228 public boolean isValueOnAxis(DateTime date) {
229 return date.getMillis() > getLowerBound().getMillis() && date.getMillis() < getUpperBound().getMillis();
233 public double toNumericValue(DateTime date) {
234 return date.getMillis();
238 public DateTime toRealValue(
double v) {
239 return new DateTime((
long) v);
243 protected Object autoRange(
double length) {
244 if (isAutoRanging()) {
245 return new Interval(minDate, maxDate);
247 if (getLowerBound() == null || getUpperBound() == null) {
255 protected List<DateTime> calculateTickValues(
double length, Object range) {
256 List<DateTime> tickDates =
new ArrayList<>();
260 rangeDivisionInfo = RangeDivisionInfo.getRangeDivisionInfo((Interval) range);
261 final DateTime lowerBound1 = getLowerBound();
262 final DateTime upperBound1 = getUpperBound();
264 if (lowerBound1 == null || upperBound1 == null) {
267 DateTime lower = lowerBound1.withZone(TimeLineController.getJodaTimeZone());
268 DateTime upper = upperBound1.withZone(TimeLineController.getJodaTimeZone());
270 DateTime current = lower;
272 while (current.isBefore(upper)) {
273 tickDates.add(current);
274 current = current.plus(rangeDivisionInfo.getPeriodSize().getPeriod());
278 tickDates.add(upper);
284 if (tickDates.size() > 2) {
285 DateTime secondDate = tickDates.get(1);
286 DateTime thirdDate = tickDates.get(2);
287 DateTime lastDate = tickDates.get(tickDates.size() - 2);
288 DateTime previousLastDate = tickDates.get(tickDates.size() - 3);
291 if (secondDate.getMillis() - lower.getMillis() < (thirdDate.getMillis() - secondDate.getMillis()) / 2) {
292 tickDates.remove(lower);
297 if (upper.getMillis() - lastDate.getMillis() < (lastDate.getMillis() - previousLastDate.getMillis()) / 2) {
298 tickDates.remove(lastDate);
302 if (tickDates.size() >= 2) {
303 tickSpacing.set(getDisplayPosition(tickDates.get(1)) - getDisplayPosition(tickDates.get(0)));
304 }
else if (tickDates.size() >= 4) {
305 tickSpacing.set(getDisplayPosition(tickDates.get(2)) - getDisplayPosition(tickDates.get(1)));
311 protected Object getRange() {
313 return new Interval(getLowerBound(), getUpperBound());
317 protected String getTickMarkLabel(DateTime date) {
318 return rangeDivisionInfo.getTickFormatter().print(date);
322 protected void layoutChildren() {
323 super.layoutChildren();
327 protected void setRange(Object range,
boolean animating) {
329 rangeDivisionInfo = RangeDivisionInfo.getRangeDivisionInfo((Interval) range);
331 setLowerBound(
new DateTime(rangeDivisionInfo.getLowerBound()));
332 setUpperBound(
new DateTime(rangeDivisionInfo.getUpperBound()));
335 ReadOnlyDoubleProperty getTickSpacing() {
336 return tickSpacing.getReadOnlyProperty();