net.tourbook.statistics.StatisticTourTime.java Source code

Java tutorial

Introduction

Here is the source code for net.tourbook.statistics.StatisticTourTime.java

Source

/*******************************************************************************
 * Copyright (C) 2005, 2010  Wolfgang Schramm and Contributors
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 *******************************************************************************/
package net.tourbook.statistics;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Formatter;
import java.util.GregorianCalendar;

import net.tourbook.application.TourbookPlugin;
import net.tourbook.chart.BarChartMinMaxKeeper;
import net.tourbook.chart.Chart;
import net.tourbook.chart.ChartDataModel;
import net.tourbook.chart.ChartDataXSerie;
import net.tourbook.chart.ChartDataYSerie;
import net.tourbook.chart.ChartSegments;
import net.tourbook.chart.ChartToolTipInfo;
import net.tourbook.chart.IBarSelectionListener;
import net.tourbook.chart.IChartInfoProvider;
import net.tourbook.chart.SelectionBarChart;
import net.tourbook.colors.GraphColorProvider;
import net.tourbook.data.TourData;
import net.tourbook.data.TourPerson;
import net.tourbook.database.TourDatabase;
import net.tourbook.preferences.ITourbookPreferences;
import net.tourbook.tour.SelectionTourId;
import net.tourbook.tour.TourInfoToolTipProvider;
import net.tourbook.tour.TourManager;
import net.tourbook.ui.ITourProvider;
import net.tourbook.ui.TourTypeFilter;
import net.tourbook.ui.UI;
import net.tourbook.ui.action.ActionEditQuick;
import net.tourbook.util.IToolTipHideListener;

import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.IPostSelectionProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPartSite;

public class StatisticTourTime extends YearStatistic implements IBarSelectionProvider, ITourProvider {

    private TourPerson _activePerson;
    private TourTypeFilter _activeTourTypeFiler;
    private int _currentYear;
    private int _numberOfYears;

    private final Calendar _calendar = GregorianCalendar.getInstance();
    private final DateFormat _dateFormatter = DateFormat.getDateInstance(DateFormat.FULL);

    private Chart _chart;

    private StatisticTourToolTip _tourToolTip;
    private TourInfoToolTipProvider _tourInfoToolTipProvider = new TourInfoToolTipProvider();

    private TourTimeData _tourTimeData;

    private final BarChartMinMaxKeeper _minMaxKeeper = new BarChartMinMaxKeeper();
    private boolean _ifIsSynchScaleEnabled;

    private IPostSelectionProvider _postSelectionProvider;

    private Long _selectedTourId = null;
    private int _currentMonth;

    @Override
    public void activateActions(final IWorkbenchPartSite partSite) {

        //      IContextService contextService = (IContextService) partSite.getService(IContextService.class);
        //      fContextBarChart = contextService.activateContext(Chart.CONTEXT_ID_BAR_CHART);
        //      net.tourbook.chart.context.isTourChart
        //      fChart.updateChartActionHandlers();
    }

    @Override
    public boolean canSelectTour() {
        return true;
    }

    /**
     * create segments for the chart
     */
    ChartSegments createChartSegments(final TourTimeData tourDataTime) {

        final int segmentStart[] = new int[_numberOfYears];
        final int segmentEnd[] = new int[_numberOfYears];
        final String[] segmentTitle = new String[_numberOfYears];

        final int[] allYearDays = tourDataTime.yearDays;
        final int oldestYear = _currentYear - _numberOfYears + 1;
        int yearDaysSum = 0;

        // create segments for each year
        for (int yearIndex = 0; yearIndex < allYearDays.length; yearIndex++) {

            final int yearDays = allYearDays[yearIndex];

            segmentStart[yearIndex] = yearDaysSum;
            segmentEnd[yearIndex] = yearDaysSum + yearDays - 1;
            segmentTitle[yearIndex] = Integer.toString(oldestYear + yearIndex);

            yearDaysSum += yearDays;
        }

        final ChartSegments chartSegments = new ChartSegments();
        chartSegments.valueStart = segmentStart;
        chartSegments.valueEnd = segmentEnd;
        chartSegments.segmentTitle = segmentTitle;

        chartSegments.years = tourDataTime.years;
        chartSegments.yearDays = tourDataTime.yearDays;
        chartSegments.allValues = tourDataTime.allDaysInAllYears;

        return chartSegments;
    }

