com.extjs.gxt.ui.client.util.ClickRepeater.java Source code

Java tutorial

Introduction

Here is the source code for com.extjs.gxt.ui.client.util.ClickRepeater.java

Source

/*
 * Sencha GXT 2.3.1 - Sencha for GWT
 * Copyright(c) 2007-2013, Sencha, Inc.
 * licensing@sencha.com
 * 
 * http://www.sencha.com/products/gxt/license/
 */
package com.extjs.gxt.ui.client.util;

import java.util.Date;

import com.extjs.gxt.ui.client.core.El;
import com.extjs.gxt.ui.client.event.BaseObservable;
import com.extjs.gxt.ui.client.event.ClickRepeaterEvent;
import com.extjs.gxt.ui.client.event.EventType;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.PreviewEvent;
import com.extjs.gxt.ui.client.widget.ComponentAttachable;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.Timer;

/**
 * A utility class that continues to fire a "click" event when the user holds
 * the mouse key down.
 * 
 * <dl>
 * <dt><b>Events:</b></dt>
 * 
 * <dd><b>OnClick</b> : ClickRepeaterEvent(source, el)<br>
 * <div>Fires when the user holds down the mouse button.</div>
 * <ul>
 * <li>source : this</li>
 * <li>el : the click element</li>
 * </ul>
 * </dd>
 * </dl>
 */
public class ClickRepeater extends BaseObservable implements ComponentAttachable {

    private boolean accelerate;
    private int delay = 250;
    private El el;
    private int interval = 20;
    private Date mousedownTime;
    private BaseEventPreview preview;
    private String pressClass;
    private Timer timer;
    private boolean waitForMouseOut;
    private boolean waitForMouseOver;

    /**
     * Creates a new click repeater.
     * 
     * @param el the element to be clicked
     */
    public ClickRepeater(El el) {
        this.el = el;
        preview = new BaseEventPreview() {
            protected boolean onPreview(PreviewEvent pe) {
                if (pe.getEventTypeInt() == Event.ONMOUSEUP) {
                    ClickRepeater.this.handleMouseUp();
                }
                return true;
            }
        };
        preview.setAutoHide(false);
        el.addEventsSunk(Event.ONMOUSEDOWN | Event.ONMOUSEOUT | Event.ONMOUSEOVER);
    }

    public void doAttach() {
        DOM.setEventListener(el.dom, new EventListener() {
            public void onBrowserEvent(Event event) {
                switch (event.getTypeInt()) {
                case Event.ONMOUSEDOWN:
                    event.stopPropagation();
                    event.preventDefault();
                    handleMouseDown();
                    break;
                case Event.ONMOUSEOUT:
                    handleMouseOut();
                    break;
                case Event.ONMOUSEOVER:
                    handleMouseReturn();
                    break;
                }
            }
        });

        el.disableTextSelection(true);
        preview.add();
    }

    public void doDetach() {
        DOM.setEventListener(el.dom, null);
        el.disableTextSelection(false);
        preview.remove();
    }

    public boolean fireEvent(EventType eventType) {
        return fireEvent(eventType, new ClickRepeaterEvent(this, el));
    }

    /**
     * Returns the amount before events are fired once the user holds the mouse
     * down.
     * 
     * @return the delay in milliseconds
     */
    public int getDelay() {
        return delay;
    }

    /**
     * Returns the "click" element.
     * 
     * @return the element
     */
    public El getEl() {
        return el;
    }

    /**
     * Returns the amount of time between "clicks".
     * 
     * @return the time in milliseconds
     */
    public int getInterval() {
        return interval;
    }

    /**
     * Returns the press CSS style name.
     * 
     * @return the press class
     */
    public String getPressClass() {
        return pressClass;
    }

    /**
     * Returns true if acceleration is enabled.
     * 
     * @return true if enabled
     */
    public boolean isAccelerate() {
        return accelerate;
    }

    /**
     * True if autorepeating should start slowly and accelerate (defaults to
     * false). "interval" and "delay" are ignored.
     * 
     * @param accelerate true to accelerate
     */
    public void setAccelerate(boolean accelerate) {
        this.accelerate = accelerate;
    }

    /**
     * The initial delay before the repeating event begins firing (defaults to
     * 250). Similar to an autorepeat key delay.
     * 
     * @param delay the delay in milliseconds
     */
    public void setDelay(int delay) {
        this.delay = delay;
    }

    /**
     * Sets the interval (defaults to 250).
     * 
     * @param interval the interval in milliseconds
     */
    public void setInterval(int interval) {
        this.interval = interval;
    }

    /**
     * A CSS class name to be applied to the element while pressed.
     * 
     * @param pressClass the style name
     */
    public void setPressClass(String pressClass) {
        this.pressClass = pressClass;
    }

    // private
    protected void click() {
        fireEvent(Events.OnClick);
        timer.schedule(accelerate ? easeOutExpo(new Date().getTime() - mousedownTime.getTime(), 400, -390, 12000)
                : interval);
    }

    protected int easeOutExpo(long t, int b, int c, int d) {
        return (int) ((t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b);
    }

    protected void handleMouseDown() {
        if (timer == null) {
            timer = new Timer() {
                public void run() {
                    click();
                }
            };
        }
        timer.cancel();
        el.blur();

        if (pressClass != null) {
            el.addStyleName(pressClass);
        }
        mousedownTime = new Date();

        waitForMouseOut = true;
        fireEvent(Events.OnMouseDown);
        fireEvent(Events.OnClick);

        // Do not honor delay or interval if acceleration wanted.
        if (accelerate) {
            delay = 400;
        }
        timer.schedule(delay);
    }

    protected void handleMouseOut() {
        if (waitForMouseOut) {
            timer.cancel();
            if (pressClass != null) {
                el.removeStyleName(pressClass);
            }
            waitForMouseOver = true;
        }
    }

    protected void handleMouseReturn() {
        if (waitForMouseOver) {
            waitForMouseOver = false;
            if (pressClass != null) {
                el.addStyleName(pressClass);
            }
            click();
        }
    }

    protected void handleMouseUp() {
        if (waitForMouseOut) {
            timer.cancel();
            waitForMouseOut = false;
            waitForMouseOver = false;
            el.removeStyleName(pressClass);
            fireEvent(Events.OnMouseUp);
        }
    }
}