Source Code Cross Referenced for Animator.java in  » Science » jcm1-source » edu » hws » jcm » awt » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Science » jcm1 source » edu.hws.jcm.awt 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*************************************************************************
002:         *                                                                        *
003:         *   1) This source code file, in unmodified form, and compiled classes   *
004:         *      derived from it can be used and distributed without restriction,  *
005:         *      including for commercial use.  (Attribution is not required       *
006:         *      but is appreciated.)                                              *
007:         *                                                                        *
008:         *    2) Modified versions of this file can be made and distributed       *
009:         *       provided:  the modified versions are put into a Java package     *
010:         *       different from the original package, edu.hws;  modified          *
011:         *       versions are distributed under the same terms as the original;   *
012:         *       and the modifications are documented in comments.  (Modification *
013:         *       here does not include simply making subclasses that belong to    *
014:         *       a package other than edu.hws, which can be done without any      *
015:         *       restriction.)                                                    *
016:         *                                                                        *
017:         *   David J. Eck                                                         *
018:         *   Department of Mathematics and Computer Science                       *
019:         *   Hobart and William Smith Colleges                                    *
020:         *   Geneva, New York 14456,   USA                                        *
021:         *   Email: eck@hws.edu          WWW: http://math.hws.edu/eck/            *
022:         *                                                                        *
023:         *************************************************************************/package edu.hws.jcm.awt;
024:
025:        import edu.hws.jcm.data.*;
026:        import java.awt.*;
027:        import java.awt.event.*;
028:
029:        /**
030:         * An Animator can change a value continuously, without user intervention, by running
031:         * a separate Thread.  By default, an animator appears as a "Start" button.  When the
032:         * button is pressed, the value of the animator starts counting 0, 1, 2, ...  The button
033:         * changes to a "Stop" button.  When this is pressed, the value stops changing.  A Controller
034:         * can be set, by calling the setOnChange() method, to be notified whenever the value is
035:         * changed.  If this is done, then the value of the Animator will only change when its
036:         * checkInput() method is called, so it should be added to a Controller which will call
037:         * this method.
038:         *
039:         * <p>The getValueAsVariable() method can be called to get a Variable whose value is
040:         * the value of the Animator.  This variable can then be added to a Parser, so it can
041:         * be used in expressions.  An Animator is "Tieable", so it can share its value
042:         * with another InputObject, such as a VariableSlider or a VariableIput.
043:         *
044:         * <p>There are many options:  If maximum and minimum values are both specified, then the value
045:         * of the Animator ranges between these values.  By default, this interval is divided into
046:         * 100 sub-intervals, so that there are 101 frames.  However, the number of intervals can
047:         * also be set.  If no min or max is specified but a number of intervals is specified,
048:         * then the value is an integer which ranges from 0 up to the specified number of intervals.
049:         * If the number of frames is finite, then there are three possibities when the last
050:         * frame is reached:  The animation can stop; it can loop back to the the starting
051:         * frame, or it can reverse direction and cycle back and forth.  The behavior is controlled
052:         * with the setLoopStyle() method.
053:         *
054:         * <p>An Animator is actually a Panel which can contain other controls in addition to or
055:         * instead of the Start/Stop button.  For example, it can contain a "Next" button or
056:         * a pop-up menu to control the speed.
057:         * 
058:         */
059:        public class Animator extends Panel implements  Value, Tieable,
060:                InputObject, ActionListener, ItemListener, Runnable {
061:
062:            /**
063:             * Used to add a component to the Animator Panel; can be used in a constructor
064:             * or in the addControl() method.  Can also be used in the getControl() method
065:             * to specify which component is to be retrieved.
066:             */
067:            public static final int START_STOP_BUTTON = 1, START_BUTTON = 2,
068:                    PAUSE_BUTTON = 4, STOP_BUTTON = 8, NEXT_BUTTON = 16,
069:                    PREV_BUTTON = 32, SPEED_CHOICE = 64, LOOP_CHOICE = 128;
070:
071:            /**
072:             * Indicates that the components in the Animator panel are to be stacked vertically.
073:             * (Can be used in a constructor and in the setOrientation method.)
074:             */
075:            public static final int VERTICAL = 1;
076:
077:            /**
078:             * Indicates that the components in the Animator panel are to be in a horizontal row.
079:             * (Can be used in a constructor and in the setOrientation method.)
080:             */
081:            public static final int HORIZONTAL = 0;
082:
083:            /**
084:             * Represents a loop style in which the animation is played once.  When the final frame
085:             * is reached, the animation ends.  Use in the setLoopStyle() method.
086:             */
087:            public static final int ONCE = 0;
088:
089:            /**
090:             * Represents a loop style in which the animation is played repeatedly.  When the final frame
091:             * is reached, the animation returns to the first frame.  Use in the setLoopStyle() method.
092:             */
093:            public static final int LOOP = 1;
094:
095:            /**
096:             * Represents a loop style in which the animation is cycled back and forth.  When the final frame
097:             * is reached, the animation reverses direction.  Use in the setLoopStyle() method.
098:             */
099:            public static final int BACK_AND_FORTH = 2;
100:
101:            private Button startStopButton, startButton, stopButton,
102:                    pauseButton, nextButton, prevButton;
103:            private Choice speedChoice, loopChoice;
104:            private int orientation;
105:            private String startButtonName = "Start";
106:            private String stopButtonName = "Stop";
107:
108:            private volatile int loopStyle;
109:            private boolean runningBackwards;
110:            private volatile int millisPerFrame = 100;
111:            private volatile int frame;
112:            private int maxFrame;
113:            private double value;
114:
115:            private volatile long serialNumber = 1;
116:
117:            private Computable onChange;
118:
119:            private Value min, max; // If both are non-null, give the max and min values of the animator.
120:            private Value intervals; // If non-null, gives the number of sub-intervals.  Number of frames is this value plus one.
121:            private boolean needsValueCheck = true;
122:            private double min_val, max_val; // Values of min and max.
123:            private int intervals_val; // Value of intervals.
124:
125:            private static int START = 0, PAUSE = 1, NEXT = 2, PREV = 3,
126:                    STOP = 4, RUN = 5; // possible values of thread status
127:            private Thread runner;
128:            private volatile int status = STOP;
129:
130:            private boolean undefinedWhenNotRunning;
131:
132:            /**
133:             * Create a default Animator.  If no changes are made by calling other methods, it will appear as
134:             * a Start/Stop button.  When Start is pressed, the value will count 0, 1, 2, 3, ..., until the Stop
135:             * button is pressed.  Restarting the animation starts the value again at zero.
136:             */
137:            public Animator() {
138:                this (START_STOP_BUTTON, HORIZONTAL);
139:            }
140:
141:            /**
142:             * Create an Animator containing the specified control.  The parameter can consist of one or
143:             * more of the following constants, or'ed together:  START_STOP_BUTTON, START_BUTTON, STOP_BUTTON,
144:             * PAUSE_BUTTON, NEXT_BUTTON, PREV_BUTTON, SPEED_CHOICE, LOOP_CHOICE.  If no changes are made
145:             * by calling other methods, the value of the Animator will be 0, 1, 2, 3, ....  The components
146:             * are arranged into one horizontal row, using a GridLayout.
147:             */
148:            public Animator(int controls) {
149:                this (controls, HORIZONTAL, null, null, null);
150:            }
151:
152:            /**
153:             * Create an Animator containing specified controls.  (See the one-parameter constructor.)
154:             * The second parameter should be one of the constants HORIZONTAL or VERTICAL, to specify
155:             * how the components are arranged in the Animator panel.
156:             */
157:            public Animator(int controls, int orientation) {
158:                this (controls, orientation, null, null, null);
159:            }
160:
161:            /** Create an Animator with specified controls, orienation, range limits and number of intervals
162:             *
163:             * @param controls Specify the controls to add to the Animator.  Can consist of one or
164:             *      more of the following constants, or'ed together:  START_STOP_BUTTON, START_BUTTON, STOP_BUTTON,
165:             *      PAUSE_BUTTON, NEXT_BUTTON, PREV_BUTTON, SPEED_CHOICE, LOOP_CHOICE.
166:             * @param orientation How the controls are arranged in the panel.  One of the constants VERTICAL or HORIZONTAL.
167:             * @param min If BOTH min and max are non-null, they specify the range of values of the Animator.
168:             * @param max If BOTH min and max are non-null, they specify the range of values of the Animator.
169:             * @param intervals If non-null, specifies the number of intervals into which the range of values
170:             *      is divided.  Note that the value will be rounded to the nearest integer and clamped to the
171:             *      range 0 to 100000.   The number of frames is the number of intervals, plus one.  If min and max are
172:             *      non-null and intervals is null, then a default value of 100 is used.  If either min or max is
173:             *      null and intervals is non-null, then the Animator takes on the values 0, 1, 2, ..., intervals.
174:             */
175:            public Animator(int controls, int orientation, Value min,
176:                    Value max, Value intervals) {
177:                this .min = min;
178:                this .max = max;
179:                this .intervals = intervals;
180:                this .orientation = orientation;
181:                if (orientation == VERTICAL)
182:                    setLayout(new GridLayout(0, 1));
183:                else
184:                    setLayout(new GridLayout(1, 0));
185:                for (int i = 1; i <= LOOP_CHOICE; i <<= 1)
186:                    if ((i & controls) != 0)
187:                        addControl(i);
188:            }
189:
190:            //-------------- Accessor methods for public properties ------------------
191:
192:            /**
193:             * Get one of controls associated with the Animator.  Usually, these are displayed
194:             * in the Animator panel, but you could get a control and add it to another panel if you
195:             * want.  Even if you do this, the control will still be managed by the Animator (which
196:             * will respond to it and enable/disable it, for example).  You might also want to get
197:             * one of the Animator's buttons so that you can change its label.  The value
198:             * of the parameter should be one of the constants START_STOP_BUTTON, START_BUTTON, STOP_BUTTON,
199:             * PAUSE_BUTTON, NEXT_BUTTON, PREV_BUTTON, SPEED_CHOICE, LOOP_CHOICE.  If the parameter is
200:             * not one of these values, then null is returned.
201:             */
202:            public Component getControl(int controlCode) {
203:                switch (controlCode) {
204:                case START_STOP_BUTTON:
205:                    if (startStopButton == null) {
206:                        startStopButton = new Button(startButtonName);
207:                        startStopButton.setBackground(Color.lightGray);
208:                        startStopButton.addActionListener(this );
209:                    }
210:                    return startStopButton;
211:                case START_BUTTON:
212:                    if (startButton == null) {
213:                        startButton = new Button(startButtonName);
214:                        startButton.setBackground(Color.lightGray);
215:                        startButton.addActionListener(this );
216:                    }
217:                    return startButton;
218:                case STOP_BUTTON:
219:                    if (stopButton == null) {
220:                        stopButton = new Button(stopButtonName);
221:                        stopButton.setBackground(Color.lightGray);
222:                        stopButton.addActionListener(this );
223:                        stopButton.setEnabled(false);
224:                    }
225:                    return stopButton;
226:                case PAUSE_BUTTON:
227:                    if (pauseButton == null) {
228:                        pauseButton = new Button("Pause");
229:                        pauseButton.setBackground(Color.lightGray);
230:                        pauseButton.addActionListener(this );
231:                        pauseButton.setEnabled(false);
232:                    }
233:                    return pauseButton;
234:                case NEXT_BUTTON:
235:                    if (nextButton == null) {
236:                        nextButton = new Button("Next");
237:                        nextButton.setBackground(Color.lightGray);
238:                        nextButton.addActionListener(this );
239:                    }
240:                    return nextButton;
241:                case PREV_BUTTON:
242:                    if (prevButton == null) {
243:                        prevButton = new Button("Prev");
244:                        prevButton.setBackground(Color.lightGray);
245:                        prevButton.addActionListener(this );
246:                    }
247:                    return prevButton;
248:                case SPEED_CHOICE:
249:                    if (speedChoice == null) {
250:                        speedChoice = new Choice();
251:                        speedChoice.add("Fastest");
252:                        speedChoice.add("Fast");
253:                        speedChoice.add("Moderate");
254:                        speedChoice.add("Slow");
255:                        speedChoice.add("Slower");
256:                        speedChoice.select(2);
257:                        speedChoice.addItemListener(this );
258:                    }
259:                    return speedChoice;
260:                case LOOP_CHOICE:
261:                    if (loopChoice == null) {
262:                        loopChoice = new Choice();
263:                        loopChoice.add("Play Once");
264:                        loopChoice.add("Loop");
265:                        loopChoice.add("Back and Forth");
266:                        loopChoice.addItemListener(this );
267:                    }
268:                    return loopChoice;
269:                default:
270:                    return null;
271:                }
272:            }
273:
274:            /**
275:             * Add one of the possible control buttons or pop-up menus to the Animator. The possible values
276:             * of the parameter and their meanings are as follows:
277:             * <p>START_STOP_BUTTON: When clicked, animation starts and name of button changes; when clicked again, animation stops.
278:             * <p>START_BUTTON: When clicked, animation starts.
279:             * <p>STOP_BUTTON: When clicked, animaton stops.
280:             * <p>PAUSE_BUTTON: When clicked, animation is paused; this is different from stopping the animation since
281:             *   a paused animation can be resumed from the same point while a stopped animation can only be restarted
282:             *   from the beginning.
283:             * <p>NEXT_BUTTON: When clicked, the animation advances one frame; this is disabled when the animation is running.
284:             * <p>PREV_BUTTON: When clicked, the animation is moved back one frame;  this is disabled when the animation is running.
285:             * <p>SPEED_CHOICE: A pop-up menu whose value controls the speed at which the animation plays.
286:             * <P>LOOP_CHOICE: A pop-up menu that controls the style of animation, that is, what happens when the 
287:             *  animation reaches its final frame; values are Play Once, Loop, and Back and Forth.
288:             * <p>If the parameter is not one of these constants, then nothing is done.  Ordinarily, this
289:             * will be called during initialization.  (If you call it at some other time, you will have
290:             * to validate the panel yourself.)  The return value is the component that is added, or null
291:             * if the parameter value is not legal.
292:             */
293:            public Component addControl(int controlCode) {
294:                Component c = getControl(controlCode);
295:                if (c == null)
296:                    return null;
297:                else {
298:                    add(c);
299:                    return c;
300:                }
301:            }
302:
303:            /**
304:             * The name of the Start/Stop button is managed by the Animator, so changing it directly makes
305:             * no sense.  This method can be used to specify the label displayed by the Start/Stop button
306:             * when the animation is NOT running.  This name is also used for the Start button.  This method
307:             * should ordinarily be called during initialization.  In any case, it should not be called while
308:             * an animation is running, since it changes the name of the Start/Stop button to the specified value.
309:             */
310:            public void setStartButtonName(String name) {
311:                if (name != null) {
312:                    startButtonName = name;
313:                    if (startStopButton != null)
314:                        startStopButton.setLabel(name);
315:                    if (startButton != null)
316:                        startButton.setLabel(name);
317:                }
318:            }
319:
320:            /**
321:             * The name of the Start/Stop button is managed by the Animator, so changing it directly makes
322:             * no sense.  This method can be used to specify the label displayed by the Start/Stop button
323:             * when the animation IS running.  This name is also used for the Stop button.  This method
324:             * should ordinarily be called during initialization.  In any case, it should not be called while
325:             * an animation is running, since it does not change the name  of the Start/Stop button.
326:             */
327:            public void setStopButtonName(String name) {
328:                if (name != null) {
329:                    stopButtonName = name;
330:                    if (stopButton != null)
331:                        stopButton.setLabel(name);
332:                }
333:            }
334:
335:            /**
336:             * Get the constant, VERTICAL or HORIZONTAL, that was used to specify whether the components
337:             * in the animator are arranged veritcally or horizontally.
338:             */
339:            public int getOrientation() {
340:                return orientation;
341:            }
342:
343:            /**
344:             *  Set the orientation of the components in the Animator panel.  The parameter should be one
345:             *  of the constants HORIZONTAL or VERTICAL.  This just sets the layout for the panel to
346:             *  be a GridLayout with one row or one column and validates the panel.  You could also
347:             *  set the layout to be something else, such as a FlowLayout, using the setLayout() method.
348:             */
349:            public void setOrientation(int orientation) {
350:                if (orientation != this .orientation
351:                        && (orientation == HORIZONTAL || orientation == VERTICAL)) {
352:                    this .orientation = orientation;
353:                    if (orientation == VERTICAL)
354:                        setLayout(new GridLayout(0, 1));
355:                    else
356:                        setLayout(new GridLayout(1, 0));
357:                    validate();
358:                }
359:            }
360:
361:            /**
362:             * Get the Value object that specifies the final value of the Animator.  This object can be null.
363:             */
364:            public Value getMax() {
365:                return max;
366:            }
367:
368:            /**
369:             * Set the Value object that gives the final value of the Animator.  If both min and max are 
370:             * non-null, the value of the Animator ranges from min to max as the animation procedes.  (It is not required
371:             * that max be greater than min.  They should probably be calles startVal and endVal.)
372:             */
373:            public void setMax(Value max) {
374:                this .max = max;
375:                needsValueCheck = true;
376:            }
377:
378:            /**
379:             * A convenience method that simply calls setMax(new Constant(d)).
380:             */
381:            public void setMax(double d) {
382:                setMax(new Constant(d));
383:            }
384:
385:            /**
386:             * Get the Value object that specifies the starting value of the Animator.  This object can be null.
387:             */
388:            public Value getMin() {
389:                return min;
390:            }
391:
392:            /**
393:             * Set the Value object that gives the starting value of the Animator.  If both min and max are 
394:             * non-null, the value ranges from min to max as the animation procedes.  (It is not required
395:             * that max be greater than min.)
396:             */
397:            public void setMin(Value min) {
398:                this .min = min;
399:                needsValueCheck = true;
400:            }
401:
402:            /**
403:             * A convenience method that simply calls setMin(new Constant(d)).
404:             */
405:            public void setMin(double d) {
406:                setMin(new Constant(d));
407:            }
408:
409:            /**
410:             * Get the Value object that specifies the number of frames in the animation.  This can be null.
411:             */
412:            public Value getIntervals() {
413:                return intervals;
414:            }
415:
416:            /**
417:             * Set the Value object that specifies the number of frames in the animation.  If non-null, then
418:             * the value is rounded to the nearest integer and clamped to the range 1 to 100000.  If it is
419:             * null and min and max are non-null, then a default value of 100 is used.  If it is null and
420:             * min or max is null, then the number of frames is unlimited and the values taken on by the
421:             * animator are 0, 1, 2, 3, ..., that is, the value of the animator is the frame number.
422:             * If min or max is null and intervals is non-null, then the values taken on by the
423:             * animator are 0, 1, 2, ..., intervals.  Note that the number of frames is (intervals+1).
424:             */
425:            public void setIntervals(Value intervals) {
426:                this .intervals = intervals;
427:                needsValueCheck = true;
428:            }
429:
430:            /**
431:             * A convenience method that simply calls setIntervals(new Constant(d)).
432:             */
433:            public void setIntervals(int intervals) {
434:                setIntervals(new Constant(intervals));
435:            }
436:
437:            /**
438:             * Get the nominal number of milliseconds per frame.  The actual time between frames
439:             * can be longer because of the work that is done processing the frame or on other tasks.
440:             */
441:            public int getMillisPerFrame() {
442:                return millisPerFrame;
443:            }
444:
445:            /**
446:             * Set the nominal number of milliseconds per frame.  The actual time between frames
447:             * can be longer because of the work that is done processing the frame or on other tasks.
448:             * Values less than 5 are effectively equivalent to 5.  Realistic values are 25 or more,
449:             * but it depends on what system the program is running on and how complicated each frame is.
450:             */
451:            public void setMillisPerFrame(int millis) {
452:                millisPerFrame = millis;
453:            }
454:
455:            /**
456:             * Get the loop style, which determines what happens when the final frame of the animation is reached.
457:             */
458:            public int getLoopStyle() {
459:                return loopStyle;
460:            }
461:
462:            /**
463:             * Set the loop style, which determines what happens when the final frame of the animation is reached.
464:             * The parameter can be one of the constants: ONCE (animation stops when final frame is reached),
465:             * LOOP (animation cycles back to the first frame and continues from there); or BACK_AND_FORTH (animation reverses direction
466:             * and cycles back and forth).
467:             */
468:            public void setLoopStyle(int style) {
469:                if (style >= 0 && style <= 2 && style != loopStyle) {
470:                    loopStyle = style;
471:                    if (loopChoice != null)
472:                        loopChoice.select(style);
473:                    runningBackwards = false;
474:                }
475:            }
476:
477:            /**
478:             * Set the value of the animation.  Note that the value does not have to be one of
479:             * the values that would ordinarily occur in the animation.  Of course, if the animation
480:             * is running, then the new value won't be around for long since it will change as
481:             * soon as the next frame comes up.
482:             */
483:            synchronized public void setVal(double val) {
484:                if (needsValueCheck)
485:                    checkValue(); // make sure min,max,intervals are evaluated if necessary
486:                value = val;
487:                serialNumber++;
488:                needsValueCheck = false;
489:                // Try to make the frame number match the value as closely as possible
490:                if (!Double.isNaN(val)) {
491:                    if (min == null || max == null)
492:                        frame = (int) Math.round(val);
493:                    else if (!Double.isNaN(min_val) && !Double.isNaN(max_val)
494:                            && min_val != max_val)
495:                        frame = (int) Math.round((val - min_val)
496:                                / (max_val - min_val) * maxFrame);
497:                    if (frame < 0)
498:                        frame = 0;
499:                    else if (maxFrame > 0 && frame > maxFrame)
500:                        frame = maxFrame;
501:                }
502:            }
503:
504:            /**
505:             * Get the current value of the Animator.
506:             */
507:            public double getVal() {
508:                if (needsValueCheck)
509:                    checkValue();
510:                return value;
511:            }
512:
513:            /**
514:             * Get a variable whose value is always equal to the value of the animator.
515:             * The name of the variable will be k.
516:             */
517:            public Variable getValueAsVariable() {
518:                return getValueAsVariable("k");
519:            }
520:
521:            /**
522:             * Get a variable whose value is always equal to the value of the animator.
523:             * The name of the variable is specified by the parameter.
524:             */
525:            public Variable getValueAsVariable(String name) {
526:                return new Variable(name) {
527:                    public void setVal(double val) {
528:                        Animator.this .setVal(val);
529:                    }
530:
531:                    public double getVal() {
532:                        return Animator.this .getVal();
533:                    }
534:                };
535:            }
536:
537:            /**
538:             * Get the Controller that is notified (by calling its compute() method) whenever
539:             * the frame changes.  This can be null.
540:             */
541:            public Computable getOnChange() {
542:                return onChange;
543:            }
544:
545:            /**
546:             * Set the Controller that is notified (by calling its compute() method) whenever
547:             * the frame changes.  If null, no Controller is notified.  NOTE:  Animators are
548:             * different from InputObjects in that when onChange is null, the value of animator
549:             * and its associated Variable will change without checkInput() being called.
550:             * However, if the onChange is not null, then checkInput() must be called for
551:             * the value to change. (So the Animation to be added to the Controller by
552:             * calling the Controller's add() method.  Then, the Controller will call
553:             * the checkInput() method.)
554:             */
555:            public void setOnChange(Computable onChange) {
556:                this .onChange = onChange;
557:            }
558:
559:            /**
560:             * Method required by the InputObject interface.  It just calls setOnChange(c).
561:             * This is meant to be called by the gatherInputs() method in JCMPanel.
562:             */
563:            public void notifyControllerOnChange(Controller c) {
564:                setOnChange(c);
565:            }
566:
567:            /**
568:             *  Get the value of the undefinedWhenNotRunning property.
569:             */
570:            public boolean getUndefinedWhenNotRunning() {
571:                return undefinedWhenNotRunning;
572:            }
573:
574:            /**
575:             * Set the value of the undefinedWhenNotRunning property.  If this is true,
576:             * then the value of the Animator is Double.NaN except when the animation is
577:             * running (or paused), (or if it has been set by a call to the setVal() method).
578:             * The default value is false.
579:             */
580:            public void setUndefinedWhenNotRunning(
581:                    boolean undefinedWhenNotRunning) {
582:                this .undefinedWhenNotRunning = undefinedWhenNotRunning;
583:            }
584:
585:            //--------------- play control --------------------------------------
586:
587:            /**
588:             *  Start the animation from the first frame, or continue it if it was paused.
589:             *  This is called when the Start button or Start/Stop button is pressed, but
590:             *  it could also be called directly.
591:             */
592:            synchronized public void start() {
593:                if (runner != null && runner.isAlive() && status == STOP) {
594:                    // A previous run is stopping.  Give it a chance to stop.
595:                    try {
596:                        wait(1000);
597:                    } catch (InterruptedException e) {
598:                    }
599:                    if (runner != null && runner.isAlive()) {
600:                        runner.stop(); // bad form, but what choice do I have?
601:                        runner = null;
602:                    }
603:                }
604:                if (runner == null || !runner.isAlive()) {
605:                    runner = new Thread(this );
606:                    status = START;
607:                    runner.start();
608:                } else if (status != RUN) {
609:                    status = START;
610:                    notify();
611:                }
612:            }
613:
614:            /**
615:             *  Pause the animation, if it is running.
616:             *  This is called when the Pause button is pressed, but
617:             *  it could also be called directly.
618:             */
619:            synchronized public void pause() {
620:                if (status == RUN) {
621:                    status = PAUSE;
622:                    notify();
623:                }
624:            }
625:
626:            /**
627:             *  Advance the animation by one frame.  This will start the animation from the
628:             *  first frame if it is stopped.  This has no effect unless the animation is
629:             *  stopped or paused. This is called when the Next button  pressed, but
630:             *  it could also be called directly.
631:             */
632:            synchronized public void next() {
633:                if (runner == null || !runner.isAlive()) {
634:                    runner = new Thread(this );
635:                    status = NEXT;
636:                    runner.start();
637:                } else if (status == PAUSE) {
638:                    status = NEXT;
639:                    notify();
640:                }
641:            }
642:
643:            /**
644:             *  Advance the animation BACK one frame.  This will start the animation from the
645:             *  first frame if it is stopped.  This has no effect unless the animation is
646:             *  stopped or paused. This is called when the Prev button  pressed, but
647:             *  it could also be called directly.
648:             */
649:            synchronized public void prev() {
650:                if (runner == null || !runner.isAlive()) {
651:                    runner = new Thread(this );
652:                    status = PREV;
653:                    runner.start();
654:                } else if (status == PAUSE) {
655:                    status = PREV;
656:                    notify();
657:                }
658:            }
659:
660:            /**
661:             *  Stop the animation, if it is running or paused.  This is called when the Stop button 
662:             *  or the StartStop button is pressed, but it could also be called directly.
663:             *  NOTE: If the Animator is in an applet, then it is a good idea to call the stop()
664:             *  method of the Animator from the applet's destroy() method.
665:             */
666:            synchronized public void stop() {
667:                status = STOP;
668:                if (runner == null || !runner.isAlive())
669:                    return;
670:                notify();
671:            }
672:
673:            //-----------------Implementation details --------------------------
674:
675:            /**
676:             * Respond to button clicks.  This is not meant to be called directly.
677:             */
678:            synchronized public void actionPerformed(ActionEvent evt) {
679:                Object src = evt.getSource();
680:                if (src == null)
681:                    return;
682:                if (src == startStopButton) {
683:                    if (status == RUN)
684:                        stop();
685:                    else
686:                        start();
687:                } else if (src == startButton) {
688:                    start();
689:                } else if (src == stopButton) {
690:                    stop();
691:                } else if (src == nextButton) {
692:                    next();
693:                } else if (src == prevButton) {
694:                    prev();
695:                } else if (src == pauseButton) {
696:                    pause();
697:                }
698:            }
699:
700:            /**
701:             * Respond to clicks on pop-up menus.  This is not meant to be called directly.
702:             */
703:            synchronized public void itemStateChanged(ItemEvent evt) {
704:                if (evt.getSource() == loopChoice && loopChoice != null) {
705:                    setLoopStyle(loopChoice.getSelectedIndex());
706:                } else if (evt.getSource() == speedChoice
707:                        && speedChoice != null) {
708:                    switch (speedChoice.getSelectedIndex()) {
709:                    case 0:
710:                        millisPerFrame = 0;
711:                        break;
712:                    case 1:
713:                        millisPerFrame = 30;
714:                        break;
715:                    case 2:
716:                        millisPerFrame = 100;
717:                        break;
718:                    case 3:
719:                        millisPerFrame = 500;
720:                        break;
721:                    case 4:
722:                        millisPerFrame = 2000;
723:                        break;
724:                    }
725:                }
726:            }
727:
728:            /**
729:             * Part of the IputObject interface.  This is meant to be called by a Controller.
730:             */
731:            public void checkInput() {
732:                needsValueCheck = true;
733:            }
734:
735:            /**
736:             *  Part of the Tieable interface.  This is meant to be called by other Tieable objects
737:             *  as part of object synchronization.
738:             */
739:            public long getSerialNumber() {
740:                if (needsValueCheck)
741:                    checkValue();
742:                return serialNumber;
743:            }
744:
745:            /**
746:             *  Part of the Tieable interface.  This is meant to be called by Tie objects
747:             *  as part of object synchronization.
748:             */
749:            public void sync(Tie tie, Tieable newest) {
750:                if (newest != this ) {
751:                    if (!(newest instanceof  Value))
752:                        throw new IllegalArgumentException(
753:                                "Internal Error:  An Animator can only sync with Value objects.");
754:                    setVal(((Value) newest).getVal());
755:                    serialNumber = newest.getSerialNumber();
756:                }
757:            }
758:
759:            synchronized private void checkValue() { // Recompute the value, which might have changed.
760:                double newVal;
761:                if (min != null)
762:                    min_val = min.getVal();
763:                if (max != null)
764:                    max_val = max.getVal();
765:                if (intervals == null)
766:                    intervals_val = 0;
767:                else {
768:                    double d = intervals.getVal();
769:                    if (Double.isNaN(d) || d <= 0.5)
770:                        intervals_val = 0;
771:                    else if (d > 100000)
772:                        intervals_val = 100000;
773:                    else
774:                        intervals_val = (int) Math.round(d);
775:                }
776:                maxFrame = intervals_val;
777:                if (min == null || max == null) { // value is frame number
778:                    newVal = frame;
779:                } else if (Double.isNaN(min_val) || Double.isNaN(max_val)
780:                        || Double.isInfinite(min_val)
781:                        || Double.isInfinite(max_val)) {
782:                    newVal = Double.NaN;
783:                } else if (intervals_val > 0) {
784:                    newVal = min_val + (frame * (max_val - min_val))
785:                            / intervals_val;
786:                } else { // Assume 100 intervals if 
787:                    maxFrame = 100;
788:                    newVal = min_val + (frame * (max_val - min_val)) / 100;
789:                }
790:                if (undefinedWhenNotRunning && status == STOP)
791:                    newVal = Double.NaN;
792:                value = newVal;
793:                needsValueCheck = false;
794:            }
795:
796:            private void doControlStatus(int status) {
797:                // Enable/disable buttons according to Thread status.
798:                // status should be START or STOP or PAUSE
799:                if (startStopButton != null)
800:                    startStopButton.setLabel((status == START) ? stopButtonName
801:                            : startButtonName);
802:                if (startButton != null)
803:                    startButton.setEnabled(status != START);
804:                if (stopButton != null)
805:                    stopButton.setEnabled(status != STOP);
806:                if (nextButton != null)
807:                    nextButton.setEnabled(status != START);
808:                if (prevButton != null)
809:                    prevButton.setEnabled(status != START);
810:                if (pauseButton != null)
811:                    pauseButton.setEnabled(status == START);
812:            }
813:
814:            private void doAdvanceFrame(int amt) {
815:                // Move on to next or previous frame.
816:                // amt is +1 or -1
817:                serialNumber++;
818:                if (loopStyle == BACK_AND_FORTH && runningBackwards)
819:                    frame -= amt;
820:                else
821:                    frame += amt;
822:                if (frame < 0) {
823:                    if (loopStyle == LOOP)
824:                        frame = maxFrame; // might be 0, which is OK I guess
825:                    else if (loopStyle == BACK_AND_FORTH) {
826:                        frame = 1;
827:                        if (amt == 1)
828:                            runningBackwards = false;
829:                        else
830:                            runningBackwards = true;
831:                    } else
832:                        frame = 0;
833:                } else if (maxFrame > 0 && frame > maxFrame) {
834:                    if (loopStyle == LOOP)
835:                        frame = 1; // Don't use 0, because usually frames 0 and maxFrame will be the same
836:                    else if (loopStyle == ONCE) {
837:                        frame = maxFrame;
838:                        status = STOP;
839:                        return; // exit at once
840:                    } else { // loopStyle == BACK_AND_FORTH
841:                        frame = maxFrame - 1;
842:                        if (amt == 1)
843:                            runningBackwards = true;
844:                        else
845:                            runningBackwards = false;
846:                    }
847:                }
848:                if (onChange != null)
849:                    onChange.compute();
850:                else
851:                    needsValueCheck = true;
852:            }
853:
854:            /**
855:             * The method that is run by the animation thread.  This is not meant to be called directly.
856:             */
857:            public void run() {
858:                int localstatus = status;
859:                long lastFrameTime = 0;
860:                runningBackwards = false;
861:                if (frame != 0 || undefinedWhenNotRunning) {
862:                    frame = 0;
863:                    serialNumber++;
864:                    lastFrameTime = System.currentTimeMillis();
865:                    if (onChange != null)
866:                        onChange.compute();
867:                    else
868:                        needsValueCheck = true;
869:                    if (status == PREV || status == NEXT)
870:                        status = PAUSE;
871:                }
872:                try {
873:                    while (true) {
874:                        synchronized (this ) {
875:                            while (status == PAUSE) {
876:                                if (localstatus != PAUSE) {
877:                                    doControlStatus(PAUSE);
878:                                    localstatus = PAUSE;
879:                                }
880:                                try {
881:                                    wait();
882:                                } catch (InterruptedException e) {
883:                                }
884:                            }
885:                            if (status == STOP)
886:                                break;
887:                            localstatus = status;
888:                            if (needsValueCheck)
889:                                checkValue(); // make sure maxFrame is correct
890:                        }
891:                        if (localstatus == START) {
892:                            doControlStatus(START);
893:                            localstatus = status = RUN;
894:                        }
895:                        if (localstatus == RUN) {
896:                            long sinceLastFrame = System.currentTimeMillis()
897:                                    - lastFrameTime;
898:                            long waitTime = millisPerFrame - sinceLastFrame;
899:                            if (waitTime <= 5)
900:                                waitTime = 5;
901:                            try {
902:                                synchronized (this ) {
903:                                    wait(waitTime);
904:                                }
905:                            } catch (InterruptedException e) {
906:                            }
907:                            lastFrameTime = System.currentTimeMillis();
908:                            if (status == RUN)
909:                                doAdvanceFrame(1);
910:                        } else if (localstatus == NEXT) {
911:                            doAdvanceFrame(1);
912:                            if (status != STOP) // status can become stop in doAdvanceFrame
913:                                status = localstatus = PAUSE;
914:                        } else if (localstatus == PREV) {
915:                            doAdvanceFrame(-1);
916:                            if (status != STOP) // status can become stop in doAdvanceFrame (but shouldn't happen here)
917:                                status = localstatus = PAUSE;
918:                        }
919:                    }
920:                } finally {
921:                    synchronized (this ) {
922:                        status = STOP;
923:                        doControlStatus(STOP);
924:                        frame = 0;
925:                        serialNumber++;
926:                        if (onChange != null)
927:                            onChange.compute();
928:                        else
929:                            needsValueCheck = true;
930:                        runner = null;
931:                        notify(); // in case start() method is waiting for thread to end
932:                    }
933:                }
934:            }
935:
936:        } // class Animator
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.