Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.animation; 027 028import javafx.collections.ListChangeListener.Change; 029import javafx.collections.ObservableList; 030import javafx.util.Duration; 031 032import com.sun.javafx.collections.TrackableObservableList; 033import com.sun.scenario.animation.AbstractMasterTimer; 034import com.sun.scenario.animation.shared.TimelineClipCore; 035 036/** 037 * A {@code Timeline} can be used to define a free from animation of any 038 * {@link javafx.beans.value.WritableValue}, e.g. all 039 * {@link javafx.beans.property.Property JavaFX Properties}. 040 * <p> 041 * A {@code Timeline}, defined by one or more {@link KeyFrame}s, processes 042 * individual {@code KeyFrame} sequentially, in the order specified by 043 * {@code KeyFrame.time}. The animated properties, defined as key values in 044 * {@code KeyFrame.values}, are interpolated 045 * to/from the targeted key values at the specified time of the {@code KeyFrame} 046 * to {@code Timeline}'s initial position, depends on {@code Timeline}'s 047 * direction. 048 * <p> 049 * {@code Timeline} processes individual {@code KeyFrame} at or after specified 050 * time interval elapsed, it does not guarantee the timing when {@code KeyFrame} 051 * is processed. 052 * <p> 053 * The {@link #cycleDurationProperty()} will be set to the largest time value 054 * of Timeline's keyFrames. 055 * <p> 056 * If a {@code KeyFrame} is not provided for the {@code time==0s} instant, one 057 * will be synthesized using the target values that are current at the time 058 * {@link #play()} or {@link #playFromStart()} is called. 059 * <p> 060 * It is not possible to change the {@code keyFrames} of a running {@code Timeline}. 061 * If the value of {@code keyFrames} is changed for a running {@code Timeline}, it 062 * has to be stopped and started again to pick up the new value. 063 * 064 * @see Animation 065 * @see KeyFrame 066 * @see KeyValue 067 * 068 */ 069public final class Timeline extends Animation { 070 /* Package-private for testing purposes */ 071 final TimelineClipCore clipCore; 072 073 /** 074 * Returns the {@link KeyFrame KeyFrames} of this {@code Timeline}. 075 */ 076 public final ObservableList<KeyFrame> getKeyFrames() { 077 return keyFrames; 078 } 079 private final ObservableList<KeyFrame> keyFrames = new TrackableObservableList<KeyFrame>() { 080 @Override 081 protected void onChanged(Change<KeyFrame> c) { 082 while (c.next()) { 083 if (!c.wasPermutated()) { 084 for (final KeyFrame keyFrame : c.getRemoved()) { 085 final String cuePoint = keyFrame.getName(); 086 if (cuePoint != null) { 087 getCuePoints().remove(cuePoint); 088 } 089 } 090 for (final KeyFrame keyFrame : c.getAddedSubList()) { 091 final String cuePoint = keyFrame.getName(); 092 if (cuePoint != null) { 093 getCuePoints().put(cuePoint, keyFrame.getTime()); 094 } 095 } 096 final Duration duration = clipCore.setKeyFrames(getKeyFrames()); 097 setCycleDuration(duration); 098 } 099 } 100 } 101 }; 102 103 /** 104 * The constructor of {@code Timeline}. 105 * 106 * This constructor allows to define a {@link Animation#targetFramerate}. 107 * 108 * @param targetFramerate 109 * The custom target frame rate for this {@code Timeline} 110 * @param keyFrames 111 * The keyframes of this {@code Timeline} 112 */ 113 public Timeline(double targetFramerate, KeyFrame... keyFrames) { 114 super(targetFramerate); 115 clipCore = new TimelineClipCore(this); 116 getKeyFrames().setAll(keyFrames); 117 } 118 119 /** 120 * The constructor of {@code Timeline}. 121 * 122 * @param keyFrames 123 * The keyframes of this {@code Timeline} 124 */ 125 public Timeline(KeyFrame... keyFrames) { 126 super(); 127 clipCore = new TimelineClipCore(this); 128 getKeyFrames().setAll(keyFrames); 129 } 130 131 /** 132 * The constructor of {@code Timeline}. 133 * 134 * This constructor allows to define a {@link Animation#targetFramerate}. 135 * 136 * @param targetFramerate 137 * The custom target frame rate for this {@code Timeline} 138 */ 139 public Timeline(double targetFramerate) { 140 super(targetFramerate); 141 clipCore = new TimelineClipCore(this); 142 } 143 144 /** 145 * The constructor of {@code Timeline}. 146 */ 147 public Timeline() { 148 super(); 149 clipCore = new TimelineClipCore(this); 150 } 151 152 // This constructor is only for testing purposes 153 Timeline(final AbstractMasterTimer timer) { 154 super(timer); 155 clipCore = new TimelineClipCore(this); 156 } 157 158 @Override 159 void impl_playTo(long currentTicks, long cycleTicks) { 160 clipCore.playTo(currentTicks); 161 } 162 163 @Override 164 void impl_jumpTo(long currentTicks, long cycleTicks, boolean forceJump) { 165 impl_sync(false); 166 impl_setCurrentTicks(currentTicks); 167 clipCore.jumpTo(currentTicks, forceJump); 168 } 169 170 @Override 171 void impl_setCurrentRate(double currentRate) { 172 super.impl_setCurrentRate(currentRate); 173 clipCore.notifyCurrentRateChanged(); 174 } 175 176 @Override 177 void impl_start(boolean forceSync) { 178 super.impl_start(forceSync); 179 clipCore.start(forceSync); 180 } 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override 186 public void stop() { 187 if (parent != null) { 188 throw new IllegalStateException("Cannot stop when embedded in another animation"); 189 } 190 if (getStatus() == Status.RUNNING) { 191 clipCore.abort(); 192 } 193 super.stop(); 194 } 195}