001 /**
002 * Copyright (c) 2008-2009, Piet Blok
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without
006 * modification, are permitted provided that the following conditions
007 * are met:
008 *
009 * * Redistributions of source code must retain the above copyright
010 * notice, this list of conditions and the following disclaimer.
011 * * Redistributions in binary form must reproduce the above
012 * copyright notice, this list of conditions and the following
013 * disclaimer in the documentation and/or other materials provided
014 * with the distribution.
015 * * Neither the name of the copyright holder nor the names of the
016 * contributors may be used to endorse or promote products derived
017 * from this software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
020 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
021 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
022 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
023 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
024 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
025 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
026 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
027 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
029 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031
032 package org.pbjar.jxlayer.plaf.misc;
033
034 import java.awt.Cursor;
035 import java.awt.Point;
036 import java.awt.Toolkit;
037 import java.awt.event.AWTEventListener;
038 import java.awt.event.ActionEvent;
039 import java.awt.event.ActionListener;
040 import java.awt.event.MouseEvent;
041 import java.awt.image.BufferedImage;
042 import java.util.ArrayList;
043 import java.util.List;
044
045 import javax.swing.AbstractAction;
046 import javax.swing.Action;
047 import javax.swing.JComponent;
048 import javax.swing.JOptionPane;
049 import javax.swing.JSpinner;
050 import javax.swing.SpinnerNumberModel;
051 import javax.swing.Timer;
052
053 import org.jdesktop.jxlayer.JXLayer;
054
055 /**
056 * A LayerUI that hides the cursor. After a MouseEvent or MouseMoveEvent the
057 * cursor will reappear for some specified time.
058 *
059 * @author Piet Blok
060 */
061 public final class HideCursorUI extends
062 GeneralLayerUI<JComponent, HideCursorUI.HideCursorState> {
063
064 /**
065 * Holds state information.
066 */
067 protected static class HideCursorState {
068
069 private final Timer timer;
070
071 private int timeout;
072
073 private final Cursor oldCursor;
074
075 public HideCursorState(final JXLayer<JComponent> layer, int timeout) {
076 this.timeout = timeout;
077 oldCursor = layer.getGlassPane().getCursor();
078 this.timer = new Timer(timeout, new ActionListener() {
079
080 @Override
081 public void actionPerformed(ActionEvent event) {
082 layer.getGlassPane().setCursor(nullCursor);
083 }
084 });
085 timer.setRepeats(false);
086 }
087
088 public int getTimeout() {
089 return timeout;
090 }
091
092 public void resetCursor(JXLayer<JComponent> layer) {
093 if (timeout > 0) {
094 layer.getGlassPane().setCursor(oldCursor);
095 timer.restart();
096 }
097 }
098
099 public void setTimeout(int timeout) {
100 this.timeout = timeout;
101 timer.setInitialDelay(timeout);
102 }
103
104 }
105
106 private static final Cursor nullCursor = Toolkit.getDefaultToolkit()
107 .createCustomCursor(
108 new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB),
109 new Point(0, 0), "nullCursor");
110
111 private final int timeout;
112
113 /**
114 * Equivalent to {@code HideCursorUI(0, false)}.
115 *
116 * @see #HideCursorUI(int, boolean)
117 */
118 public HideCursorUI() {
119 this(0, false);
120 }
121
122 /**
123 * Equivalent to {@code HideCursorUI(timeout, false)}.
124 *
125 * @see #HideCursorUI(int, boolean)
126 */
127 public HideCursorUI(int timeout) {
128 this(timeout, false);
129 }
130
131 /**
132 * Create an instance. Via the timeout argument the time can be specified
133 * for how long the cursor must be shown after a MouseEvent or
134 * MouseMoveEvent. A value of 0 or negative indicates that the cursor will
135 * not be shown at all, even after a MouseEvent or MouseMoveEvent.
136 * <p>
137 * Via the enableAWTEventListener argument, {@link AWTEventListener} can be
138 * enabled or disabled.
139 * </p>
140 *
141 * @param timeout
142 * the timeout time in milliseconds
143 * @param enableAWTEventListener
144 * if {@code true}, {@link AWTEventListener} will be enabled.
145 * Specifying {@code true} Solves a problem with non editable
146 * {@code JTextComponent}s.
147 *
148 * @throws SecurityException
149 * when enableAWTEventListener is {@code true} and if a security
150 * manager exists and its {@code checkPermission} method doesn't
151 * allow the operation.
152 * @see Toolkit#addAWTEventListener(AWTEventListener, long)
153 */
154 public HideCursorUI(int timeout, boolean enableAWTEventListener) {
155 super(enableAWTEventListener);
156 this.timeout = timeout;
157 }
158
159 /**
160 * Get {@link Action}s that:
161 * <ol>
162 * <li>Set the cursor timeout value.<li>
163 * </ol>
164 */
165 @Override
166 public List<Action> getActions(final JXLayer<JComponent> layer) {
167 ArrayList<Action> actionList = new ArrayList<Action>();
168 actionList.addAll(super.getActions(layer));
169 /*
170 * Change the cursor timeout
171 */
172 actionList.add(new AbstractAction("Set cursor timeout") {
173
174 private static final long serialVersionUID = 1L;
175
176 @Override
177 public void actionPerformed(ActionEvent event) {
178 HideCursorState state = HideCursorUI.this.getStateObject(layer);
179 Integer timeout = state.getTimeout();
180 JSpinner spinner = new JSpinner();
181 SpinnerNumberModel model = (SpinnerNumberModel) spinner
182 .getModel();
183 model.setStepSize(100);
184 model.setMinimum(0);
185 spinner.setValue(timeout);
186 if (JOptionPane.OK_OPTION == JOptionPane.showConfirmDialog(
187 layer, spinner, "Change cursor timeout",
188 JOptionPane.OK_CANCEL_OPTION)) {
189 timeout = (Integer) spinner.getValue();
190 state.setTimeout(timeout);
191 }
192 }
193 });
194
195 return actionList;
196 }
197
198 private void resetCursor(JXLayer<JComponent> layer) {
199 getStateObject(layer).resetCursor(layer);
200 }
201
202 @Override
203 protected void cleanupStateObject(HideCursorState stateObject) {
204 stateObject.timer.stop();
205 }
206
207 @Override
208 protected HideCursorState createStateObject(JXLayer<JComponent> layer) {
209 return new HideCursorState(layer, timeout);
210 }
211
212 @Override
213 protected void processMouseEvent(MouseEvent e, JXLayer<JComponent> layer) {
214 super.processMouseEvent(e, layer);
215 resetCursor(layer);
216 }
217
218 @Override
219 protected void processMouseMotionEvent(MouseEvent e, JXLayer<JComponent> l) {
220 super.processMouseMotionEvent(e, l);
221 resetCursor(l);
222 }
223
224 }