com.spaceapplications.vaadin.addon.eventtimeline.gwt.client.VEventTimelineDisplay.java Source code

Java tutorial

Introduction

Here is the source code for com.spaceapplications.vaadin.addon.eventtimeline.gwt.client.VEventTimelineDisplay.java

Source

/*
@VaadinAddonLicenseForJavaFiles@
 */
package com.spaceapplications.vaadin.addon.eventtimeline.gwt.client;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.dom.client.MouseWheelEvent;
import com.google.gwt.event.dom.client.MouseWheelHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.Event.NativePreviewHandler;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.spaceapplications.vaadin.addon.eventtimeline.gwt.canvas.client.Canvas;
import com.spaceapplications.vaadin.addon.eventtimeline.gwt.style.client.ComputedStyle;
import com.vaadin.terminal.gwt.client.DateTimeService;

/**
 * VEventTimelineDisplay, based on original version from vaadin-timeline.
 * 
 * @author Thomas Neidhart / Space Applications Services NV/SA
 * @author John Ahlroos / IT Mill Oy Ltd
 */
public class VEventTimelineDisplay extends Widget implements VDataListener, MouseDownHandler, MouseUpHandler,
        MouseMoveHandler, MouseWheelHandler, NativePreviewHandler {

    private static final String CLASSNAME_BOTTOMBAR = VEventTimelineWidget.DISPLAY_CLASSNAME + "-bottombar";
    private static final String CLASSNAME_CANVAS = VEventTimelineWidget.DISPLAY_CLASSNAME + "-canvas";
    private static final String CLASSNAME_CANVASDRAG = CLASSNAME_CANVAS + "-drag";
    private static final String CLASSNAME_LOADINGCURTAIN = VEventTimelineWidget.DISPLAY_CLASSNAME + "-curtain";
    public static final String CLASSNAME_EVENT = VEventTimelineWidget.CLASSNAME + "-event";
    public static final String CLASSNAME_EVENT_SELECTED = CLASSNAME_EVENT + "-selected";
    public static final String CLASSNAME_EVENT_CAPTION = CLASSNAME_EVENT + "-caption";
    public static final String CLASSNAME_EVENT_CONTENT = CLASSNAME_EVENT + "-content";
    private static final String CLASSNAME_SCALEVALUE = VEventTimelineWidget.DISPLAY_CLASSNAME + "-vscale";
    private static final String CLASSNAME_SCALEVALUEDRAG = CLASSNAME_SCALEVALUE + "-drag";
    private static final String CLASSNAME_SCALEDATE = VEventTimelineWidget.DISPLAY_CLASSNAME + "-hscale";
    private static final String CLASSNAME_SCALEDATE_LEFT = CLASSNAME_SCALEDATE + "-left";

    public static final Long SECOND = 1000L;
    public static final Long MINUTE = 60000L;
    public static final Long HOUR = 3600000L;
    public static final Long DAY = 86400000L;
    public static final Long WEEK = 604800000L;
    public static final Long MONTH = 2629743830L;
    public static final Long YEAR = 31556926000L;

    private final VEventTimelineWidget widget;

    private final Element browserRoot;
    private final AbsolutePanel displayComponentPanel;

    private final Canvas canvas;

    private final HTML bottomBar;

    private final Map<Integer, List<VEvent>> currentEvents = new TreeMap<Integer, List<VEvent>>();
    private final List<VEventLabel> events = new ArrayList<VEventLabel>();

    private Map<Integer, Integer> maxSlots = new HashMap<Integer, Integer>();

    // The selected date range
    private Date currentStartDate = null;
    private Date currentEndDate = null;

    // Mouse actions
    private boolean mouseIsDown = false;
    private boolean mouseIsActive = false;
    private int mouseDownX = 0;
    private int lastMouseX = 0;

    // States
    private boolean enabled = true;
    private boolean forcePlot = false;

    // Dragging
    private Date currentStartDragDate = null;
    private Date currentEndDragDate = null;

    // Curtains
    private final HTML loadingCurtain;
    private final HTML disabledCurtain;

    // Scale components lists
    private final List<Label> horizontalScaleComponents = new ArrayList<Label>();
    private final List<Label> verticalScaleComponents = new ArrayList<Label>();

    // Error and loading messages
    private final Label noDataLabel = new Label("No data source.");

    // Graph formatting
    private String gridColor = "rgb(200,200,200)";

    private HandlerRegistration mouseMoveReg, mouseUpReg, mouseDownReg, mouseScrollReg, preview;

    private DateTimeFormat yearFormatShort = DateTimeFormat.getFormat("''yy");
    private DateTimeFormat yearFormatLong = DateTimeFormat.getFormat("yyyy");

    private DateTimeFormat monthFormatShort = DateTimeFormat.getFormat("MMM yyyy");
    private DateTimeFormat monthFormatLong = DateTimeFormat.getFormat("MMMM yyyy");

    private DateTimeFormat dayFormatShort = DateTimeFormat.getFormat("MMM d, yyyy");
    private DateTimeFormat dayFormatLong = DateTimeFormat.getFormat("MMMM d, yyyy");

    private DateTimeFormat timeFormatShort = DateTimeFormat.getFormat("HH:mm");
    private DateTimeFormat timeFormatLong = DateTimeFormat.getFormat("HH:mm:ss");

    public VEventTimelineDisplay(VEventTimelineWidget w) {
        widget = w;

        browserRoot = DOM.createDiv();
        setElement(browserRoot);
        setStyleName(VEventTimelineWidget.DISPLAY_CLASSNAME);

        // Add the components
        displayComponentPanel = new AbsolutePanel();
        browserRoot.appendChild(displayComponentPanel.getElement());
        DOM.setStyleAttribute(displayComponentPanel.getElement(), "position", "relative");

        // Add the canvas
        canvas = new Canvas(100, 100);

        canvas.setStyleName(CLASSNAME_CANVAS);
        displayComponentPanel.add(canvas, 0, 0);

        // Create the loading indicator
        loadingCurtain = new HTML("");
        loadingCurtain.setStyleName("v-app-loading");
        loadingCurtain.addStyleName(CLASSNAME_LOADINGCURTAIN);
        loadingCurtain.setWidth("100%");
        loadingCurtain.setHeight("100%");
        displayComponentPanel.add(loadingCurtain);

        // Create the bottom bar
        bottomBar = new HTML();
        bottomBar.setWidth("100%");
        bottomBar.setStyleName(CLASSNAME_BOTTOMBAR);
        displayComponentPanel.add(bottomBar);

        // Add no data source label
        noDataLabel.setVisible(false);
        displayComponentPanel.add(noDataLabel, 10, 10);

        // Create the disabled curtain
        disabledCurtain = new HTML("");
        disabledCurtain.setVisible(false);
        disabledCurtain.setStyleName(CLASSNAME_LOADINGCURTAIN);
        disabledCurtain.setWidth("100%");
        disabledCurtain.setHeight("100%");
        displayComponentPanel.add(disabledCurtain);
    }

    @Override
    protected void onLoad() {
        super.onLoad();
        mouseDownReg = addDomHandler(this, MouseDownEvent.getType());
        mouseUpReg = addDomHandler(this, MouseUpEvent.getType());
        mouseMoveReg = addDomHandler(this, MouseMoveEvent.getType());
        mouseScrollReg = addDomHandler(this, MouseWheelEvent.getType());
        preview = Event.addNativePreviewHandler(this);
    }

    @Override
    public void setHeight(String height) {
        super.setHeight(height);
        int canvasHeight = getOffsetHeight() - bottomBar.getOffsetHeight();
        canvas.setHeight(canvasHeight + "px");
        displayComponentPanel.setHeight(getOffsetHeight() + "px");
        displayComponentPanel.setWidgetPosition(bottomBar, 0, getOffsetHeight() - bottomBar.getOffsetHeight());
    }

    @Override
    public void setWidth(String width) {
        super.setWidth(width);
        canvas.setWidth(getOffsetWidth() + "px");
        displayComponentPanel.setWidth(getOffsetWidth() + "px");
    }

    @Override
    protected void onUnload() {
        super.onUnload();
        if (mouseDownReg != null) {
            mouseDownReg.removeHandler();
            mouseDownReg = null;
        }
        if (mouseUpReg != null) {
            mouseUpReg.removeHandler();
            mouseUpReg = null;
        }
        if (mouseMoveReg != null) {
            mouseMoveReg.removeHandler();
            mouseMoveReg = null;
        }
        if (mouseScrollReg != null) {
            mouseScrollReg.removeHandler();
            mouseScrollReg = null;
        }
        if (preview != null) {
            preview.removeHandler();
            preview = null;
        }
    }

    @SuppressWarnings("deprecation")
    private void plotHorizontalScale(long startTime, long endTime, long unitTime, float xUnit, boolean leftAlign) {

        if (unitTime <= 0 || xUnit <= 0) {
            return;
        }

        float width = unitTime * xUnit;
        boolean shortDateFormat = width < 100;
        int year = widget.getStartDate().getYear();
        long time = (new Date(year, 0, 1)).getTime();

        DateTimeFormat formatter;
        if (unitTime < DAY) {
            formatter = shortDateFormat ? timeFormatShort : timeFormatLong;
        } else if (unitTime < MONTH) {
            formatter = shortDateFormat ? dayFormatShort : dayFormatLong;
        } else if (unitTime < YEAR) {
            formatter = shortDateFormat ? monthFormatShort : monthFormatLong;
        } else {
            formatter = shortDateFormat ? yearFormatShort : yearFormatLong;
        }

        if (gridColor != null) {
            canvas.setStrokeStyle(gridColor);
            canvas.setLineWidth(0.8);
            canvas.beginPath();
        }

        long stepsUntilInRange = (startTime - time) / unitTime;
        time += stepsUntilInRange * unitTime;

        while (time <= endTime) {
            if (time >= startTime - unitTime && time <= endTime + unitTime) {
                Label lbl = new Label();
                lbl.setStyleName(leftAlign ? CLASSNAME_SCALEDATE_LEFT : CLASSNAME_SCALEDATE);
                lbl.setWidth(width + "px");
                Date date = new Date(time);

                lbl.setText(widget.getDateTimeService().formatDate(date, formatter.getPattern()));

                long timeFromStart = time - startTime;
                float x = timeFromStart * xUnit;

                if (gridColor != null) {
                    canvas.moveTo(x, 0);
                    canvas.lineTo(x, canvas.getHeight());
                }

                displayComponentPanel.add(lbl, (int) x, displayComponentPanel.getOffsetHeight() - 15);
                horizontalScaleComponents.add(lbl);
            }

            if (unitTime == MONTH) {
                /*
                 * Month resolution is not so easy since it changes depending on
                 * the month. We use the Date to resolve the new time
                 */
                time += DateTimeService.getNumberOfDaysInMonth(new Date(time)) * DAY;
            } else if (unitTime == YEAR) {
                /*
                 * Take leap years into account
                 */
                if (DateTimeService.isLeapYear(new Date(time))) {
                    time += unitTime + DAY;
                } else {
                    time += unitTime;
                }

            } else {
                time += unitTime;
            }
        }

        if (gridColor != null) {
            canvas.closePath();
            canvas.stroke();
        }
    }

    /**
     * Plots the horizontal scale
     */
    private void plotHorizontalScale(float xUnit, long startTime, long endTime) {

        long timeDiff = endTime - startTime;

        for (Label lbl : horizontalScaleComponents) {
            displayComponentPanel.remove(lbl);
        }
        horizontalScaleComponents.clear();

        canvas.setGlobalCompositeOperation(Canvas.DESTINATION_OVER);

        // Selection is less than a minute
        if (timeDiff <= VEventTimelineDisplay.MINUTE) {
            plotHorizontalScale(startTime, endTime, 10 * VEventTimelineDisplay.SECOND, xUnit, true);
        }

        // Selections is less the 5 minutes
        else if (timeDiff <= 5 * MINUTE) {
            plotHorizontalScale(startTime, endTime, VEventTimelineDisplay.MINUTE, xUnit, true);
        }

        // Selection is less than 30 minutes
        else if (timeDiff <= 30 * MINUTE) {
            plotHorizontalScale(startTime, endTime, 5 * MINUTE, xUnit, true);
        }

        // Selection is less than 1 hour
        else if (timeDiff <= HOUR) {
            plotHorizontalScale(startTime, endTime, 10 * MINUTE, xUnit, true);
        }

        // Selection is less then 6 hours
        else if (timeDiff <= 6 * HOUR) {
            plotHorizontalScale(startTime, endTime, 30 * MINUTE, xUnit, true);
        }

        // Selection is less then a half day
        else if (timeDiff <= 12 * HOUR) {
            plotHorizontalScale(startTime, endTime, HOUR, xUnit, false);
        }

        // Selection is less than a day
        else if (timeDiff <= DAY) {
            plotHorizontalScale(startTime, endTime, 2 * HOUR, xUnit, true);
        }

        // Selection is less than 3 days
        else if (timeDiff <= 3 * DAY) {
            plotHorizontalScale(startTime, endTime, 6 * HOUR, xUnit, true);
        }

        // Selection is less than a week. Show dayly view
        else if (timeDiff <= WEEK) {
            plotHorizontalScale(startTime, endTime, DAY, xUnit, false);
        }

        // Selection is less than two weeks
        else if (timeDiff <= 2 * WEEK) {
            plotHorizontalScale(startTime, endTime, 3 * DAY, xUnit, true);
        }

        // Selection is less than a month. Show weekly view
        else if (timeDiff <= 2 * MONTH) {
            plotHorizontalScale(startTime, endTime, WEEK, xUnit, true);
        }

        // Selection is less than two years
        else if (timeDiff <= 2 * YEAR) {
            plotHorizontalScale(startTime, endTime, MONTH, xUnit, false);
        }

        // Selection is more than two years
        else {
            plotHorizontalScale(startTime, endTime, YEAR, xUnit, false);
        }

        canvas.setGlobalCompositeOperation(Canvas.SOURCE_OVER);
    }

    public void redraw() {
        plotData(true);
    }

    private void plotData(boolean force) {
        // set the text fields with the correct date
        widget.setFromDateTextField(currentStartDate);
        widget.setToDateTextField(currentEndDate);

        // calculate some needed values
        Float canvasWidth = new Float(canvas.getWidth());
        // Float canvasHeight = new Float(canvas.getWidth());
        Long startTime = currentStartDate.getTime();
        Long endTime = currentEndDate.getTime();

        Long timeDiff = endTime - startTime;

        // ensure we have something to plot
        if (timeDiff <= 0) {
            return;
        }

        Float xUnit = canvasWidth / timeDiff.floatValue();

        // clear old drawings
        canvas.clear();

        // draw current time if it is in the current display
        Date d = new Date();
        float timeX = (d.getTime() - startTime) * xUnit;

        if (timeX > 0 && timeX < canvas.getWidth()) {
            canvas.beginPath();
            canvas.moveTo(timeX, canvas.getWidth());
            canvas.lineTo(timeX, 0);
            canvas.closePath();

            canvas.setStrokeStyle("#a00000");
            canvas.setLineWidth(1.0d);
            canvas.stroke();
        }

        if (force) {
            // remove old events
            for (VEventLabel w : events) {
                displayComponentPanel.remove(w);
            }

            events.clear();
        }

        // if there are no event widgets yet, force creation
        if (events.isEmpty()) {
            force = true;
        }

        float y = 5;

        if (!force) {
            // in case a redraw is not forced, just move the existing labels
            // this is an optimization in case the user is dragging the display
            for (VEventLabel w : events) {
                VEvent event = w.getEvent();
                Long eventStartTime = event.getStartTime();

                Long timeFromStart = eventStartTime - startTime;

                float x = timeFromStart * xUnit;

                DOM.setStyleAttribute(w.getElement(), "left", x + "px");
            }
        } else {

            // paint events
            for (Integer band : currentEvents.keySet()) {
                List<VEvent> eventList = currentEvents.get(band);

                int bandHeight = widget.getBandHeight(band);
                int slots = maxSlots.get(band);

                if (bandHeight > 0) {
                    for (int idx = 0; idx < eventList.size(); idx++) {
                        VEvent event = eventList.get(idx);
                        Long eventStartTime = event.getStartTime();
                        Long eventEndTime = event.getEndTime();

                        Long timeFromStart = eventStartTime - startTime;

                        float x = timeFromStart * xUnit;

                        Long duration = eventEndTime - eventStartTime;
                        float w = duration * xUnit;

                        int cw = canvas.getWidth();
                        if ((x >= 0 && x + w < cw) || (x < 0 && x + w > 0 && x + w < cw)
                                || (x >= 0 && x < cw && x + w > cw) || (x <= 0 && x + w > cw)) {
                            if (force) {
                                int height = Math.max(0, bandHeight - 6);
                                plotEvent(event, x, y, w, slots, height);
                            }
                        }
                    }
                    y += bandHeight;
                }
            }
        }

        // paint horizontal lines to separate bands
        canvas.setStrokeStyle("#000");
        canvas.setLineWidth(0.5);
        canvas.beginPath();

        y = 1;
        for (Integer band : currentEvents.keySet()) {
            y += widget.getBandHeight(band);

            canvas.moveTo(0, y);
            canvas.lineTo(canvas.getWidth(), y);
        }

        canvas.closePath();
        canvas.stroke();

        // plot the horizontal scale
        plotHorizontalScale(xUnit, startTime, endTime);
    }

    private int checkOverlaps(List<VEvent> events, Long startTime, Long endTime) {
        ArrayList<VEvent> slots = new ArrayList<VEvent>();
        // first sweep get maximum slots
        for (VEvent event : events) {
            if (slots.isEmpty()) {
                slots.add(event);
                event.setSlotIndex(0);
                event.setHeight(1);
            } else {
                boolean foundSlot = false;
                for (int slotIdx = 0; slotIdx < slots.size(); slotIdx++) {
                    VEvent slotEvent = slots.get(slotIdx);

                    boolean overlaps = overlaps(slotEvent, event);

                    if (foundSlot) {
                        if (overlaps) {
                            event.setHeight(slotIdx - event.getSlotIndex());
                            break;
                        }
                    } else {
                        if (!overlaps) {
                            slots.set(slotIdx, event);
                            event.setSlotIndex(slotIdx);
                            event.setHeight(1);
                            foundSlot = true;
                        }
                    }
                }
                if (!foundSlot) {
                    slots.add(event);
                    event.setSlotIndex(slots.size() - 1);
                    event.setHeight(1);
                }
            }
        }

        return slots.size();
    }

    public boolean overlaps(VEvent evt1, VEvent evt2) {
        if ((evt1.getStartTime() >= evt2.getStartTime() && evt1.getStartTime() <= evt2.getEndTime())
                || (evt2.getStartTime() >= evt1.getStartTime() && evt2.getStartTime() <= evt1.getEndTime())) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Plots an event onto the display
     * 
     * @param caption
     *            The caption that shows on the screen
     * @param date
     *            The date the event happened
     * @param index
     *            The server index of the event
     * @param x
     *            The X-coordinate
     * @param y
     *            The Y-coordinate
     * @param w
     *            The width
     * @param maxHeight
     *            The maximum height of the event
     */
    private void plotEvent(VEvent event, float x, float y, float w, int slots, int maxHeight) {
        int space = 3;
        float slotHeight = (float) maxHeight / (float) slots;
        int slotPosition = (int) (slotHeight * (float) event.getSlotIndex());
        int elementHeight = (int) (slotHeight * (float) event.getHeight()) - space;

        final VEventLabel eventElement = new VEventLabel(event, w, Math.max(0, elementHeight));
        displayComponentPanel.add(eventElement, (int) x, (int) y + slotPosition);

        String bg = ComputedStyle.getBackgroundColor(eventElement.getElement());
        event.setBackgroundColor(bg);

        events.add(eventElement);
    }

    public void dataReceived(Integer band, List<VEvent> events) {
        // Check if we have events
        if (events != null) {
            currentEvents.put(band, events);

            Long startTime = currentStartDate.getTime();
            Long endTime = currentEndDate.getTime();
            int slots = checkOverlaps(events, startTime, endTime);
            maxSlots.put(band, slots);
        }
    }

    public void dataReceivedAll() {
        // we have received data for all bands, redraw now the display

        plotData(forcePlot);

        // forced plotting is always turned off after a forced plot.
        // To force it again you have to set it on again be
        // before the next plot.
        forcePlot = false;

        // hide curtain
        setLoadingIndicatorVisible(false);
    }

    @Override
    public void dataRemoved(Integer[] bands) {
        for (int i = 0; i < bands.length; i++) {
            Integer band = bands[i];
            // Check if we have events
            if (events != null) {
                currentEvents.remove(band);
                maxSlots.remove(band.intValue());

                // // we have received data for all bands, redraw now the
                // display
                // plotData(forcePlot);
                //
                // // forced plotting is always turned off after a forced plot.
                // // To force it again you have to set it on again be
                // // before the next plot.
                // forcePlot = false;
                //
                // // hide curtain
                // setLoadingIndicatorVisible(false);
            }
        }

    }

    /**
     * Should the spinning loading indicator be visible?
     * 
     * @param visible
     *            Is it visible
     */
    private void setLoadingIndicatorVisible(boolean visible) {
        loadingCurtain.setVisible(visible);
    }

    public boolean setRange(Date start, Date end) {
        if (mouseIsActive) {
            // if we are dragging then ignore any setRange requests
            return false;
        }

        return setRange(start, end, false, false, true);
    }

    /**
     * Set the range to display
     * 
     * @param start
     *            The start date
     * @param end
     *            The end date
     * @return
     */
    private boolean setRange(Date start, Date end, Boolean useCurtain, boolean forceServer, boolean forceRedraw) {
        if (!isVisible()) {
            return false;
        }

        if (start == null || end == null) {
            return false;
        }

        currentStartDate = start;
        currentEndDate = end;

        if (forceRedraw) {
            resetDisplayCache();

            // Get the events
            forcePlot = true;
            boolean cached = widget.getEvents(this, start, end, !forceServer);
            setLoadingIndicatorVisible(useCurtain && !cached);
        } else {
            plotData(false);
        }

        return true;
    }

    /**
     * Resets the display cache
     */
    public void resetDisplayCache() {
        currentEvents.clear();
    }

    /**
     * Returns the canvas width
     * 
     * @return The width in pixels
     */
    public int getCanvasWidth() {
        return canvas.getWidth();
    }

    /**
     * Get the current starting date
     * 
     * @return The date
     */
    public Date getSelectionStartDate() {
        return currentStartDate;
    }

    /**
     * Get the current ending date
     * 
     * @return The date
     */
    public Date getSelectionEndDate() {
        return currentEndDate;
    }

    /**
     * Triggered when an VEvent widget is pressed
     * 
     * @param eventElement
     */
    private void eventClick(VEventLabel eventElement) {
        VEvent event = eventElement.getEvent();
        widget.fireEventButtonClickEvent(event.getID());
    }

    /**
     * Does the component have an specific element
     * 
     * @param elem
     *            The element
     * @return True if the component has the element
     */
    public boolean hasElement(com.google.gwt.dom.client.Element elem) {
        for (Label lbl : horizontalScaleComponents) {
            if (lbl.getElement() == elem) {
                return true;
            }
        }

        for (Label lbl : verticalScaleComponents) {
            if (lbl.getElement() == elem) {
                return true;
            }
        }

        for (VEventLabel eventWidget : events) {
            if (eventWidget.getElement() == elem) {
                return true;
            }
        }

        if (elem == displayComponentPanel.getElement() || elem == getElement() || elem == canvas.getElement()
                || elem == loadingCurtain.getElement() || elem == browserRoot || elem == bottomBar.getElement()
                || elem == disabledCurtain.getElement()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Displays the no data found message
     * 
     * @param enabled
     *            Is the message displayed
     */
    public void displayNoDataMessage(boolean enabled) {
        noDataLabel.setVisible(enabled);
        setLoadingIndicatorVisible(false);
    }

    /**
     * Is the display enabled
     * 
     * @param enabled
     *            True if enabled
     */
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
        setLoadingIndicatorVisible(false);
    }

    /**
     * Force plotting the the data even if it is the same time range. Forced
     * plotting is always turned off after a forced plot so you will have to
     * turn on forced plotting again before the next plot.
     * 
     * @param enabled
     *            The plotting is forced
     */
    public void setForcedPlotting(boolean enabled) {
        forcePlot = enabled;
    }

    /**
     * Sets the scale grid color, set to null to not draw the grid
     * 
     * @param color
     *            The color
     */
    public void setGridColor(String color) {
        gridColor = color;
    }

    int dragX = 0;
    private Command drag = new Command() {
        public void execute() {
            Long timeDiff = currentEndDragDate.getTime() - currentStartDragDate.getTime();
            float xdiff = (dragX - mouseDownX) / 2f;
            float canvasWidth = canvas.getWidth();
            float widthUnit = xdiff / canvasWidth;

            Float time = timeDiff * widthUnit;

            Long start = currentStartDate.getTime() - time.longValue();
            Long end = currentEndDate.getTime() - time.longValue();

            Date startDate = new Date(start);
            Date endDate = new Date(end);

            setRange(startDate, endDate, false, false, false);
            widget.setBrowserRange(startDate, endDate);
            mouseDownX = dragX;
        }
    };

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.google.gwt.event.dom.client.MouseMoveHandler#onMouseMove(com.google
     * .gwt.event.dom.client.MouseMoveEvent)
     */
    public void onMouseMove(MouseMoveEvent event) {
        NativeEvent mouseEvent = event.getNativeEvent();
        lastMouseX = event.getClientX();

        // Dragging action occurring..
        if (mouseIsDown && enabled && currentEndDragDate != null && currentStartDragDate != null) {
            dragX = mouseEvent.getClientX();
            drag.execute();

            // Mouse is hovering over the display area
        } else if (enabled) {
            // int x = mouseEvent.getClientX() - getAbsoluteLeft();
            // int y = mouseEvent.getClientY() - getAbsoluteTop();
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.google.gwt.event.dom.client.MouseUpHandler#onMouseUp(com.google.gwt
     * .event.dom.client.MouseUpEvent)
     */
    public void onMouseUp(MouseUpEvent event) {
        mouseIsActive = false;

        DOM.releaseCapture(canvas.getElement());

        if (enabled && currentEndDragDate != null && currentStartDragDate != null) {
            Long timeDiff = currentEndDragDate.getTime() - currentStartDragDate.getTime();
            float xdiff = (lastMouseX - mouseDownX) / 2f;
            float canvasWidth = canvas.getWidth();
            float widthUnit = xdiff / canvasWidth;

            Float time = timeDiff * widthUnit;

            Long start = currentStartDate.getTime() - time.longValue();
            Long end = currentEndDate.getTime() - time.longValue();

            Date startDate = new Date(start);
            Date endDate = new Date(end);

            if (startDate.compareTo(widget.getStartDate()) >= 0 && endDate.compareTo(widget.getEndDate()) <= 0) {

                // only trigger a redraw of the display, if the mouse has been
                // moved (dragged)
                boolean mouseMoved = startDate.compareTo(currentStartDragDate) != 0;
                if (mouseMoved && setRange(startDate, endDate, true, false, true)) {
                    // widget.setBrowserRange(startDate, endDate);
                    mouseDownX = lastMouseX;
                    widget.fireDateRangeChangedEvent();
                }
            }

            for (Label lbl : verticalScaleComponents) {
                lbl.setStyleName(CLASSNAME_SCALEVALUE);
            }
            canvas.setStyleName(CLASSNAME_CANVAS);

            currentStartDragDate = null;
            currentEndDragDate = null;
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.google.gwt.event.dom.client.MouseDownHandler#onMouseDown(com.google
     * .gwt.event.dom.client.MouseDownEvent)
     */
    public void onMouseDown(MouseDownEvent event) {
        NativeEvent mouseEvent = event.getNativeEvent();

        mouseIsActive = true;

        event.preventDefault();
        event.stopPropagation();

        if (enabled) {
            mouseDownX = mouseEvent.getClientX();
            canvas.setStyleName(CLASSNAME_CANVASDRAG);

            for (Label lbl : verticalScaleComponents) {
                lbl.setStyleName(CLASSNAME_SCALEVALUEDRAG);
            }

            DOM.setCapture(canvas.getElement());

            currentStartDragDate = new Date(currentStartDate.getTime());
            currentEndDragDate = new Date(currentEndDate.getTime());
        }

        // Remove the selected style from the widget again
        for (VEventLabel w : events) {
            w.removeStyleName(CLASSNAME_EVENT_SELECTED);
        }

        // Check if element is a event button
        for (VEventLabel w : events) {
            w.removeStyleName(CLASSNAME_EVENT_SELECTED);
            com.google.gwt.dom.client.Element mouseEventElement = Element.as(mouseEvent.getEventTarget());
            if (mouseEventElement == w.getElement() || mouseEventElement.getParentElement() == w.getElement()) {
                w.addStyleName(CLASSNAME_EVENT_SELECTED);
                eventClick(w);
                break;
            }
        }
    }

    public void onMouseWheel(MouseWheelEvent event) {
        NativeEvent mouseEvent = event.getNativeEvent();
        if (hasElement(Element.as(mouseEvent.getEventTarget()))) {
            event.preventDefault();
            float x = mouseEvent.getClientX();
            boolean up = mouseEvent.getMouseWheelVelocityY() > 0;
            float canvasWidth = canvas.getWidth();
            float ratio = x / canvasWidth;

            // Calculate the minimum timeunit for the whole range
            long diff = widget.getEndDate().getTime() - widget.getStartDate().getTime();
            float minTimeSpan = (diff / canvasWidth) * 60f;
            float minAllowedTimeSpan = (diff / canvasWidth) * 20f;

            Float startRatio = ratio * minTimeSpan;
            Float endRatio = (1f - ratio) * minTimeSpan;

            if (up) {
                Date start = new Date(currentStartDate.getTime() - startRatio.longValue());

                if (start.before(widget.getStartDate())) {
                    /*
                     * Ensure we are in bounds
                     */
                    start = widget.getStartDate();
                }

                Date end = new Date(currentEndDate.getTime() + endRatio.longValue());

                if (end.after(widget.getEndDate())) {
                    /*
                     * Ensure we are in bounds
                     */
                    end = widget.getEndDate();
                }

                if (end.getTime() - start.getTime() > minAllowedTimeSpan) {
                    currentStartDate = start;
                    currentEndDate = end;
                    refresh();
                    widget.setBrowserRange(currentStartDate, currentEndDate);
                }

            } else {
                Date start = new Date(currentStartDate.getTime() + startRatio.longValue());

                if (start.before(widget.getStartDate())) {
                    /*
                     * Ensure we are in bounds
                     */
                    start = widget.getStartDate();
                }

                Date end = new Date(currentEndDate.getTime() - endRatio.longValue());

                if (end.after(widget.getEndDate())) {
                    /*
                     * Ensure we are in bounds
                     */
                    end = widget.getEndDate();
                }

                if (end.getTime() - start.getTime() > minAllowedTimeSpan) {
                    currentStartDate = start;
                    currentEndDate = end;
                    refresh();
                    widget.setBrowserRange(currentStartDate, currentEndDate);
                }
            }
        }
    }

    public void onPreviewNativeEvent(NativePreviewEvent event) {
        // Monitor mouse button state
        if (event.getTypeInt() == Event.ONMOUSEUP
                && event.getNativeEvent().getButton() == NativeEvent.BUTTON_LEFT) {
            mouseIsDown = false;
            if (mouseIsActive) {
                onMouseUp(null);
            }
        } else if (event.getTypeInt() == Event.ONMOUSEDOWN
                && event.getNativeEvent().getButton() == NativeEvent.BUTTON_LEFT) {
            mouseIsDown = true;
        }
    }

    /**
     * Initializes the canvas i.e. it will fetch the points for the whole
     * timeline and render it to the canvas.
     */
    public void refresh() {
        if (!isVisible()) {
            return;
        }
        setRange(getSelectionStartDate(), getSelectionEndDate(), false, false, true);
    }

    public void setYearFormatShort(DateTimeFormat format) {
        this.yearFormatShort = format;
    }

    public void setYearFormatLong(DateTimeFormat format) {
        this.yearFormatLong = format;
    }

    public void setMonthFormatShort(DateTimeFormat format) {
        this.monthFormatShort = format;
    }

    public void setMonthFormatLong(DateTimeFormat format) {
        this.monthFormatLong = format;
    }

    public void setDayFormatShort(DateTimeFormat format) {
        this.dayFormatShort = format;
    }

    public void setDayFormatLong(DateTimeFormat format) {
        this.dayFormatLong = format;
    }

    public void setTimeFormatShort(DateTimeFormat format) {
        this.timeFormatShort = format;
    }

    public void setTimeFormatLong(DateTimeFormat format) {
        this.timeFormatLong = format;
    }

    public boolean isMouseActive() {
        return mouseIsActive;
    }
}