    @Override
    public void createControl(final Composite parent, final IViewSite viewSite,
            final IPostSelectionProvider postSelectionProvider) {

        super.createControl(parent);

        _postSelectionProvider = postSelectionProvider;

        // chart widget page
        _chart = new Chart(parent, SWT.BORDER | SWT.FLAT);
        //      fChart.setShowPartNavigation(true);
        _chart.setShowZoomActions(true);
        _chart.setCanScrollZoomedChart(true);
        _chart.setDrawBarChartAtBottom(false);
        _chart.setToolBarManager(viewSite.getActionBars().getToolBarManager(), false);

        // set tour info icon into the left axis
        _tourToolTip = new StatisticTourToolTip(_chart.getToolTipControl());
        _tourToolTip.addToolTipProvider(_tourInfoToolTipProvider);
        _tourToolTip.addHideListener(new IToolTipHideListener() {
            @Override
            public void afterHideToolTip(final Event event) {
                // hide hovered image
                _chart.getToolTipControl().afterHideToolTip(event);
            }
        });

        _chart.setTourToolTipProvider(_tourInfoToolTipProvider);
        _tourInfoToolTipProvider.setActionsEnabled(true);

        _chart.addBarSelectionListener(new IBarSelectionListener() {
            public void selectionChanged(final int serieIndex, int valueIndex) {

                final long[] tourIds = _tourTimeData.fTourIds;

                if (tourIds != null && tourIds.length > 0) {

                    if (valueIndex >= tourIds.length) {
                        valueIndex = tourIds.length - 1;
                    }

                    _selectedTourId = tourIds[valueIndex];
                    _tourInfoToolTipProvider.setTourId(_selectedTourId);

                    DataProviderTourTime.getInstance().setSelectedTourId(_selectedTourId);
                    _postSelectionProvider.setSelection(new SelectionTourId(_selectedTourId));
                }
            }
        });

        /*
         * open tour with double click on the tour bar
         */
        _chart.addDoubleClickListener(new IBarSelectionListener() {
            public void selectionChanged(final int serieIndex, final int valueIndex) {
                final long[] tourIds = _tourTimeData.fTourIds;
                if (tourIds.length > 0) {

                    _selectedTourId = tourIds[valueIndex];
                    _tourInfoToolTipProvider.setTourId(_selectedTourId);

                    DataProviderTourTime.getInstance().setSelectedTourId(_selectedTourId);

                    ActionEditQuick.doAction(StatisticTourTime.this);
                }
            }
        });

        /*
         * open tour with Enter key
         */
        _chart.addTraverseListener(new TraverseListener() {
            public void keyTraversed(final TraverseEvent event) {

                if (event.detail == SWT.TRAVERSE_RETURN) {
                    final ISelection selection = _chart.getSelection();
                    if (selection instanceof SelectionBarChart) {
                        final SelectionBarChart barChartSelection = (SelectionBarChart) selection;

                        if (barChartSelection.serieIndex != -1) {

                            _selectedTourId = _tourTimeData.fTourIds[barChartSelection.valueIndex];
                            _tourInfoToolTipProvider.setTourId(_selectedTourId);

                            ActionEditQuick.doAction(StatisticTourTime.this);
                        }
                    }
                }
            }
        });

    }

