/* * 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.ArrayList; import java.util.List; import bibliothek.gui.dock.extension.css.CssItem; import bibliothek.gui.dock.extension.css.CssPropertyKey; import bibliothek.gui.dock.extension.css.CssRuleContent; import bibliothek.gui.dock.extension.css.CssScheme; /** * Default implementation of {@link TransitionalCssRuleChain}, executes transitions in parallel and does not allow * transitions to influence each other. * @author Benjamin Sigg */ public class DefaultAnimatedCssRuleChain implements TransitionalCssRuleChain{ private CssScheme scheme; private CssItem item; /** the very first rule of this chain, may not be <code>null</code> */ private Link head; /** the most recent rule of this chain, may not be <code>null</code> */ private Link tail; /** * Creates the new chain. * @param scheme the scheme in whose realm this chain is used * @param item the item which is animated by this chain * @param scheduler responsible for executing transitions asynchronously */ public DefaultAnimatedCssRuleChain( CssScheme scheme, CssItem item ){ this.scheme = scheme; this.item = item; head = new Link( null ); tail = head; } @Override public TransitionalCssRuleContent animate( CssPropertyKey transitionKey, CssTransition<?> transition ){ TransitionalCssRuleContent rule = tail.getRule(); rule.animate( transitionKey, transition ); return rule; } @Override public TransitionalCssRuleContent transition( CssRuleContent next ){ TransitionalCssRuleContent oldRule = tail.getRule(); Link link = new Link( next ); tail.setNext( link ); link.setPrevious( tail ); tail = link; oldRule.transition( next ); return link.getRule(); } @Override public CssItem getItem(){ return item; } @Override public CssScheme getScheme(){ return scheme; } @Override public void destroy(){ Link link = head; while( link != null ){ link.destroy(); link = link.getNext(); } } /** * Creates a new {@link TransitionalCssRuleContent} which takes its default properties from <code>root</code>. * @param root the root rule, can be <code>null</code> * @return the new animated rule */ protected TransitionalCssRuleContent createRule( CssRuleContent root ){ return new DefaultTransitionalCssRule( root ); } @Override public String toString(){ StringBuilder builder = new StringBuilder(); builder.append( getClass().getSimpleName() ).append( "[item=" ).append( item ).append( ", chain={" ); Link link = head; while( link != null ){ builder.append( "\n " ).append( link ); link = link.next; } builder.append( "\n}]" ); return builder.toString(); } private class Link implements RuleChainLink{ private List<RuleChainLinkListener> listeners = new ArrayList<RuleChainLinkListener>( 2 ); private TransitionalCssRuleContent rule; private Link previous; private Link next; public Link( CssRuleContent root ){ rule = createRule( root ); rule.inserted( this ); } @Override public String toString(){ return getClass().getSimpleName() + "[rule=" + rule + "]"; } @Override public TransitionalCssRuleContent getRule(){ return rule; } @Override public Link getPrevious(){ return previous; } public void setPrevious( Link previous ){ Link oldPrevious = this.previous; this.previous = previous; for( RuleChainLinkListener listener : listeners() ){ listener.previousChanged( this, oldPrevious, this.previous ); } } @Override public Link getNext(){ return next; } public void setNext( Link next ){ Link oldNext = this.next; this.next = next; for( RuleChainLinkListener listener : listeners() ){ listener.nextChanged( this, oldNext, this.next ); } } @Override public TransitionalCssRuleChain getChain(){ return DefaultAnimatedCssRuleChain.this; } @Override public void remove(){ if( head == this && tail == this ){ // this should never happen: remove is only to be called after a transition, and // if there is a transition there are at least two links in the chain. throw new IllegalStateException( "the only link in the chain cannot remove itself" ); } destroy(); } /** * Removes this link from the chain without any further validity checks. */ public void destroy(){ if( next != null ){ next.setPrevious( previous ); } if( previous != null ){ previous.setNext( next ); } if( tail == this ){ tail = previous; } if( head == this ){ head = next; } setNext( null ); setPrevious( null ); for( RuleChainLinkListener listener : listeners() ){ listener.removed( this ); } } @Override public void addListener( RuleChainLinkListener listener ){ if( listener == null ){ throw new IllegalArgumentException( "listener must not be null" ); } listeners.add( listener ); } @Override public void removeListener( RuleChainLinkListener listener ){ listeners.remove( listener ); } private RuleChainLinkListener[] listeners(){ return listeners.toArray( new RuleChainLinkListener[ listeners.size() ] ); } } }