package de.unisiegen.gtitool.core.entities; import javax.swing.event.EventListenerList; import de.unisiegen.gtitool.core.entities.listener.PrettyStringChangedListener; import de.unisiegen.gtitool.core.i18n.Messages; import de.unisiegen.gtitool.core.parser.ParserOffset; import de.unisiegen.gtitool.core.parser.style.PrettyPrintable; import de.unisiegen.gtitool.core.parser.style.PrettyString; import de.unisiegen.gtitool.core.parser.style.PrettyToken; import de.unisiegen.gtitool.core.parser.style.Style; import de.unisiegen.gtitool.core.parser.style.PrettyString.PrettyStringMode; import de.unisiegen.gtitool.core.storage.Attribute; import de.unisiegen.gtitool.core.storage.Element; import de.unisiegen.gtitool.core.storage.Storable; import de.unisiegen.gtitool.core.storage.exceptions.StoreException; /** * The {@link DefaultSymbol} entity. * * @author Christian Fehler * @version $Id$ */ public final class DefaultSymbol implements Symbol { /** * the serial verion uid. */ private static final long serialVersionUID = 121593210993378021L; /** * The name of this state. */ private String name = null; /** * This {@link Symbol} is a error {@link Symbol}. */ private boolean error = false; /** * This {@link Symbol} is a active {@link Symbol}. */ private boolean active = false; /** * The offset of this {@link DefaultSymbol} in the source code. * * @see #getParserOffset() * @see #setParserOffset(ParserOffset) */ private ParserOffset parserOffset = NO_PARSER_OFFSET; /** * Flag that indicates if this {@link Symbol} is a epsilon {@link Symbol}. */ private boolean epsilon; /** * The cached {@link PrettyString}. */ private PrettyString cachedPrettyString = null; /** * The {@link EventListenerList}. */ private EventListenerList listenerList = new EventListenerList (); /** * Allocates a new {@link DefaultSymbol}. */ public DefaultSymbol () { this.epsilon = true; } /** * Allocates a new {@link DefaultSymbol}. * * @param element The {@link Element}. * @throws StoreException If the {@link Element} can not be parsed. */ public DefaultSymbol ( Element element ) throws StoreException { // Check if the element is correct if ( !element.getName ().equals ( "Symbol" ) ) //$NON-NLS-1$ { throw new IllegalArgumentException ( "element " + Messages.QUOTE + element.getName () //$NON-NLS-1$ + Messages.QUOTE + " is not a symbol" ); //$NON-NLS-1$ } // Attribute boolean foundName = false; boolean foundEpsilon = false; for ( Attribute current : element.getAttribute () ) { if ( current.getName ().equals ( "name" ) ) //$NON-NLS-1$ { if ( !this.epsilon ) { setName ( current.getValue () ); } foundName = true; } else if ( current.getName ().equals ( "epsilon" ) ) //$NON-NLS-1$ { this.epsilon = current.getValueBoolean (); foundEpsilon = true; } else { throw new StoreException ( Messages .getString ( "StoreException.AdditionalAttribute" ) ); //$NON-NLS-1$ } } // Not all attribute values found if ( !foundName || !foundEpsilon ) { throw new StoreException ( Messages .getString ( "StoreException.MissingAttribute" ) ); //$NON-NLS-1$ } // Element if ( element.getElement ().size () > 0 ) { throw new StoreException ( Messages .getString ( "StoreException.AdditionalElement" ) ); //$NON-NLS-1$ } } /** * Allocates a new {@link DefaultSymbol}. * * @param name The name of this {@link DefaultSymbol}. */ public DefaultSymbol ( String name ) { setName ( name ); } /** * {@inheritDoc} * * @see PrettyPrintable#addPrettyStringChangedListener(PrettyStringChangedListener) */ public final void addPrettyStringChangedListener ( PrettyStringChangedListener listener ) { this.listenerList.add ( PrettyStringChangedListener.class, listener ); } /** * {@inheritDoc} * * @see Comparable#compareTo(Object) */ public final int compareTo ( Symbol other ) { if ( !this.epsilon && !other.isEpsilon () ) { if ( this.name.length () > other.getName ().length () ) { return -1; } if ( this.name.length () < other.getName ().length () ) { return 1; } return this.name.compareTo ( other.getName () ); } if ( !this.epsilon && other.isEpsilon () ) { return 1; } if ( this.epsilon && !other.isEpsilon () ) { return -1; } return 0; } /** * {@inheritDoc} * * @see Object#equals(Object) */ @Override public final boolean equals ( Object other ) { if ( other instanceof DefaultSymbol ) { DefaultSymbol symbol = ( DefaultSymbol ) other; if ( this.epsilon != symbol.epsilon ) { return false; } if ( this.epsilon && symbol.epsilon ) { return true; } return this.name.equals ( symbol.name ); } return false; } /** * Let the listeners know that the {@link PrettyString} has changed. */ private final void firePrettyStringChanged () { this.cachedPrettyString = null; PrettyStringChangedListener [] listeners = this.listenerList .getListeners ( PrettyStringChangedListener.class ); for ( PrettyStringChangedListener current : listeners ) { current.prettyStringChanged (); } } /** * {@inheritDoc} * * @see Storable#getElement() */ public final Element getElement () { Element newElement = new Element ( "Symbol" ); //$NON-NLS-1$ if ( this.epsilon ) { newElement.addAttribute ( new Attribute ( "name", "\"epsilon\"" ) ); //$NON-NLS-1$ //$NON-NLS-2$ newElement.addAttribute ( new Attribute ( "epsilon", true ) ); //$NON-NLS-1$ } else { newElement.addAttribute ( new Attribute ( "name", this.name ) ); //$NON-NLS-1$ newElement.addAttribute ( new Attribute ( "epsilon", false ) ); //$NON-NLS-1$ } return newElement; } /** * {@inheritDoc} * * @see Symbol#getName() */ public final String getName () { return this.name; } /** * {@inheritDoc} * * @see Entity#getParserOffset() */ public final ParserOffset getParserOffset () { return this.parserOffset; } /** * {@inheritDoc} * * @see Entity#hashCode() */ @Override public final int hashCode () { if ( this.epsilon ) { return "epsilon".hashCode (); //$NON-NLS-1$ } return this.name.hashCode (); } /** * {@inheritDoc} * * @see Symbol#isActive() */ public final boolean isActive () { return this.active; } /** * {@inheritDoc} * * @see Symbol#isEpsilon() */ public final boolean isEpsilon () { return this.epsilon; } /** * {@inheritDoc} * * @see Symbol#isError() */ public final boolean isError () { return this.error; } /** * {@inheritDoc} * * @see PrettyPrintable#removePrettyStringChangedListener(PrettyStringChangedListener) */ public final void removePrettyStringChangedListener ( PrettyStringChangedListener listener ) { this.listenerList.remove ( PrettyStringChangedListener.class, listener ); } /** * {@inheritDoc} * * @see Symbol#setActive(boolean) */ public final void setActive ( boolean active ) { if ( this.active != active ) { this.active = active; firePrettyStringChanged (); } } /** * {@inheritDoc} * * @see Symbol#setError(boolean) */ public final void setError ( boolean error ) { if ( this.error != error ) { this.error = error; firePrettyStringChanged (); } } /** * Sets the name of this symbol. * * @param name The name to set. */ private final void setName ( String name ) { if ( this.epsilon ) { throw new RuntimeException ( "this symbol is a epsilon symbol without a name" ); //$NON-NLS-1$ } if ( name == null ) { throw new NullPointerException ( "name is null" ); //$NON-NLS-1$ } if ( ( this.name == null ) || !this.name.equals ( name ) ) { this.name = name; firePrettyStringChanged (); } } /** * {@inheritDoc} * * @see Entity#setParserOffset(ParserOffset) */ public final void setParserOffset ( ParserOffset parserOffset ) { this.parserOffset = parserOffset; } /** * {@inheritDoc} * * @see PrettyPrintable#toPrettyString() */ public final PrettyString toPrettyString () { if ( ( this.cachedPrettyString == null ) || PrettyString.MODE.equals ( PrettyStringMode.CACHING_OFF ) ) { this.cachedPrettyString = new PrettyString (); if ( this.epsilon ) { if ( this.error ) { this.cachedPrettyString.add ( new PrettyToken ( "\u03B5", //$NON-NLS-1$ Style.SYMBOL_ERROR ) ); } else if ( this.active ) { this.cachedPrettyString.add ( new PrettyToken ( "\u03B5", //$NON-NLS-1$ Style.SYMBOL_ACTIVE ) ); } else { this.cachedPrettyString.add ( new PrettyToken ( "\u03B5", Style.SYMBOL ) ); //$NON-NLS-1$ } } else { if ( this.error ) { this.cachedPrettyString.add ( new PrettyToken ( this.name, Style.SYMBOL_ERROR ) ); } else if ( this.active ) { this.cachedPrettyString.add ( new PrettyToken ( this.name, Style.SYMBOL_ACTIVE ) ); } else { this.cachedPrettyString.add ( new PrettyToken ( this.name, Style.SYMBOL ) ); } } } return this.cachedPrettyString; } /** * {@inheritDoc} * * @see Entity#toString() */ @Override public final String toString () { if ( this.epsilon ) { return "\u03B5"; //$NON-NLS-1$ } return this.name; } }