/*
* 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.scheme;
import bibliothek.gui.dock.extension.css.CssItem;
import bibliothek.gui.dock.extension.css.CssProperty;
import bibliothek.gui.dock.extension.css.CssPropertyContainer;
import bibliothek.gui.dock.extension.css.CssPropertyKey;
import bibliothek.gui.dock.extension.css.CssRule;
import bibliothek.gui.dock.extension.css.CssRuleContent;
import bibliothek.gui.dock.extension.css.CssScheme;
import bibliothek.gui.dock.extension.css.transition.TransitionalCssRuleContent;
/**
* A {@link MatchedCssRule} is responsible for reading the properties of one {@link CssRule}
* and forward them to a {@link CssItem}. Due to transitions several {@link CssRule}s may be active
* at the same time, in this case this {@link MatchedCssRule} is marked as {@link #outdate()}. Only
* {@link CssProperty}s which are considered {@link #isInput(CssPropertyKey) input properties} remain
* active. Input properties usually are attached to a {@link CssPropertyContainer} which got involved
* in an transition, yet itself is not a {@link CssProperty} nor a {@link CssItem}.
* @author Benjamin Sigg
*/
public class MatchedCssRule {
private static enum Mode{
NEW, HEAD, OUTDATED, DESTROYED
}
/** the values of all the properties */
private TransitionalCssRuleContent rule;
/** the behavior of this {@link MatchedCssRule} */
private Mode mode = Mode.NEW;
private Forwarder forwarder;
/**
* Creates a new match
* @param scheme the scheme in whose realm this rule is used
* @param item the item whose properties are set
* @param rule the rule from which to read properties, can be <code>null</code>
*/
public MatchedCssRule( CssScheme scheme, CssItem item, TransitionalCssRuleContent rule ){
this.rule = rule;
forwarder = new Forwarder( rule, item, scheme );
}
/**
* Install <code>this</code>, starts monitoring all {@link CssProperty}s of the {@link CssItem}.
* @param firstRule whether this is the first rule for the {@link CssItem}, the first rule also
* call {@link CssProperty#setScheme(CssScheme, String)}
*/
public void install( boolean firstRule ){
if( mode != Mode.NEW ){
throw new IllegalStateException( "already installed" );
}
mode = Mode.HEAD;
forwarder.install( firstRule );
}
private boolean isInput( CssPropertyKey key ){
if( rule == null ){
return false;
}
return rule.isInput( key );
}
/**
* Informs this {@link MatchedCssRule} that it is no longer working with the most recent
* {@link CssRule}. The current {@link CssProperty}s will be copied and kept alive until
* {@link #destroy()} is called.
*/
public void outdate(){
if( mode != Mode.DESTROYED ){
if( mode == Mode.HEAD ){
forwarder.outdate();
}
mode = Mode.OUTDATED;
}
}
/**
* Informs this {@link MatchedCssRule} that it is no longer in use, all resources are released.
*/
public void destroy(){
if( mode != Mode.DESTROYED ){
outdate();
mode = Mode.DESTROYED;
forwarder.destroy();
}
}
private class Forwarder extends PropertyForwarder{
public Forwarder( CssRuleContent source, CssPropertyContainer target, CssScheme scheme ){
super( source, target, scheme );
}
@Override
protected <T> void addProperty( CssPropertyKey key, CssProperty<T> property, boolean firstRule ){
if( mode == Mode.OUTDATED && !isInput(key) ){
throw new IllegalStateException( "attempt to register a static property after rule has been outdated" );
}
super.addProperty( key, property, firstRule );
}
public void outdate(){
// remove all static properties, keep dynamic properties until destruction
ignoreTarget();
CssPropertyKey[] keys = getKeys();
for( CssPropertyKey key : keys ){
CssProperty<?> property = getProperty( key );
if( !isInput(key) ){
removeProperty( key, property, false );
}
}
}
}
}