org.vectomatic.dom.svg.ui.SVGButtonBase.java Source code

Java tutorial

Introduction

Here is the source code for org.vectomatic.dom.svg.ui.SVGButtonBase.java

Source

/**********************************************
 * Copyright (C) 2010 Lukas Laag
 * This file is part of lib-gwt-svg.
 * 
 * libgwtsvg is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * libgwtsvg 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with libgwtsvg.  If not, see http://www.gnu.org/licenses/
 **********************************************/
package org.vectomatic.dom.svg.ui;

import java.util.HashMap;
import java.util.Map;

import org.vectomatic.dom.svg.OMSVGAnimatedString;
import org.vectomatic.dom.svg.OMSVGSVGElement;
import org.vectomatic.dom.svg.OMSVGStyle;
import org.vectomatic.dom.svg.itf.ISVGStylable;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasAllMouseHandlers;
import com.google.gwt.event.dom.client.HasClickHandlers;
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.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
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;

/**
 * Abstract base class for SVG buttons. 
 * <p>SVG buttons consists
 * in an SVG element and a collection of six predefined faces<p>
 * <ul>
 * <li>UP</li>
 * <li>UP_DISABLED</li>
 * <li>UP_HOVERING</li>
 * <li>DOWN</li>
 * <li>DOWN_DISABLED</li>
 * <li>DOWN_HOVERING</li>
 * </ul>
 * <p>Each face consists in a list of changes which are applied to the
 * main SVG element (currently, CSS style changes but other changes
 * are possible). You do not need to specify all faces for a button. In
 * case a face is missing, the widget will attempt to use another face for
 * the button.</p>
 * @author laaglu
 */
