001: /*
002: * $RCSfile: ViewPlatformAWTBehavior.java,v $
003: *
004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistribution of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * - Redistribution in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * Neither the name of Sun Microsystems, Inc. or the names of
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * This software is provided "AS IS," without a warranty of any
023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034: * POSSIBILITY OF SUCH DAMAGES.
035: *
036: * You acknowledge that this software is not designed, licensed or
037: * intended for use in the design, construction, operation or
038: * maintenance of any nuclear facility.
039: *
040: * $Revision: 1.5 $
041: * $Date: 2007/02/09 17:20:15 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.utils.behaviors.vp;
046:
047: import java.awt.event.ComponentEvent;
048: import java.awt.event.MouseEvent;
049: import java.awt.event.MouseListener;
050: import java.awt.event.MouseWheelListener;
051: import java.awt.event.MouseMotionListener;
052: import java.awt.event.KeyListener;
053: import java.awt.event.KeyEvent;
054: import java.awt.AWTEvent;
055: import java.awt.Component;
056: import java.awt.Cursor;
057: import javax.swing.SwingUtilities;
058: import java.util.ArrayList;
059:
060: import javax.media.j3d.WakeupOnBehaviorPost;
061: import javax.media.j3d.WakeupOnElapsedFrames;
062: import javax.media.j3d.WakeupOr;
063: import javax.media.j3d.WakeupCriterion;
064: import javax.media.j3d.WakeupCondition;
065: import javax.media.j3d.TransformGroup;
066: import javax.media.j3d.Transform3D;
067: import javax.media.j3d.View;
068: import javax.media.j3d.Canvas3D;
069:
070: import javax.vecmath.Vector3f;
071: import com.sun.j3d.utils.universe.*;
072:
073: /**
074: * Abstract class which implements much of the event tracking and
075: * state updating in a thread safe manner.
076: *
077: * AWT Events are captured and placed in a queue.
078: *
079: * While there are pending events or motion the behavior will wake
080: * up every frame, call processAWTEvents and integrateTransforms.
081: *
082: * @since Java 3D 1.2.1
083: */
084: public abstract class ViewPlatformAWTBehavior extends
085: ViewPlatformBehavior implements MouseListener,
086: MouseMotionListener, KeyListener, MouseWheelListener {
087:
088: private final static boolean DEBUG = false;
089:
090: /**
091: * Behavior PostId used in this behavior
092: */
093: protected final static int POST_ID = 9998;
094:
095: /**
096: * The different criterion for the behavior to wakeup
097: */
098: protected WakeupOnElapsedFrames frameWakeup;
099:
100: /**
101: * The Or of the different criterion for the behavior to wakeup
102: */
103: protected WakeupOnBehaviorPost postWakeup;
104:
105: /**
106: * The target Transform3D for this behavior
107: */
108: protected Transform3D targetTransform = new Transform3D();
109:
110: /**
111: * Boolean for whether the mouse is in motion
112: */
113: protected boolean motion = false;
114:
115: /**
116: * Flag indicating Behavior should listen for Mouse Events
117: */
118: public final static int MOUSE_LISTENER = 0x01;
119:
120: /**
121: * Flag indicating Behavior should listen for Mouse Motion Events
122: */
123: public final static int MOUSE_MOTION_LISTENER = 0x02;
124:
125: /**
126: * Flag indicating Behavior should listen for Key Events
127: */
128: public final static int KEY_LISTENER = 0x04;
129:
130: /**
131: * Flag indicating Behavior should listen for MouseWheel Events
132: */
133: public final static int MOUSE_WHEEL_LISTENER = 0x08;
134:
135: /**
136: * The Canvas3Ds from which this Behavior gets AWT events
137: */
138: protected Canvas3D canvases[];
139:
140: private ArrayList eventQueue = new ArrayList();
141: private int listenerFlags = 0;
142: private boolean firstEvent = false;
143:
144: /**
145: * Parameterless constructor for this behavior, intended for use by
146: * subclasses instantiated through ConfiguredUniverse. Such a constructor
147: * is required for configurable behaviors.
148: * @since Java 3D 1.3
149: */
150: protected ViewPlatformAWTBehavior() {
151: super ();
152: }
153:
154: /**
155: * Construct a behavior which listens for events specified by the given
156: * flags, intended for use by subclasses instantiated through
157: * ConfiguredUniverse.
158: *
159: * @param listenerFlags Indicates which listener should be registered,
160: * one or more of MOUSE_LISTENER, MOUSE_MOTION_LISTENER, KEY_LISTENER, MOUSE_WHEEL_LISTENER
161: * @since Java 3D 1.3
162: */
163: protected ViewPlatformAWTBehavior(int listenerFlags) {
164: super ();
165: setListenerFlags(listenerFlags);
166: }
167:
168: /**
169: * Constructs a new ViewPlatformAWTBehavior.
170: *
171: * @param c The Canvas3D on which to listen for events. If this is null a
172: * NullPointerException will be thrown.
173: * @param listenerFlags Indicates which listener should be registered,
174: * one or more of MOUSE_LISTENER, MOUSE_MOTION_LISTENER, KEY_LISTENER, MOUSE_WHEEL_LISTENER
175: */
176: public ViewPlatformAWTBehavior(Canvas3D c, int listenerFlags) {
177: super ();
178:
179: if (c == null)
180: throw new NullPointerException();
181:
182: canvases = new Canvas3D[] { c };
183: setListenerFlags(listenerFlags);
184: }
185:
186: /**
187: * Sets listener flags for this behavior.
188: *
189: * @param listenerFlags Indicates which listener should be registered,
190: * one or more of MOUSE_LISTENER, MOUSE_MOTION_LISTENER, KEY_LISTENER, MOUSE_WHEEL_LISTENER
191: * @since Java 3D 1.3
192: */
193: protected void setListenerFlags(int listenerFlags) {
194: this .listenerFlags = listenerFlags;
195: }
196:
197: /**
198: * Initializes the behavior.
199: * NOTE: Applications should not call this method. It is called by the
200: * Java 3D behavior scheduler.
201: */
202: public void initialize() {
203: frameWakeup = new WakeupOnElapsedFrames(0);
204: postWakeup = new WakeupOnBehaviorPost(this , POST_ID);
205:
206: wakeupOn(postWakeup);
207: }
208:
209: /**
210: * Process a stimulus meant for this behavior.
211: * NOTE: Applications should not call this method. It is called by the
212: * Java 3D behavior scheduler.
213: */
214: public void processStimulus(java.util.Enumeration behEnum) {
215: boolean hadPost = false;
216:
217: while (behEnum.hasMoreElements()) {
218: WakeupCondition wakeup = (WakeupCondition) behEnum
219: .nextElement();
220: if (wakeup instanceof WakeupOnBehaviorPost) {
221: hadPost = true;
222: } else if (wakeup instanceof WakeupOnElapsedFrames) {
223: AWTEvent[] events = null;
224: // access to event queue must be synchronized
225: synchronized (eventQueue) {
226: events = (AWTEvent[]) eventQueue
227: .toArray(new AWTEvent[eventQueue.size()]);
228: eventQueue.clear();
229: }
230: processAWTEvents(events);
231:
232: if (motion)
233: integrateTransforms();
234: }
235: }
236:
237: if (motion || hadPost) {
238: // wake up on behavior posts and elapsed frames if in motion
239: wakeupOn(frameWakeup);
240: } else {
241: // only wake up on behavior posts if not in motion
242: wakeupOn(postWakeup);
243: }
244: }
245:
246: /**
247: * Overload setEnable from Behavior.
248: *
249: * Adds/Removes the AWT listeners depending on the requested
250: * state.
251: */
252: public void setEnable(boolean state) {
253: if (state == getEnable())
254: return;
255:
256: super .setEnable(state);
257:
258: if (canvases != null) {
259: enableListeners(state);
260: }
261: }
262:
263: private void enableListeners(boolean enable) {
264: if (enable) {
265: firstEvent = true;
266: if ((listenerFlags & MOUSE_LISTENER) != 0)
267: for (int i = 0; i < canvases.length; i++)
268: canvases[i].addMouseListener(this );
269:
270: if ((listenerFlags & MOUSE_MOTION_LISTENER) != 0)
271: for (int i = 0; i < canvases.length; i++)
272: canvases[i].addMouseMotionListener(this );
273:
274: if ((listenerFlags & MOUSE_WHEEL_LISTENER) != 0)
275: for (int i = 0; i < canvases.length; i++)
276: canvases[i].addMouseWheelListener(this );
277:
278: if ((listenerFlags & KEY_LISTENER) != 0)
279: for (int i = 0; i < canvases.length; i++)
280: canvases[i].addKeyListener(this );
281: } else {
282: if ((listenerFlags & MOUSE_LISTENER) != 0)
283: for (int i = 0; i < canvases.length; i++)
284: canvases[i].removeMouseListener(this );
285:
286: if ((listenerFlags & MOUSE_MOTION_LISTENER) != 0)
287: for (int i = 0; i < canvases.length; i++)
288: canvases[i].removeMouseMotionListener(this );
289:
290: if ((listenerFlags & MOUSE_WHEEL_LISTENER) != 0)
291: for (int i = 0; i < canvases.length; i++)
292: canvases[i].removeMouseWheelListener(this );
293:
294: if ((listenerFlags & KEY_LISTENER) != 0)
295: for (int i = 0; i < canvases.length; i++)
296: canvases[i].removeKeyListener(this );
297: }
298: }
299:
300: /**
301: * Sets the ViewingPlatform for this behavior. This method is
302: * called by the ViewingPlatform.
303: * If a sub-calls overrides this method, it must call
304: * super.setViewingPlatform(vp).
305: * NOTE: Applications should <i>not</i> call this method.
306: */
307: public void setViewingPlatform(ViewingPlatform vp) {
308: super .setViewingPlatform(vp);
309:
310: if (vp == null) {
311: enableListeners(false);
312: } else {
313: if (canvases != null) {
314: // May be switching canvases here.
315: enableListeners(false);
316: }
317:
318: // Use the canvases associated with viewer[0]; if no viewer is
319: // available yet, see if a canvas was provided with a constructor.
320: Viewer[] viewers = vp.getViewers();
321:
322: if (viewers != null && viewers[0] != null)
323: canvases = viewers[0].getCanvas3Ds();
324:
325: if (canvases == null || canvases[0] == null)
326: throw new IllegalStateException("No canvases available");
327:
328: if (getEnable()) {
329: enableListeners(true);
330: }
331: }
332: }
333:
334: /**
335: * This is called once per frame if there are any AWT events to
336: * process.
337: *
338: * The <code>motion</code> variable will be true when the method
339: * is called. If it is true when the method returns integrateTransforms
340: * will be called immediately.
341: *
342: * The AWTEvents are presented in the array in the order in which they
343: * arrived from AWT.
344: */
345: protected abstract void processAWTEvents(
346: final java.awt.AWTEvent[] events);
347:
348: /**
349: * Called once per frame (if the view is moving) to calculate the new
350: * view platform transform
351: */
352: protected abstract void integrateTransforms();
353:
354: /**
355: * Queue AWTEvents in a thread safe manner.
356: *
357: * If subclasses override this method they must call
358: * super.queueAWTEvent(e)
359: */
360: protected void queueAWTEvent(AWTEvent e) {
361: // add new event to the queue
362: // must be MT safe
363: synchronized (eventQueue) {
364: eventQueue.add(e);
365: // Only need to post if this is the only event in the queue.
366: // There have been reports that the first event after
367: // setViewingPlatform() is sometimes missed, so check the
368: // firstEvent flag as well.
369: if (firstEvent || eventQueue.size() == 1) {
370: firstEvent = false;
371: postId(POST_ID);
372: }
373: }
374: }
375:
376: public void mouseClicked(final MouseEvent e) {
377: queueAWTEvent(e);
378: }
379:
380: public void mouseEntered(final MouseEvent e) {
381: queueAWTEvent(e);
382: }
383:
384: public void mouseExited(final MouseEvent e) {
385: queueAWTEvent(e);
386: }
387:
388: public void mousePressed(final MouseEvent e) {
389: queueAWTEvent(e);
390: }
391:
392: public void mouseReleased(final MouseEvent e) {
393: queueAWTEvent(e);
394: }
395:
396: public void mouseDragged(final MouseEvent e) {
397: queueAWTEvent(e);
398: }
399:
400: public void mouseMoved(final MouseEvent e) {
401: queueAWTEvent(e);
402: }
403:
404: public void keyReleased(final java.awt.event.KeyEvent e) {
405: queueAWTEvent(e);
406: }
407:
408: public void keyPressed(final java.awt.event.KeyEvent e) {
409: queueAWTEvent(e);
410: }
411:
412: public void keyTyped(final java.awt.event.KeyEvent e) {
413: queueAWTEvent(e);
414: }
415:
416: public void mouseWheelMoved(final java.awt.event.MouseWheelEvent e) {
417: queueAWTEvent(e);
418: }
419: }
|