/* * Bibliothek - DockingFrames * Library built on Java/Swing, allows the user to "drag and drop" * panels containing any Swing-Component the developer likes to add. * * Copyright (C) 2012 Benjamin Sigg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Benjamin Sigg * benjamin_sigg@gmx.ch * CH - Switzerland */ package bibliothek.gui.dock.extension.css.transition; import java.util.HashMap; import java.util.Map; import bibliothek.gui.dock.extension.css.CssProperty; import bibliothek.gui.dock.extension.css.CssPropertyKey; import bibliothek.gui.dock.extension.css.CssRuleContent; import bibliothek.gui.dock.extension.css.CssRuleContentListener; import bibliothek.gui.dock.extension.css.CssScheme; import bibliothek.gui.dock.extension.css.CssType; import bibliothek.gui.dock.extension.css.property.AbstractCssPropertyContainer; import bibliothek.gui.dock.extension.css.transition.scheduler.CssSchedulable; import bibliothek.gui.dock.extension.css.transition.scheduler.CssScheduler; import bibliothek.util.Filter; /** * This transition offers methods that can help to blend one type of item slowly into another type of item. * The {@link AbstractCssTransition} can observe one or many properties of type <code>T</code>. * If these properties have any sub-properties, then sub-s can be used to modify them as well. * @author Benjamin Sigg * @param <T> the type of item this handles */ public abstract class AbstractCssTransition<T> extends AbstractCssPropertyContainer implements CssTransition<T>{ private CssTransitionCallback callback; private CssRuleContent source; private CssRuleContent target; private Filter<CssPropertyKey> propertyFilter; /** the list of properties which either are animated or required for the */ private Map<CssPropertyKey, AnimatedProperty<?>> properties = new HashMap<CssPropertyKey, AnimatedProperty<?>>(); private CssType<T> type; private CssRuleContentListener listener = new CssRuleContentListener(){ @Override public void propertiesChanged( CssRuleContent source ){ for( AnimatedProperty<?> property : properties.values() ){ property.updateValues(); } } @Override public void propertyChanged( CssRuleContent source, CssPropertyKey key ){ AnimatedProperty<?> animatedProperty = properties.get( key ); if( animatedProperty != null ){ animatedProperty.updateValues(); } } }; @Override public void setType( CssType<T> type ){ if( type == null ){ throw new IllegalArgumentException( "type must not be null" ); } this.type = type; } @Override public boolean isInput( CssPropertyKey key ){ for( AnimatedProperty<?> value : properties.values() ){ if( value.dependencies.containsKey( key )){ return true; } } return false; } @Override public String[] getPropertyKeys(){ return new String[]{}; } @Override public CssProperty<?> getProperty( String key ){ return null; } @Override public void setPropertyFilter( Filter<CssPropertyKey> propertyFilter ){ this.propertyFilter = propertyFilter; } @Override public void init( CssRuleContent current, CssTransitionCallback callback ){ this.callback = callback; this.source = current; source.addRuleContentListener( listener ); CssPropertyKey[] keys = callback.getPropertiesOfType( type ); for( CssPropertyKey key : keys ){ if( propertyFilter == null || propertyFilter.includes( key )){ AnimatedProperty<T> property = new AnimatedProperty<T>( key, createProperty( type, key ), type ); properties.put( key, property ); property.updateValues(); } } } /** * Sets the progress of the animation and schedules a new call to {@link #step(int)}. * @param progress the current progress, between <code>0</code> and <code>1</code> */ protected void updateProgress( double progress ){ for( AnimatedProperty<?> next : properties.values()){ next.updateProgress( progress ); } callback.step(); } /** * Informs all properties that the animation is over. */ protected void endAnimation(){ for( AnimatedProperty<?> next : properties.values()){ next.end(); } } @Override public void transition( CssRuleContent destination ){ target = destination; target.addRuleContentListener( listener ); for( AnimatedProperty<?> property : properties.values() ){ property.updateValues(); } callback.step(); } /** * Creates a new animated property. * @param type the type of the property * @param key the name of the property * @return the , not <code>null</code> */ protected abstract TransitionalCssProperty<T> createProperty( CssType<T> type, CssPropertyKey key ); /** * A wrapper around an {@link TransitionalCssProperty}, knows which other properties are required * for the {@link TransitionalCssProperty} (the dependencies), and automatically updates the * list of dependencies by creating sub-{@link AnimatedProperty}s. * @author Benjamin Sigg * @param <S> the kind of object handled by the wrapped {@link TransitionalCssProperty} */ private class AnimatedProperty<S> implements TransitionalCssPropertyCallback<S>, CssSchedulable{ private TransitionalCssProperty<S> property; private CssPropertyKey key; private CssType<S> type; private Map<CssPropertyKey, CssProperty<?>> dependencies = new HashMap<CssPropertyKey,CssProperty<?>>(); public AnimatedProperty( CssPropertyKey key, TransitionalCssProperty<S> property, CssType<S> type ){ this.key = key; this.property = property; this.type = type; property.setCallback( this ); } @Override public void addSourceDependency( String key, CssProperty<?> property ){ callback.addSourceDependency( key, property ); dependencies.put( this.key.append( key ), property ); } @Override public void removeSourceDependency( String key ){ dependencies.remove( this.key.append( key ) ); callback.removeSourceDependency( key ); } @Override public void addTargetDependency( String key, CssProperty<?> property ){ callback.addTargetDependency( key, property ); } @Override public void removeTargetDependency( String key ){ callback.removeTargetDependency( key ); } @Override public CssScheme getScheme(){ return callback.getScheme(); } public void end(){ set( target.getProperty( type, key )); } public void updateValues(){ property.setSource( source.getProperty( type, key ) ); if( target != null ){ property.setTarget( target.getProperty( type, key ) ); } } public void updateProgress( double progress ){ property.setTransition( progress ); } @Override public void set( S value ){ callback.setProperty( type, key, value ); } @Override public void step( CssScheduler scheduler, int delay ){ property.step( delay ); } @Override public void step(){ getScheme().getScheduler().step( this ); } @Override public void step( int delay ){ getScheme().getScheduler().step( this, delay ); } } }