    private ChartToolTipInfo createToolTipInfo(int valueIndex) {

        final int[] tourDOYValues = _tourTimeData.fTourDOYValues;

        if (valueIndex >= tourDOYValues.length) {
            valueIndex -= tourDOYValues.length;
        }

        if (tourDOYValues == null || valueIndex >= tourDOYValues.length) {
            return null;
        }

        /*
         * set calendar day/month/year
         */
        final int oldestYear = _currentYear - _numberOfYears + 1;
        final int tourDOY = tourDOYValues[valueIndex];
        _calendar.set(oldestYear, 0, 1);
        _calendar.set(Calendar.DAY_OF_YEAR, tourDOY + 1);
        final String beginDate = _dateFormatter.format(_calendar.getTime());

        _currentMonth = _calendar.get(Calendar.MONTH) + 1;
        final long tooltipTourId = _tourTimeData.fTourIds[valueIndex];

        final String tourTypeName = TourDatabase.getTourTypeName(_tourTimeData.fTypeIds[valueIndex]);
        final String tourTags = TourDatabase.getTagNames(_tourTimeData.fTagIds.get(tooltipTourId));
        final String tourDescription = _tourTimeData.tourDescription.get(valueIndex).replace(UI.SYSTEM_NEW_LINE,
                UI.NEW_LINE);

        final int[] startValue = _tourTimeData.fTourTimeStartValues;
        final int[] endValue = _tourTimeData.fTourTimeEndValues;

        final Integer recordingTime = _tourTimeData.fTourRecordingTimeValues.get(valueIndex);
        final Integer drivingTime = _tourTimeData.fTourDrivingTimeValues.get(valueIndex);
        final int breakTime = recordingTime - drivingTime;

        final float distance = _tourTimeData.fTourDistanceValues[valueIndex];
        final float speed = drivingTime == 0 ? 0 : distance / (drivingTime / 3.6f);
        final int pace = (int) (distance == 0 ? 0 : (drivingTime * 1000 / distance));

        final StringBuilder toolTipFormat = new StringBuilder();
        toolTipFormat.append(Messages.TourTime_Info_DateDay); //         %s - CW %d
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(Messages.tourtime_info_distance_tour);
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(Messages.tourtime_info_altitude);
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(Messages.tourtime_info_time);
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(Messages.tourtime_info_recording_time_tour);
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(Messages.tourtime_info_driving_time_tour);
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(Messages.tourtime_info_break_time_tour);
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(Messages.tourtime_info_avg_speed);
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(Messages.tourtime_info_avg_pace);
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(Messages.tourtime_info_tour_type);
        toolTipFormat.append(NEW_LINE);
        toolTipFormat.append(Messages.tourtime_info_tags);

        if (tourDescription.length() > 0) {
            toolTipFormat.append(NEW_LINE);
            toolTipFormat.append(NEW_LINE);
            toolTipFormat.append(Messages.tourtime_info_description);
            toolTipFormat.append(NEW_LINE);
            toolTipFormat.append(Messages.tourtime_info_description_text);
        }

        final String toolTipLabel = new Formatter().format(toolTipFormat.toString(),
                //
                beginDate, _tourTimeData.weekValues[valueIndex],
                //
                distance / 1000, UI.UNIT_LABEL_DISTANCE,
                //
                _tourTimeData.fTourAltitudeValues[valueIndex], UI.UNIT_LABEL_ALTITUDE,
                //
                // start time
                startValue[valueIndex] / 3600, (startValue[valueIndex] % 3600) / 60,
                //
                // end time
                endValue[valueIndex] / 3600 % 24, (endValue[valueIndex] % 3600) / 60,
                //
                recordingTime / 3600, (recordingTime % 3600) / 60, (recordingTime % 3600) % 60,
                //
                drivingTime / 3600, (drivingTime % 3600) / 60, (drivingTime % 3600) % 60,
                //
                breakTime / 3600, (breakTime % 3600) / 60, (breakTime % 3600) % 60,
                //
                speed, UI.UNIT_LABEL_SPEED,
                //
                pace / 60, pace % 60, UI.UNIT_LABEL_PACE,
                //
                tourTypeName, tourTags,
                //
                tourDescription
        //
        ).toString();

        /*
         * create tool tip info
         */
        String tourTitle = _tourTimeData.fTourTitle.get(valueIndex);
        if (tourTitle == null || tourTitle.trim().length() == 0) {
            tourTitle = tourTypeName;
        }

        final ChartToolTipInfo toolTipInfo = new ChartToolTipInfo();
        toolTipInfo.setTitle(tourTitle);
        toolTipInfo.setLabel(toolTipLabel);
        //            toolTipInfo.setLabel(toolTipFormat.toString());

        return toolTipInfo;
    }

    @Override
    public void deactivateActions(final IWorkbenchPartSite partSite) {

        //      IContextService contextService = (IContextService) partSite.getService(IContextService.class);
        //      contextService.deactivateContext(fContextBarChart);
    }

