Package org.sleuthkit.autopsy.timeline.ui.countsview

Source Code of org.sleuthkit.autopsy.timeline.ui.countsview.EventCountsChart$IntegerOnlyStringConverter

/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.timeline.ui.countsview;

import java.util.Arrays;
import java.util.Collections;
import javafx.scene.chart.Axis;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.StackedBarChart;
import javafx.scene.control.ContextMenu;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.util.StringConverter;
import org.controlsfx.control.action.ActionGroup;
import org.controlsfx.control.action.ActionUtils;
import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.actions.Back;
import org.sleuthkit.autopsy.timeline.actions.Forward;
import org.sleuthkit.autopsy.timeline.events.FilteredEventsModel;
import org.sleuthkit.autopsy.timeline.ui.TimeLineChart;
import org.sleuthkit.autopsy.timeline.utils.RangeDivisionInfo;

/** Customized {@link StackedBarChart<String, Number>} used to display the event
* counts in {@link CountsViewPane} */
class EventCountsChart extends StackedBarChart<String, Number> implements TimeLineChart<String> {

    private ContextMenu contextMenu;

    private TimeLineController controller;

    private IntervalSelector<? extends String> intervalSelector;

    /** * the RangeDivisionInfo for the currently displayed time range,
     * used to correct the interval provided
     * {@link  EventCountsChart#intervalSelector} by padding the end with one
     * 'period' */
    private RangeDivisionInfo rangeInfo;

    EventCountsChart(CategoryAxis dateAxis, NumberAxis countAxis) {
        super(dateAxis, countAxis);
        //configure constant properties on axes and chart
        dateAxis.setAnimated(true);
        dateAxis.setLabel(null);
        dateAxis.setTickLabelsVisible(false);
        dateAxis.setTickLabelGap(0);

        countAxis.setLabel(NbBundle.getMessage(CountsViewPane.class, "CountsChartPane.numberOfEvents"));
        countAxis.setAutoRanging(false);
        countAxis.setLowerBound(0);
        countAxis.setAnimated(true);
        countAxis.setMinorTickCount(0);
        countAxis.setTickLabelFormatter(new IntegerOnlyStringConverter());

        setAlternativeRowFillVisible(true);
        setCategoryGap(2);
        setLegendVisible(false);
        setAnimated(true);
        setTitle(null);

        //use one handler with an if chain because it maintains state
        ChartDragHandler<String, EventCountsChart> dragHandler = new ChartDragHandler<>(this, getXAxis());
        setOnMousePressed(dragHandler);
        setOnMouseReleased(dragHandler);
        setOnMouseDragged(dragHandler);

        setOnMouseClicked((MouseEvent clickEvent) -> {
            contextMenu.hide();
            if (clickEvent.getButton() == MouseButton.SECONDARY && clickEvent.isStillSincePress()) {
                contextMenu.show(EventCountsChart.this, clickEvent.getScreenX(), clickEvent.getScreenY());
                clickEvent.consume();
            }
        });
    }

    @Override
    public void clearIntervalSelector() {
        getChartChildren().remove(intervalSelector);
        intervalSelector = null;
    }

    @Override
    public final synchronized void setController(TimeLineController controller) {
        this.controller = controller;
        setModel(this.controller.getEventsModel());
        //we have defered creating context menu until control is available
        contextMenu = ActionUtils.createContextMenu(
                Arrays.asList(new ActionGroup("Zoom History", new Back(controller), new Forward(controller))));
        contextMenu.setAutoHide(true);
    }

    @Override
    public IntervalSelector<? extends String> getIntervalSelector() {
        return intervalSelector;
    }

    @Override
    public void setIntervalSelector(IntervalSelector<? extends String> newIntervalSelector) {
        intervalSelector = newIntervalSelector;
        getChartChildren().add(getIntervalSelector());
    }

    @Override
    public void setModel(FilteredEventsModel filteredEvents) {
        filteredEvents.getRequestedZoomParamters().addListener(o -> {
            clearIntervalSelector();
            controller.selectEventIDs(Collections.emptyList());
        });
    }

    @Override
    public CountsIntervalSelector newIntervalSelector(double x, Axis<String> dateAxis) {
        return new CountsIntervalSelector(x, getHeight() - dateAxis.getHeight() - dateAxis.getTickLength(), dateAxis, controller);
    }

    /** used by {@link CountsViewPane#BarClickHandler} to close the context menu
     * when the bar menu is requested
     *
     * @return the context menu for this chart */
    ContextMenu getContextMenu() {
        return contextMenu;
    }

    void setRangeInfo(RangeDivisionInfo rangeInfo) {
        this.rangeInfo = rangeInfo;
    }

    /**
     * StringConvereter used to 'format' vertical axis labels
     */
    private static class IntegerOnlyStringConverter extends StringConverter<Number> {

        @Override
        public String toString(Number n) {
            //suppress non-integer values
            return n.intValue() == n.doubleValue()
                   ? Integer.toString(n.intValue()) : "";
        }

        @Override
        public Number fromString(String string) {
            //this is unused but here for symmetry
            return Double.valueOf(string).intValue();
        }
    }

    /** Interval Selector for the counts chart, adjusts interval based on
     * rangeInfo to include final period */
    private class CountsIntervalSelector extends IntervalSelector<String> {

        public CountsIntervalSelector(double x, double height, Axis<String> axis, TimeLineController controller) {
            super(x, height, axis, controller);
        }

        @Override
        protected String formatSpan(String date) {
            return date;
        }

        @Override
        protected Interval adjustInterval(Interval i) {
            //extend range to block bounderies (ie day, month, year)
            RangeDivisionInfo iInfo = RangeDivisionInfo.getRangeDivisionInfo(i);
            final long lowerBound = iInfo.getLowerBound();
            final long upperBound = iInfo.getUpperBound();
            final DateTime lowerDate = new DateTime(lowerBound, TimeLineController.getJodaTimeZone());
            final DateTime upperDate = new DateTime(upperBound, TimeLineController.getJodaTimeZone());
            //add extra block to end that gets cut of by conversion from string/category.
            return new Interval(lowerDate, upperDate.plus(rangeInfo.getPeriodSize().getPeriod()));
        }

        @Override
        protected DateTime parseDateTime(String date) {
            return date == null ? new DateTime(rangeInfo.getLowerBound()) : rangeInfo.getTickFormatter().parseDateTime(date);
        }
    }
}
TOP

Related Classes of org.sleuthkit.autopsy.timeline.ui.countsview.EventCountsChart$IntegerOnlyStringConverter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.