public abstract class SVGButtonBase extends SVGWidget implements HasClickHandlers, HasAllMouseHandlers,
        MouseDownHandler, MouseUpHandler, MouseOverHandler, MouseOutHandler, ClickHandler, ISVGStylable {
    /**
     * Enum to represent the possible states of an SVG button
     * @author laaglu
     */
    public enum SVGFaceName {
        /**
         * face shown when button is up
         */
        UP,
        /**
         * face shown when button is up and disabled
         */
        UP_DISABLED,
        /**
         * face shown when the cursor is hovering over an up enabled button
         */
        UP_HOVERING,
        /**
         * face shown when button is down
         */
        DOWN,
        /**
         * face shown when button is down and disabled
         */
        DOWN_DISABLED,
        /**
         * face shown when the cursor is hovering over a down enabled button
         */
        DOWN_HOVERING
    }

    /**
     * Class to represent an SVG button face. A
     * button face consists in an array of changes
     * to the button SVG which occur when the face is displayed
     */
    public static class SVGFace {
        private SVGFaceChange[] changes;

        /**
         * Constructor
         * @param changes an array of changes to the
         *  button SVG which occur when the face is displayed
         */
        public SVGFace(SVGFaceChange[] changes) {
            this.changes = changes;
        }

        /**
         * Returns the array of changes to the
         * button SVG which occur when the face is displayed
         * @return the array of changes to the
         * button SVG which occur when the face is displayed
         */
        public SVGFaceChange[] getChanges() {
            return changes;
        }
    }

    /**
     * Base class to represent the changes occurring
     * to an SVG button when it enters a new state.
     * @author laaglu
     */
    public static abstract class SVGFaceChange {
        void install(SVGButtonBase button) {
        }

        void uninstall(SVGButtonBase button) {
        }
    }

    /**
     * Class to represent a style change as an SVG
     * button enters a new state.
     * @author laaglu
     */
    public static class SVGStyleChange extends SVGFaceChange {
        private String[] classNames;

        public SVGStyleChange(String[] classNames) {
            this.classNames = classNames;
        }

        @Override
        void uninstall(SVGButtonBase button) {
            if (button.svgElement != null) {
                for (String className : classNames) {
                    button.svgElement.removeClassNameBaseVal(className);
                }
            }
        }

        @Override
        void install(SVGButtonBase button) {
            if (button.svgElement != null) {
                for (String className : classNames) {
                    button.svgElement.addClassNameBaseVal(className);
                }
            }
        }

        public String[] getClassNames() {
            return classNames;
        }

        public void getClassNames(String[] classNames) {
            this.classNames = classNames;
        }
    }

    /**
     * The {@link org.vectomatic.dom.svg.OMSVGSVGElement} representing
     * this button
     */
    protected OMSVGSVGElement svgElement;
    /**
     * The name of the face currently displayed by this button
     */
    protected SVGFaceName currentFaceName;
    /**
     * A map associating button face names to button faces
     */
    protected Map<SVGFaceName, SVGFace> faces;

    /**
     * No-arg constructor.
     * You must call {@link SVGButtonBase#setResource(SVGResource)} or {@link SVGButtonBase#setSvgElement(OMSVGSVGElement)}
     * before using the widget.
     */
    protected SVGButtonBase() {
        faces = new HashMap<SVGFaceName, SVGFace>();
    }

    /**
     * Constructor
     * @param svgElement
     * The SVG element defining the button
     * @param faces
     * A collection of faces
     */
    protected SVGButtonBase(OMSVGSVGElement svgElement, Map<SVGFaceName, SVGFace> faces) {
        this();
        if (faces != null) {
            this.faces.putAll(faces);
        }
        setSvgElement(svgElement);
    }

    /**
     * Constructor
     * @param resource
     * An SVG resource to use for the SVG element defining the button
     * @param faces
     * The SVG element defining the button
     */
    protected SVGButtonBase(SVGResource resource, Map<SVGFaceName, SVGFace> faces) {
        this(resource.getSvg(), faces);
    }

    /**
     * Adds a new faces to the button
     * @param faceName
     * The face name
     * @param face
     * The face
     * @return
     * The face previously associated with this face name if there was one,
     * null otherwise
     */
    public SVGFace addFace(SVGFaceName faceName, SVGFace face) {
        return faces.put(faceName, face);
    }

    /**
     * Returns the face associated with a face name
     * @param faceName
     * The face name
     * @return
     * The face associated with this face name if there is one,
     * null otherwise
     */
    public SVGFace getFace(SVGFaceName faceName) {
        return faces.get(faceName);
    }

    /**
     * Sets the SVG resource defining the button
     * @param resource
     * An SVG resource
     */
    public void setResource(SVGResource resource) {
        setSvgElement(resource.getSvg());
    }

    /**
     * Returns the SVG element defining the button
     * @return
     * the SVG element defining the button
     */
    public OMSVGSVGElement getSvgElement() {
        return svgElement;
    }

    /**
     * Sets the SVG element defining the button
     * @param svgElement
     * the SVG element defining the button
     */
    public void setSvgElement(OMSVGSVGElement svgElement) {
        this.svgElement = svgElement;
        setElement(this.svgElement.getElement());
        if (this.svgElement != null) {
            this.svgElement.addDomHandler(this, MouseOutEvent.getType());
            this.svgElement.addDomHandler(this, MouseOverEvent.getType());
            this.svgElement.addDomHandler(this, MouseUpEvent.getType());
            this.svgElement.addDomHandler(this, MouseDownEvent.getType());
            this.svgElement.addDomHandler(this, ClickEvent.getType());
        }
    }

    /**
     * Returns the name of the face currently displayed by this button
     * @return
     * the name of the face currently displayed by this button
     */
    public SVGFaceName getCurrentFaceName() {
        return currentFaceName;
    }

    /**
     * Returns true if this button is enabled, false otherwise
     * @return
     * true if this button is enabled, false otherwise
     */
    public boolean isEnabled() {
        return currentFaceName != SVGFaceName.UP_DISABLED && currentFaceName != SVGFaceName.DOWN_DISABLED;
    }

    /**
     * Sets whether this button is enabled
     * @param enabled
     * true to enable the button, false to disable it
     */
    public void setEnabled(boolean enabled) {
        if (enabled) {
            switch (currentFaceName) {
            case UP_DISABLED:
            case UP_HOVERING:
                showFace(SVGFaceName.UP);
                break;
            case DOWN_DISABLED:
            case DOWN_HOVERING:
                showFace(SVGFaceName.DOWN);
                break;
            }
        } else {
            switch (currentFaceName) {
            case UP:
            case UP_HOVERING:
                showFace(SVGFaceName.UP_DISABLED);
                break;
            case DOWN:
            case DOWN_HOVERING:
                showFace(SVGFaceName.DOWN_DISABLED);
                break;
            }
        }
    }

    /**
     * Forces the button to display the specified face
     * @param faceName
     * The name of the face to display
     */
    public void showFace(SVGFaceName faceName) {
        //      GWT.log((currentFaceName != null ? currentFaceName.name() : "null") + " -> " + faceName.name());
        SVGFace currentFace = currentFaceName != null ? getFace(currentFaceName) : null;
        SVGFace face = faceName != null ? getFace(faceName) : null;
        if (face != currentFace) {
            if (currentFace != null) {
                for (SVGFaceChange change : currentFace.getChanges()) {
                    change.uninstall(this);
                }
            }
            if (face != null) {
                for (SVGFaceChange change : face.getChanges()) {
                    change.install(this);
                }
            }
        }
        currentFaceName = faceName;
    }

    @Override
    public HandlerRegistration addClickHandler(ClickHandler handler) {
        return svgElement.addDomHandler(handler, ClickEvent.getType());
    }

    @Override
    public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
        return svgElement.addDomHandler(handler, MouseDownEvent.getType());
    }

    @Override
    public HandlerRegistration addMouseUpHandler(MouseUpHandler handler) {
        return svgElement.addDomHandler(handler, MouseUpEvent.getType());
    }

    @Override
    public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) {
        return svgElement.addDomHandler(handler, MouseOutEvent.getType());
    }

    @Override
    public HandlerRegistration addMouseOverHandler(MouseOverHandler handler) {
        return svgElement.addDomHandler(handler, MouseOverEvent.getType());
    }

    @Override
    public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
        return svgElement.addDomHandler(handler, MouseMoveEvent.getType());
    }

    @Override
    public HandlerRegistration addMouseWheelHandler(MouseWheelHandler handler) {
        return svgElement.addDomHandler(handler, MouseWheelEvent.getType());
    }

    // Implementation of the svg::Stylable W3C IDL interface
    public OMSVGStyle getStyle() {
        return svgElement.getStyle();
    }

    public final OMSVGAnimatedString getClassName() {
        return svgElement.getClassName();
    }

    public final void addClassNameBaseVal(String className) {
        svgElement.addClassNameBaseVal(className);
    }

    public final void removeClassNameBaseVal(String className) {
        svgElement.removeClassNameBaseVal(className);
    }

    public final void replaceClassNameBaseVal(String oldClassName, String newClassName) {
        svgElement.replaceClassNameBaseVal(oldClassName, newClassName);
    }

    public final void setClassNameBaseVal(String className) {
        svgElement.setClassNameBaseVal(className);
    }

    @Override
    public void onClick(ClickEvent event) {
        // Silently block the event. Otherwise it will propagate
        // to parent elements in Webkit and trigger text selection
        event.stopPropagation();
        event.preventDefault();
    }
}