    public Integer getSelectedMonth() {
        return _currentMonth;
    }

    @Override
    public Long getSelectedTour() {
        return _selectedTourId;
    }

    public Long getSelectedTourId() {
        return _selectedTourId;
    }

    @Override
    public ArrayList<TourData> getSelectedTours() {

        if (_selectedTourId == null) {
            return null;
        }

        final ArrayList<TourData> selectedTours = new ArrayList<TourData>();

        selectedTours.add(TourManager.getInstance().getTourData(_selectedTourId));

        return selectedTours;
    }

    public void prefColorChanged() {
        refreshStatistic(_activePerson, _activeTourTypeFiler, _currentYear, 1, false);
    }

    public void refreshStatistic(final TourPerson person, final TourTypeFilter tourTypeFilter, final int year,
            final int numberOfYears, final boolean refreshData) {

        _activePerson = person;
        _activeTourTypeFiler = tourTypeFilter;
        _currentYear = year;
        _numberOfYears = numberOfYears;

        /*
         * get currently selected tour id
         */
        long selectedTourId = -1;
        final ISelection selection = _chart.getSelection();
        if (selection instanceof SelectionBarChart) {
            final SelectionBarChart barChartSelection = (SelectionBarChart) selection;

            if (barChartSelection.serieIndex != -1) {

                int selectedValueIndex = barChartSelection.valueIndex;
                final long[] tourIds = _tourTimeData.fTourIds;

                if (tourIds.length > 0) {
                    if (selectedValueIndex >= tourIds.length) {
                        selectedValueIndex = tourIds.length - 1;
                    }

                    selectedTourId = tourIds[selectedValueIndex];
                }
            }
        }

        _tourTimeData = DataProviderTourTime.getInstance().getTourTimeData(person, tourTypeFilter, year,
                numberOfYears, isDataDirtyWithReset() || refreshData);

        // reset min/max values
        if (_ifIsSynchScaleEnabled == false && refreshData) {
            _minMaxKeeper.resetMinMax();
        }

        updateChart(selectedTourId);
    }

    @Override
    public void resetSelection() {
        _chart.setSelectedBars(null);
    }

    @Override
    public void restoreState(final IDialogSettings viewState) {

        final String mementoTourId = viewState.get(MEMENTO_SELECTED_TOUR_ID);
        if (mementoTourId != null) {
            try {
                final long tourId = Long.parseLong(mementoTourId);
                selectTour(tourId);
            } catch (final Exception e) {
                // ignore
            }
        }
    }

    @Override
    public void saveState(final IDialogSettings viewState) {

        if (_chart == null || _chart.isDisposed()) {
            return;
        }

        final ISelection selection = _chart.getSelection();
        if (_tourTimeData != null && _tourTimeData.fTourIds != null && _tourTimeData.fTourIds.length > 0
                && selection instanceof SelectionBarChart) {

            final Long selectedTourId = _tourTimeData.fTourIds[((SelectionBarChart) selection).valueIndex];

            viewState.put(MEMENTO_SELECTED_TOUR_ID, Long.toString(selectedTourId));
        }
    }

    @Override
    public boolean selectMonth(final Long date) {

        _calendar.setTimeInMillis(date);
        final int tourMonth = _calendar.get(Calendar.MONTH);
        final int[] tourMonths = _tourTimeData.fTourMonthValues;

        final boolean selectedItems[] = new boolean[tourMonths.length];
        boolean isSelected = false;

        // find the tours which have the same day as the selected day
        for (int tourIndex = 0; tourIndex < tourMonths.length; tourIndex++) {
            final boolean isMonthSelected = tourMonths[tourIndex] == tourMonth ? true : false;
            if (isMonthSelected) {
                isSelected = true;
            }
            selectedItems[tourIndex] = isMonthSelected;
        }

        if (isSelected) {
            _chart.setSelectedBars(selectedItems);
        }

        return isSelected;
    }

