001    /*
002     * $Id: RolloverProducer.java 3296 2009-03-11 12:06:01Z kleopatra $
003     *
004     * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005     * Santa Clara, California 95054, U.S.A. All rights reserved.
006     *
007     * This library is free software; you can redistribute it and/or
008     * modify it under the terms of the GNU Lesser General Public
009     * License as published by the Free Software Foundation; either
010     * version 2.1 of the License, or (at your option) any later version.
011     * 
012     * This library is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015     * Lesser General Public License for more details.
016     * 
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this library; if not, write to the Free Software
019     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020     */
021    package org.jdesktop.swingx.rollover;
022    
023    import java.awt.Point;
024    import java.awt.event.MouseEvent;
025    import java.awt.event.MouseListener;
026    import java.awt.event.MouseMotionListener;
027    
028    import javax.swing.JComponent;
029    
030    /**
031     * Mouse/Motion/Listener which maps mouse coordinates to client coordinates
032     * and stores these as client properties in the target JComponent. The exact
033     * mapping process is left to subclasses. Typically, they will map to "cell"
034     * coordinates. <p>
035     * 
036     * Note: this class assumes that the target component is of type JComponent.<p>
037     * Note: this implementation is stateful, it can't be shared across different 
038     * instances of a target component.<p>
039     * 
040     * 
041     * @author Jeanette Winzenburg
042     */
043    public abstract class RolloverProducer implements MouseListener, MouseMotionListener {
044    
045        /** 
046         * Key for client property mapped from mouse-triggered action.
047         * Note that the actual mouse-event which results in setting the property
048         * depends on the implementation of the concrete RolloverProducer. 
049         */
050        public static final String CLICKED_KEY = "swingx.clicked";
051    
052        /** Key for client property mapped from rollover events */
053        public static final String ROLLOVER_KEY = "swingx.rollover";
054    
055        //        public static final String PRESSED_KEY = "swingx.pressed";
056    
057        //----------------- mouseListener
058    
059        /**
060         * Implemented to map to client property clicked and fire always.
061         */
062        public void mouseReleased(MouseEvent e) {
063            updateRollover(e, CLICKED_KEY, true);
064        }
065    
066        /**
067         * Implemented to map to client property rollover and fire only if client
068         * coordinate changed.
069         */
070        public void mouseEntered(MouseEvent e) {
071            updateRollover(e, ROLLOVER_KEY, false);
072        }
073    
074        /**
075         * Implemented to remove client properties rollover and clicked. if the
076         * source is a JComponent. Does nothing otherwise.
077         */
078        public void mouseExited(MouseEvent e) {
079            ((JComponent) e.getSource()).putClientProperty(ROLLOVER_KEY, null);
080            ((JComponent) e.getSource()).putClientProperty(CLICKED_KEY, null);
081        }
082    
083        /**
084         * Implemented to do nothing.
085         */
086        public void mouseClicked(MouseEvent e) {
087        }
088    
089        /**
090         * Implemented to do nothing.
091         */
092        public void mousePressed(MouseEvent e) {
093        }
094    
095        // ---------------- MouseMotionListener
096        /**
097         * Implemented to do nothing.
098         * PENDING JW: probably should do something? Mapped coordinates will be out of synch
099         * after a drag.
100         */
101        public void mouseDragged(MouseEvent e) {
102        }
103    
104        /**
105         * Implemented to map to client property rollover and fire only if client
106         * coordinate changed.
107         */
108        public void mouseMoved(MouseEvent e) {
109            updateRollover(e, ROLLOVER_KEY, false);
110        }
111    
112        //---------------- mapping methods
113        
114        /**
115         * Controls the mapping of the given mouse event to a client property. This
116         * implementation first calls updateRolloverPoint to convert the mouse coordinates.
117         * Then calls updateClientProperty to actually set the client property in the
118         * 
119         * @param e the MouseEvent to map to client coordinates
120         * @param property the client property to map to
121         * @param fireAlways a flag indicating whether a client event should be fired if unchanged.
122         * 
123         * @see #updateRolloverPoint(JComponent, Point)
124         * @see #updateClientProperty(JComponent, String, boolean)
125         */
126        protected void updateRollover(MouseEvent e, String property,
127                boolean fireAlways) {
128            updateRolloverPoint((JComponent) e.getComponent(), e.getPoint());
129            updateClientProperty((JComponent) e.getSource(), property, fireAlways);
130        }
131    
132        /** Current mouse location in client coordinates. */
133        protected Point rollover = new Point(-1, -1);
134    
135        /**
136         * Sets the given client property to the value of current mouse location in 
137         * client coordinates. If fireAlways, the property is force to fire a change.
138         *  
139         * @param component the target component
140         * @param property the client property to set
141         * @param fireAlways a flag indicating whether a client property 
142         *  should be forced to fire an event.
143         */
144        protected void updateClientProperty(JComponent component, String property,
145                boolean fireAlways) {
146            if (fireAlways) {
147                // fix Issue #864-swingx: force propertyChangeEvent
148                component.putClientProperty(property, null);
149                component.putClientProperty(property, new Point(rollover));
150            } else {
151                Point p = (Point) component.getClientProperty(property);
152                if (p == null || (rollover.x != p.x) || (rollover.y != p.y)) {
153                    component.putClientProperty(property, new Point(rollover));
154                }
155            }
156        }
157    
158        /**
159         * Subclasses must implement to map the given mouse coordinates into
160         * appropriate client coordinates. The result must be stored in the 
161         * rollover field. 
162         * 
163         * @param component the target component which received a mouse event
164         * @param mousePoint the mouse position of the event, coordinates are 
165         *    component pixels
166         */
167        protected abstract void updateRolloverPoint(JComponent component, Point mousePoint);
168    
169    }