    @Override
    public boolean selectTour(final Long tourId) {

        final long[] tourIds = _tourTimeData.fTourIds;

        if (tourIds.length == 0) {
            _selectedTourId = null;
            _tourInfoToolTipProvider.setTourId(-1);

            return false;
        }

        final boolean selectedTours[] = new boolean[tourIds.length];

        boolean isSelected = false;

        // find the tour which has the same tourId as the selected tour
        for (int tourIndex = 0; tourIndex < tourIds.length; tourIndex++) {
            if ((tourIds[tourIndex] == tourId)) {
                selectedTours[tourIndex] = true;
                isSelected = true;

                _selectedTourId = tourId;
                _tourInfoToolTipProvider.setTourId(_selectedTourId);

                break;
            }
        }

        if (isSelected == false) {
            // select first tour
            selectedTours[0] = true;
            _selectedTourId = tourIds[0];
            _tourInfoToolTipProvider.setTourId(_selectedTourId);
        }

        _chart.setSelectedBars(selectedTours);

        return isSelected;
    }

    private void setChartProviders(final Chart chartWidget, final ChartDataModel chartModel) {

        final IChartInfoProvider chartInfoProvider = new IChartInfoProvider() {
            public ChartToolTipInfo getToolTipInfo(final int serieIndex, final int valueIndex) {
                return createToolTipInfo(valueIndex);
            }
        };

        chartModel.setCustomData(ChartDataModel.BAR_TOOLTIP_INFO_PROVIDER, chartInfoProvider);

        // set the menu context provider
        chartModel.setCustomData(ChartDataModel.BAR_CONTEXT_PROVIDER, new TourChartContextProvider(_chart, this));
    }

    @Override
    public void setSynchScale(final boolean isSynchScaleEnabled) {
        _ifIsSynchScaleEnabled = isSynchScaleEnabled;
    }

    private void updateChart(final long selectedTourId) {

        final ChartDataModel chartModel = new ChartDataModel(ChartDataModel.CHART_TYPE_BAR);

        // set the x-axis
        final ChartDataXSerie xData = new ChartDataXSerie(_tourTimeData.fTourDOYValues);
        xData.setAxisUnit(ChartDataXSerie.AXIS_UNIT_DAY);
        xData.setVisibleMaxValue(_currentYear);
        xData.setChartSegments(createChartSegments(_tourTimeData));
        chartModel.setXData(xData);

        // set the bar low/high data
        final ChartDataYSerie yData = new ChartDataYSerie(ChartDataModel.CHART_TYPE_BAR,
                new int[][] { _tourTimeData.fTourTimeStartValues },
                new int[][] { _tourTimeData.fTourTimeEndValues });
        yData.setYTitle(Messages.LABEL_GRAPH_DAYTIME);
        yData.setUnitLabel(Messages.LABEL_GRAPH_TIME_UNIT);
        yData.setAxisUnit(ChartDataXSerie.AXIS_UNIT_HOUR_MINUTE_24H);
        yData.setYAxisDirection(false);

        yData.setColorIndex(new int[][] { _tourTimeData.fTypeColorIndex });
        StatisticServices.setTourTypeColors(yData, GraphColorProvider.PREF_GRAPH_TIME, _activeTourTypeFiler);
        StatisticServices.setDefaultColors(yData, GraphColorProvider.PREF_GRAPH_TIME);

        chartModel.addYData(yData);

        /*
         * set graph minimum width, this is the number of days in the year
         */
        _calendar.set(_currentYear, 11, 31);
        final int yearDays = _calendar.get(Calendar.DAY_OF_YEAR);
        chartModel.setChartMinWidth(yearDays);

        setChartProviders(_chart, chartModel);

        if (_ifIsSynchScaleEnabled) {
            _minMaxKeeper.setMinMaxValues(chartModel);
        }

        // set grid size
        final IPreferenceStore prefStore = TourbookPlugin.getDefault().getPreferenceStore();
        _chart.setGridDistance(prefStore.getInt(ITourbookPreferences.GRAPH_GRID_HORIZONTAL_DISTANCE),
                prefStore.getInt(ITourbookPreferences.GRAPH_GRID_VERTICAL_DISTANCE));

        // show the data in the chart
        _chart.updateChart(chartModel, false, true);

        // try to select the previous selected tour
        selectTour(selectedTourId);
    }

    @Override
    public void updateToolBar(final boolean refreshToolbar) {
        _chart.fillToolbar(refreshToolbar);
    }

}