package de.unisiegen.tpml.graphics.outline.node ;
import java.awt.Color ;
import javax.swing.tree.DefaultMutableTreeNode ;
import de.unisiegen.tpml.core.expressions.Expression ;
import de.unisiegen.tpml.core.expressions.Identifier ;
import de.unisiegen.tpml.core.interfaces.ExpressionOrType ;
import de.unisiegen.tpml.core.prettyprinter.PrettyAnnotation ;
import de.unisiegen.tpml.core.prettyprinter.PrettyCharIterator ;
import de.unisiegen.tpml.core.prettyprinter.PrettyStyle ;
import de.unisiegen.tpml.core.types.Type ;
import de.unisiegen.tpml.core.types.TypeName ;
import de.unisiegen.tpml.core.util.Theme ;
import de.unisiegen.tpml.graphics.outline.Outline ;
import de.unisiegen.tpml.graphics.outline.binding.OutlineBinding ;
import de.unisiegen.tpml.graphics.outline.binding.OutlineUnbound ;
/**
* This class represents the nodes in the {@link Outline}.
*
* @author Christian Fehler
* @version $Rev: 1075 $
*/
public final class OutlineNode extends DefaultMutableTreeNode
{
/**
* The serial version UID.
*/
private static final long serialVersionUID = 1611765250060174993L ;
/**
* The {@link Expression} should not be shown in this nodes.
*/
private static final int NO_SELECTION = - 1 ;
/**
* Bindings should not be highlighted in higher nodes.
*/
public static final int NO_BINDING = - 1 ;
/**
* The {@link Expression} has no child index.
*/
public static final int NO_CHILD_INDEX = - 1 ;
/**
* The {@link Type} has no child types.
*/
public static final int NOTHING_FOUND = - 2 ;
/**
* The selected {@link Expression} should be highlighted in higher nodes.
*
* @see #setSelection(boolean)
*/
private static boolean selection = true ;
/**
* The selected {@link Expression} should be replaced in higher nodes.
*
* @see #setReplace(boolean)
*/
private static boolean replace = true ;
/**
* Selected {@link Identifier} and bindings should be highlighted in higher
* nodes.
*
* @see #setBinding(boolean)
*/
private static boolean binding = true ;
/**
* Unbound {@link Identifier}s should be highlighted in all nodes.
*
* @see #setFree(boolean)
*/
private static boolean free = true ;
/**
* Lower than replace.
*/
private static final String LOWER_THAN_REPLACE = "<" ; //$NON-NLS-1$
/**
* Greater than replace.
*/
private static final String GREATER_THAN_REPLACE = ">" ; //$NON-NLS-1$
/**
* Ampersand replace.
*/
private static final String AMPERSAND_THAN_REPLACE = "&" ; //$NON-NLS-1$
/**
* The end of the caption.
*/
private static final String EXPRESSION_END = "</font> ]</html>" ; //$NON-NLS-1$
/**
* String, if a {@link Expression} should be replaced and selection is active.
*/
private static final String REPLACE_BOLD = "<b> ... </b>" ; //$NON-NLS-1$
/**
* String, if a {@link Expression} should be replaced.
*/
private static final String REPLACE = " ... " ; //$NON-NLS-1$
/**
* String, between child index and description.
*/
private static final String BETWEEN1 = " - " ; //$NON-NLS-1$
/**
* String, between description and {@link Expression}.
*/
private static final String BETWEEN2 = " [ " ; //$NON-NLS-1$
/**
* Begin of HTML.
*/
private static final String HTML = "<html>" ; //$NON-NLS-1$
/**
* Begin of the smaller sub text.
*/
private static final String SMALL_SUB_BEGIN = "<small><sub>" ; //$NON-NLS-1$
/**
* End of the smaller sub text.
*/
private static final String SMALL_SUB_END = "</sub></small>" ; //$NON-NLS-1$
/**
* Before the description.
*/
private static final String PREFIX_BEGIN = "<font color=\"#FFFFFF\">" ; //$NON-NLS-1$
/**
* Before the description.
*/
private static final String DESCRIPTION_BEGIN = "<font color=\"#0000FF\">" ; //$NON-NLS-1$
/**
* After the description.
*/
private static final String DESCRIPTION_END = "</font>" ; //$NON-NLS-1$
/**
* The beginning of the caption.
*/
private static final String FONT_BEGIN = "<font color=\"#" ; //$NON-NLS-1$
/**
* End of font.
*/
private static final String FONT_END = "</font>" ; //$NON-NLS-1$
/**
* After the color.
*/
private static final String FONT_AFTER_COLOR = "\">" ; //$NON-NLS-1$
/**
* String for a break.
*/
private static final String BREAK = "<br>" ; //$NON-NLS-1$
/**
* Begin of font and bold.
*/
private static final String FONT_BOLD_BEGIN = "<b><font color=\"#" ; //$NON-NLS-1$
/**
* End of font and bold.
*/
private static final String FONT_BOLD_END = "</font></b>" ; //$NON-NLS-1$
/**
* Returns the color in hexadecimal formatting.
*
* @param pColor The color which should be returned.
* @return The color in hexadecimal formatting.
*/
private static final String getHexadecimalColor ( Color pColor )
{
String red = Integer.toHexString ( pColor.getRed ( ) ) ;
red = red.length ( ) == 1 ? red = "0" + red : red ; //$NON-NLS-1$
String green = Integer.toHexString ( pColor.getGreen ( ) ) ;
green = green.length ( ) == 1 ? green = "0" + green : green ; //$NON-NLS-1$
String blue = Integer.toHexString ( pColor.getBlue ( ) ) ;
blue = blue.length ( ) == 1 ? blue = "0" + blue : blue ; //$NON-NLS-1$
return red + green + blue ;
}
/**
* Returns the replaced <code>char</code>.
*
* @param pChar Input <code>char</code>.
* @return The replaced <code>char</code>.
*/
private static final String getHTMLCode ( char pChar )
{
if ( pChar == '&' )
{
return AMPERSAND_THAN_REPLACE ;
}
if ( pChar == '<' )
{
return LOWER_THAN_REPLACE ;
}
if ( pChar == '>' )
{
return GREATER_THAN_REPLACE ;
}
return String.valueOf ( pChar ) ;
}
/**
* Sets the binding value. Selected {@link Identifier} and bindings should be
* highlighted in higher nodes.
*
* @param pBinding Should or should not be highlighted.
* @see #binding
*/
public static final void setBinding ( boolean pBinding )
{
binding = pBinding ;
}
/**
* Sets the free value. Free {@link Identifier}s should be highlighted in all
* nodes.
*
* @param pFree Should or should not be highlighted.
* @see #free
*/
public static final void setFree ( boolean pFree )
{
free = pFree ;
}
/**
* Sets the replace value. The selected {@link Expression} should be replaced
* in higher nodes.
*
* @param pReplace Should or should not be replaced.
* @see #replace
*/
public static final void setReplace ( boolean pReplace )
{
replace = pReplace ;
}
/**
* Sets the selection value. The selected {@link Expression} should be
* highlighted in higher nodes.
*
* @param pSelection Should or should not be highlighted.
* @see #selection
*/
public static final void setSelection ( boolean pSelection )
{
selection = pSelection ;
}
/**
* The selected {@link Expression} should be replaced in this node.
*
* @see #setReplaceInThisNode(boolean)
*/
private boolean replaceInThisNode ;
/**
* The caption of the node.
*/
private String caption ;
/**
* The child index of this {@link Expression}.
*/
private String childIndex ;
/**
* The {@link Expression} or (@link Type} as a <code>String</code>.
*/
private String prettyString ;
/**
* The hole caption in HTML format.
*
* @see #getCaptionHTML()
* @see #setCaptionHTML(String)
*/
private String captionHTML ;
/**
* The {@link ExpressionOrType} repressented by this node.
*/
private ExpressionOrType expressionOrType ;
/**
* The {@link OutlineBinding} in this node.
*
* @see #getOutlineBinding()
* @see #setOutlineBinding(OutlineBinding)
*/
private OutlineBinding < ? > outlineBinding ;
/**
* The {@link OutlineUnbound} which repressents the free {@link Identifier}s
* in all nodes.
*/
private OutlineUnbound outlineUnbound ;
/**
* The start index of the {@link Identifier}.
*/
private int boundStart ;
/**
* The end index of the {@link Identifier}.
*/
private int boundEnd ;
/**
* The break count.
*/
private int breakCount ;
/**
* All breaks of this node.
*
* @see #getOutlineBreak()
*/
private OutlineBreak outlineBreak ;
/**
* The current breaks of this node.
*/
private OutlineBreak currentOutlineBreak ;
/**
* Indicates, if this node is a {@link Expression}.
*/
private boolean isExpression ;
/**
* Indicates, if this node is a {@link Identifier}.
*/
private boolean isIdentifier ;
/**
* Indicates, if this node is a {@link Type}.
*/
private boolean isType ;
/**
* Indicates, if this node is a {@link TypeName}.
*/
private boolean isTypeName ;
/**
* The start index of the last selection.
*/
private int lastSelectionStart ;
/**
* The end index of the last selection.
*/
private int lastSelectionEnd ;
/**
* The {@link OutlineNodeCacheList}, which caches the caption.
*/
private OutlineNodeCacheList outlineNodeCacheList ;
/**
* The {@link Expression} color.
*/
private String expressionColor ;
/**
* The {@link Identifier} color.
*/
private String identifierColor ;
/**
* The keyword color.
*/
private String keywordColor ;
/**
* The constant color.
*/
private String constantColor ;
/**
* The type color.
*/
private String typeColor ;
/**
* The selection color.
*/
private String selectionColor ;
/**
* The bound {@link Identifier} color.
*/
private String boundIdColor ;
/**
* The binding {@link Identifier} color.
*/
private String bindingIdColor ;
/**
* The free {@link Identifier} color.
*/
private String freeIdColor ;
/**
* The prefix after a break.
*/
private String prefix ;
/**
* This constructor initializes the values.
*/
private OutlineNode ( )
{
this.expressionOrType = null ;
this.caption = null ;
this.childIndex = "" ; //$NON-NLS-1$
this.prettyString = null ;
this.outlineBinding = null ;
this.outlineUnbound = null ;
this.replaceInThisNode = false ;
this.outlineBreak = null ;
this.currentOutlineBreak = null ;
this.breakCount = 0 ;
this.isExpression = false ;
this.isIdentifier = false ;
this.isType = false ;
this.isTypeName = false ;
this.boundStart = NO_BINDING ;
this.boundEnd = NO_BINDING ;
this.lastSelectionStart = NO_SELECTION ;
this.lastSelectionEnd = NO_SELECTION ;
this.outlineNodeCacheList = new OutlineNodeCacheList ( ) ;
propertyChanged ( ) ;
}
/**
* This constructor initializes the values and loads the description. It is
* used for {@link Expression}s.
*
* @param pExpression The {@link Expression} repressented by this node.
* @param pOutlineUnbound The {@link OutlineUnbound} which repressents the
* free {@link Identifier}s in all nodes.
* @param pChildIndex The child index.
*/
public OutlineNode ( Expression pExpression , OutlineUnbound pOutlineUnbound ,
int pChildIndex )
{
this ( ) ;
this.expressionOrType = pExpression ;
this.caption = pExpression.getCaption ( ) ;
this.prettyString = pExpression.toPrettyString ( ).toString ( ) ;
this.outlineUnbound = pOutlineUnbound.reduce ( this.expressionOrType ) ;
this.outlineBreak = new OutlineBreak ( this.expressionOrType ) ;
this.currentOutlineBreak = new OutlineBreak ( ) ;
this.isExpression = true ;
this.childIndex = pExpression.getPrefix ( )
+ ( ( pChildIndex <= OutlineNode.NO_CHILD_INDEX ) ? BETWEEN1
: SMALL_SUB_BEGIN + pChildIndex + SMALL_SUB_END + BETWEEN1 ) ;
this.prefix = PREFIX_BEGIN + this.childIndex + this.caption + BETWEEN2
+ FONT_END ;
}
/**
* This constructor initializes the values and loads the description. It is
* used for {@link Identifier}s.
*
* @param pIdentifier The {@link Identifier} repressented by this node.
* @param pOutlineBinding The bindings in this node.
* @param pChildIndex The child index.
*/
public OutlineNode ( Identifier pIdentifier , int pChildIndex ,
OutlineBinding < Identifier > pOutlineBinding )
{
this ( ) ;
this.expressionOrType = pIdentifier ;
this.caption = pIdentifier.getCaption ( ) ;
this.prettyString = pIdentifier.toPrettyString ( ).toString ( ) ;
this.outlineBinding = pOutlineBinding ;
this.outlineBreak = new OutlineBreak ( this.expressionOrType ) ;
this.currentOutlineBreak = new OutlineBreak ( ) ;
this.isIdentifier = true ;
this.childIndex = pIdentifier.getPrefix ( )
+ ( ( pChildIndex <= OutlineNode.NO_CHILD_INDEX ) ? BETWEEN1
: SMALL_SUB_BEGIN + pChildIndex + SMALL_SUB_END + BETWEEN1 ) ;
this.prefix = PREFIX_BEGIN + this.childIndex + this.caption + BETWEEN2
+ FONT_END ;
}
/**
* This constructor initializes the values and loads the description. It is
* used for {@link Type}s.
*
* @param pType The {@link Type} repressented by this node.
* @param pOutlineUnbound The {@link OutlineUnbound} which repressents the
* free {@link TypeName}s in all nodes.
* @param pChildIndex The child index.
*/
public OutlineNode ( Type pType , OutlineUnbound pOutlineUnbound ,
int pChildIndex )
{
this ( ) ;
this.expressionOrType = pType ;
this.caption = pType.getCaption ( ) ;
this.prettyString = pType.toPrettyString ( ).toString ( ) ;
this.outlineUnbound = pOutlineUnbound.reduce ( this.expressionOrType ) ;
this.outlineBreak = new OutlineBreak ( this.expressionOrType ) ;
this.currentOutlineBreak = new OutlineBreak ( ) ;
this.isType = true ;
this.childIndex = pType.getPrefix ( )
+ ( ( pChildIndex <= OutlineNode.NO_CHILD_INDEX ) ? BETWEEN1
: SMALL_SUB_BEGIN + pChildIndex + SMALL_SUB_END + BETWEEN1 ) ;
this.prefix = PREFIX_BEGIN + this.childIndex + this.caption + BETWEEN2
+ FONT_END ;
}
/**
* This constructor initializes the values and loads the description. It is
* used for {@link TypeName}s.
*
* @param pTypeName The {@link TypeName} repressented by this node.
* @param pChildIndex The child index.
* @param pOutlineBinding The bindings in this node.
*/
public OutlineNode ( TypeName pTypeName , int pChildIndex ,
OutlineBinding < TypeName > pOutlineBinding )
{
this ( ) ;
this.expressionOrType = pTypeName ;
this.caption = pTypeName.getCaption ( ) ;
this.prettyString = pTypeName.toPrettyString ( ).toString ( ) ;
this.outlineBinding = pOutlineBinding ;
this.outlineBreak = new OutlineBreak ( this.expressionOrType ) ;
this.currentOutlineBreak = new OutlineBreak ( ) ;
this.isTypeName = true ;
this.childIndex = pTypeName.getPrefix ( )
+ ( ( pChildIndex <= OutlineNode.NO_CHILD_INDEX ) ? BETWEEN1
: SMALL_SUB_BEGIN + pChildIndex + SMALL_SUB_END + BETWEEN1 ) ;
this.prefix = PREFIX_BEGIN + this.childIndex + this.caption + BETWEEN2
+ FONT_END ;
}
/**
* Adds a break and resets the cpation.
*/
public final void breakCountAdd ( )
{
if ( ( ! this.isExpression ) && ( ! this.isType ) )
{
return ;
}
if ( this.outlineBreak.getBreakCountAll ( ) == this.currentOutlineBreak
.getBreakCountOwn ( ) )
{
return ;
}
this.breakCount ++ ;
this.currentOutlineBreak = this.outlineBreak.getBreaks ( this.breakCount ) ;
while ( ( this.currentOutlineBreak.getBreakCountOwn ( ) == 0 )
&& ( this.currentOutlineBreak.hasBreaksAll ( ) ) )
{
this.breakCount ++ ;
this.currentOutlineBreak = this.outlineBreak.getBreaks ( this.breakCount ) ;
}
updateCaption ( this.lastSelectionStart , this.lastSelectionEnd ) ;
}
/**
* Removes a break and resets the cpation.
*/
public final void breakCountRemove ( )
{
if ( ( ! this.isExpression ) && ( ! this.isType ) )
{
return ;
}
if ( this.breakCount == 0 )
{
return ;
}
this.breakCount -- ;
this.currentOutlineBreak = this.outlineBreak.getBreaks ( this.breakCount ) ;
updateCaption ( this.lastSelectionStart , this.lastSelectionEnd ) ;
}
/**
* Returns true, if not all possible breaks are applied, otherwise false.
*
* @return True, if not all possible breaks are applied, otherwise false.
*/
public final boolean breaksCanAdd ( )
{
if ( this.outlineBreak == null )
{
return false ;
}
if ( this.currentOutlineBreak == null )
{
return false ;
}
return ( this.outlineBreak.getBreakCountAll ( ) > this.currentOutlineBreak
.getBreakCountOwn ( ) ) ;
}
/**
* Returns true, if not all possible breaks are removed, otherwise false.
*
* @return True, if not all possible breaks are remove, otherwise false.
*/
public final boolean breaksCanRemove ( )
{
if ( this.outlineBreak == null )
{
return false ;
}
if ( this.currentOutlineBreak == null )
{
return false ;
}
return ( this.currentOutlineBreak.getBreakCountOwn ( ) > 0 ) ;
}
/**
* This method returns the length of the binding {@link Identifier} or
* {@link TypeName}, if the {@link Identifier} or {@link TypeName} begins at
* the given pCharIndex.
*
* @param pCharIndex The index of the char.
* @return The length of the {@link Identifier} or {@link TypeName}, if the
* {@link Identifier} or {@link TypeName} begins at the given
* pCharIndex.
*/
private final int charIsBinding ( int pCharIndex )
{
if ( ( pCharIndex >= this.boundStart ) && ( pCharIndex <= this.boundEnd ) )
{
return this.boundEnd - this.boundStart + 1 ;
}
return - 1 ;
}
/**
* This method returns the length of the bound {@link Identifier} or
* {@link TypeName}, if the {@link Identifier} or {@link TypeName} begins at
* the given pCharIndex.
*
* @param pCharIndex The index of the char in the {@link Expression}.
* @return The length of the {@link Identifier} or {@link TypeName}, if the
* {@link Identifier} or {@link TypeName} begins at the given
* pCharIndex.
*/
private final int charIsBound ( int pCharIndex )
{
if ( this.outlineBinding == null )
{
return - 1 ;
}
PrettyAnnotation prettyAnnotation ;
for ( int i = 0 ; i < this.outlineBinding.size ( ) ; i ++ )
{
try
{
prettyAnnotation = this.expressionOrType.toPrettyString ( )
.getAnnotationForPrintable (
( ExpressionOrType ) this.outlineBinding.get ( i ) ) ;
if ( ( pCharIndex >= prettyAnnotation.getStartOffset ( ) )
&& ( pCharIndex <= prettyAnnotation.getEndOffset ( ) ) )
{
return prettyAnnotation.getEndOffset ( )
- prettyAnnotation.getStartOffset ( ) + 1 ;
}
}
catch ( IllegalArgumentException e )
{
/*
* Happens if the bound Identifiers are not in this node.
*/
}
}
return - 1 ;
}
/**
* This method returns the length of the free {@link Identifier}, if the
* {@link Identifier} begins at the given pCharIndex.
*
* @param pCharIndex pCharIndex The index of the char in the
* {@link Expression}.
* @return The length of the {@link Identifier}, if the {@link Identifier}
* begins at the given pCharIndex.
*/
private final int charIsFreeIdentifier ( int pCharIndex )
{
PrettyAnnotation prettyAnnotation ;
for ( int i = 0 ; i < this.outlineUnbound.size ( ) ; i ++ )
{
prettyAnnotation = this.expressionOrType.toPrettyString ( )
.getAnnotationForPrintable ( this.outlineUnbound.get ( i ) ) ;
if ( ( pCharIndex >= prettyAnnotation.getStartOffset ( ) )
&& ( pCharIndex <= prettyAnnotation.getEndOffset ( ) ) )
{
return prettyAnnotation.getEndOffset ( )
- prettyAnnotation.getStartOffset ( ) + 1 ;
}
}
return - 1 ;
}
/**
* Returns the caption.
*
* @return The caption.
* @see #captionHTML
*/
public final String getCaptionHTML ( )
{
return this.captionHTML ;
}
/**
* Returns the {@link ExpressionOrType} repressented by this node.
*
* @return The {@link ExpressionOrType} in this node.
* @see #expressionOrType
*/
public final ExpressionOrType getExpressionOrType ( )
{
return this.expressionOrType ;
}
/**
* Returns the binding in this node.
*
* @return The binding in this node.
* @see #outlineBinding
* @see #setOutlineBinding(OutlineBinding)
*/
public final OutlineBinding < ? > getOutlineBinding ( )
{
return this.outlineBinding ;
}
/**
* Returns the outlineBreak.
*
* @return The outlineBreak.
* @see #outlineBreak
*/
public final OutlineBreak getOutlineBreak ( )
{
return this.outlineBreak ;
}
/**
* Returns the prettyString.
*
* @return The prettyString.
* @see #prettyString
*/
public final String getPrettyString ( )
{
return this.prettyString ;
}
/**
* Return true, if this {@link Expression} has one or more breaks.
*
* @return True, if this {@link Expression} has one or more breaks.
*/
public final boolean hasBreaks ( )
{
return this.breakCount > 0 ;
}
/**
* Returns the isExpression.
*
* @return The isExpression.
* @see #isExpression
*/
public final boolean isExpression ( )
{
return this.isExpression ;
}
/**
* Returns the isIdentifier.
*
* @return The isIdentifier.
* @see #isIdentifier
*/
public final boolean isIdentifier ( )
{
return this.isIdentifier ;
}
/**
* Returns the isType.
*
* @return The isType.
* @see #isType
*/
public final boolean isType ( )
{
return this.isType ;
}
/**
* Returns the isTypeName.
*
* @return The isTypeName.
* @see #isTypeName
*/
public final boolean isTypeName ( )
{
return this.isTypeName ;
}
/**
* Loads the current color settings.
*/
public final void propertyChanged ( )
{
this.expressionColor = getHexadecimalColor ( Theme.currentTheme ( )
.getExpressionColor ( ) ) ;
this.identifierColor = getHexadecimalColor ( Theme.currentTheme ( )
.getIdentifierColor ( ) ) ;
this.keywordColor = getHexadecimalColor ( Theme.currentTheme ( )
.getKeywordColor ( ) ) ;
this.constantColor = getHexadecimalColor ( Theme.currentTheme ( )
.getConstantColor ( ) ) ;
this.typeColor = getHexadecimalColor ( Theme.currentTheme ( )
.getTypeColor ( ) ) ;
this.selectionColor = getHexadecimalColor ( Theme.currentTheme ( )
.getSelectionColor ( ) ) ;
this.boundIdColor = getHexadecimalColor ( Theme.currentTheme ( )
.getBoundIdColor ( ) ) ;
this.bindingIdColor = getHexadecimalColor ( Theme.currentTheme ( )
.getBindingIdColor ( ) ) ;
this.freeIdColor = getHexadecimalColor ( Theme.currentTheme ( )
.getFreeIdColor ( ) ) ;
this.outlineNodeCacheList.clear ( ) ;
}
/**
* Sets the {@link Identifier} which should be highlighted.
*
* @param pBindingIdentifier The {@link Identifier} which should be
* highlighted.
*/
public final void setBindingIdentifier ( Identifier pBindingIdentifier )
{
if ( pBindingIdentifier == null )
{
this.boundStart = NO_BINDING ;
this.boundEnd = NO_BINDING ;
return ;
}
try
{
PrettyAnnotation prettyAnnotation ;
prettyAnnotation = this.expressionOrType.toPrettyString ( )
.getAnnotationForPrintable ( pBindingIdentifier ) ;
this.boundStart = prettyAnnotation.getStartOffset ( ) ;
this.boundEnd = prettyAnnotation.getEndOffset ( ) ;
}
catch ( IllegalArgumentException e )
{
/*
* Happens if the bound Identifiers are not in this node.
*/
this.boundStart = NO_BINDING ;
this.boundEnd = NO_BINDING ;
}
}
/**
* Sets the {@link TypeName} which should be highlighted.
*
* @param pBindingTypeName The {@link TypeName} which should be highlighted.
*/
public final void setBindingTypeName ( TypeName pBindingTypeName )
{
if ( pBindingTypeName == null )
{
this.boundStart = NO_BINDING ;
this.boundEnd = NO_BINDING ;
return ;
}
try
{
PrettyAnnotation prettyAnnotation = this.expressionOrType
.toPrettyString ( ).getAnnotationForPrintable ( pBindingTypeName ) ;
this.boundStart = prettyAnnotation.getStartOffset ( ) ;
this.boundEnd = prettyAnnotation.getEndOffset ( ) ;
}
catch ( IllegalArgumentException e )
{
/*
* Happens if the bound TypeNames are not in this node.
*/
this.boundStart = NO_BINDING ;
this.boundEnd = NO_BINDING ;
}
}
/**
* Sets the caption of this node.
*
* @param pCaption The caption of this node.
* @see #captionHTML
*/
public final void setCaptionHTML ( String pCaption )
{
this.captionHTML = pCaption ;
}
/**
* Sets the {@link OutlineBinding} in this node.
*
* @param pOutlineBinding The {@link OutlineBinding} in this node.
* @see #outlineBinding
* @see #getOutlineBinding()
*/
public final void setOutlineBinding ( OutlineBinding < ? > pOutlineBinding )
{
if ( ( ! this.isIdentifier ) && ( ! this.isTypeName ) )
{
this.outlineBinding = pOutlineBinding ;
}
}
/**
* Set the value replaceInThisNode.
*
* @param pReplaceInThisNode True, if the selected {@link Expression} should
* be replaced in this node.
* @see #replaceInThisNode
*/
public final void setReplaceInThisNode ( boolean pReplaceInThisNode )
{
this.replaceInThisNode = pReplaceInThisNode ;
}
/**
* Returns this <code>Object</code> as a <code>String</code>.
*
* @see Object#toString()
*/
@ Override
public final String toString ( )
{
return this.captionHTML ;
}
/**
* Updates the caption of the node. This method checks each character of the
* name, if it is a keyword, a constant, a binding, selected or normal. This
* method updates the caption without selection.
*/
public final void updateCaption ( )
{
updateCaption ( NO_SELECTION , NO_SELECTION ) ;
}
/**
* Updates the caption of the node. This method checks each character of the
* name, if it is a keyword, a constant, a binding, selected or normal.
*
* @param pSelectionStart The start offset of the selection in this node.
* @param pSelectionEnd The end offset of the selection in this node.
*/
@ SuppressWarnings ( "unqualified-field-access" )
public final void updateCaption ( int pSelectionStart , int pSelectionEnd )
{
int selectionStart = pSelectionStart ;
int selectionEnd = pSelectionEnd ;
if ( selectionStart > selectionEnd )
{
selectionStart = NO_SELECTION ;
selectionEnd = NO_SELECTION ;
}
this.lastSelectionStart = selectionStart ;
this.lastSelectionEnd = selectionEnd ;
String cache = this.outlineNodeCacheList.getCaption ( selectionStart ,
selectionEnd , selection , binding , free ,
( replace && this.replaceInThisNode ) , this.boundStart ,
this.boundEnd , this.breakCount , this.outlineBinding ) ;
if ( cache != null )
{
this.captionHTML = cache ;
return ;
}
// Load the PrettyCharIterator
PrettyCharIterator prettyCharIterator = this.expressionOrType
.toPrettyString ( ).toCharacterIterator ( ) ;
// Initialize the result as a StringBuilder
StringBuilder result = new StringBuilder ( ) ;
// Build the first part of the node caption
result.append ( HTML ) ;
result.append ( this.childIndex ) ;
result.append ( DESCRIPTION_BEGIN ) ;
result.append ( this.caption ) ;
result.append ( DESCRIPTION_END ) ;
result.append ( BETWEEN2 ) ;
result.append ( FONT_BEGIN ) ;
result.append ( this.expressionColor ) ;
result.append ( FONT_AFTER_COLOR ) ;
int count = - 1 ;
int charIndex = 0 ;
final int length = this.prettyString.length ( ) ;
while ( charIndex < length )
{
/*
* Selection
*/
if ( ( charIndex == selectionStart ) && ( selection ) )
{
charIndex = updateCaptionSelection ( charIndex , selectionEnd ,
prettyCharIterator , result , this.selectionColor ) ;
}
/*
* No selection and binding.
*/
else if ( ( charIndex == selectionStart ) && ( ! selection )
&& ( binding ) && ( this.outlineBinding != null )
&& ( this.outlineBinding.size ( ) > 0 ) )
{
charIndex = updateCaptionSelection ( charIndex , selectionEnd ,
prettyCharIterator , result , this.selectionColor ) ;
}
/*
* No selection and replace.
*/
else if ( ( charIndex == selectionStart ) && ( ! selection )
&& ( replace ) && ( this.replaceInThisNode ) )
{
result.append ( REPLACE_BOLD ) ;
while ( charIndex <= selectionEnd )
{
// Next character
charIndex ++ ;
prettyCharIterator.next ( ) ;
}
}
/*
* Bound Identifier or bound TypeName
*/
else if ( ( binding ) && ( this.isExpression || this.isType )
&& ( this.outlineBinding != null )
&& ( ( count = charIsBound ( charIndex ) ) >= 0 ) )
{
charIndex = updateCaptionBinding ( charIndex , count ,
prettyCharIterator , result , this.boundIdColor ) ;
}
/*
* Binding Identifier or binding TypeName
*/
else if ( ( binding ) && ( ( count = charIsBinding ( charIndex ) ) >= 0 ) )
{
charIndex = updateCaptionBinding ( charIndex , count ,
prettyCharIterator , result , this.bindingIdColor ) ;
}
/*
* The selected Identifier-Expression is bound in this Expression or Type,
* but should not be selected or the selected TypeName-Type is bound in
* this Expression or Type, but should not be selected.
*/
else if ( ( ! selection ) && ( binding )
&& ( this.boundStart != NO_BINDING )
&& ( this.boundEnd != NO_BINDING ) && ( charIndex == selectionStart ) )
{
charIndex = updateCaptionSelection ( charIndex , selectionEnd ,
prettyCharIterator , result , this.selectionColor ) ;
}
/*
* Unbound Identifier
*/
else if ( ( free ) && ( this.outlineUnbound != null )
&& ( ( count = charIsFreeIdentifier ( charIndex ) ) >= 0 ) )
{
charIndex = updateCaptionBinding ( charIndex , count ,
prettyCharIterator , result , this.freeIdColor ) ;
}
/*
* Keyword
*/
else if ( PrettyStyle.KEYWORD.equals ( prettyCharIterator.getStyle ( ) ) )
{
charIndex = updateCaptionStyle ( charIndex , true ,
PrettyStyle.KEYWORD , prettyCharIterator , result ,
this.keywordColor ) ;
}
/*
* Identifier
*/
else if ( PrettyStyle.IDENTIFIER
.equals ( prettyCharIterator.getStyle ( ) ) )
{
charIndex = updateCaptionStyle ( charIndex , false ,
PrettyStyle.IDENTIFIER , prettyCharIterator , result ,
this.identifierColor ) ;
}
/*
* Constant
*/
else if ( PrettyStyle.CONSTANT.equals ( prettyCharIterator.getStyle ( ) ) )
{
charIndex = updateCaptionStyle ( charIndex , true ,
PrettyStyle.CONSTANT , prettyCharIterator , result ,
this.constantColor ) ;
}
/*
* Type
*/
else if ( PrettyStyle.TYPE.equals ( prettyCharIterator.getStyle ( ) ) )
{
charIndex = updateCaptionStyle ( charIndex , true , PrettyStyle.TYPE ,
prettyCharIterator , result , this.typeColor ) ;
}
/*
* Normal character
*/
else
{
if ( this.currentOutlineBreak.isBreak ( charIndex ) )
{
result.append ( BREAK ) ;
result.append ( prefix ) ;
}
result.append ( getHTMLCode ( this.prettyString.charAt ( charIndex ) ) ) ;
// Next character
charIndex ++ ;
prettyCharIterator.next ( ) ;
}
}
result.append ( EXPRESSION_END ) ;
OutlineNodeCache outlineNodeCache = new OutlineNodeCache ( selectionStart ,
selectionEnd , selection , binding , free ,
( replace && this.replaceInThisNode ) , this.boundStart ,
this.boundEnd , this.breakCount , this.outlineBinding , result
.toString ( ) ) ;
this.outlineNodeCacheList.add ( outlineNodeCache ) ;
this.captionHTML = result.toString ( ) ;
}
/**
* Updates the caption of the node.
*
* @param pCharIndex The char index.
* @param pCount The number of characters.
* @param pPrettyCharIterator The {@link PrettyCharIterator}.
* @param pResult The result {@link StringBuilder}.
* @param pColor The {@link Color} of the characters.
* @return The charIndex at the end of this method.
*/
private final int updateCaptionBinding ( int pCharIndex , int pCount ,
PrettyCharIterator pPrettyCharIterator , StringBuilder pResult ,
String pColor )
{
int charIndex = pCharIndex ;
pPrettyCharIterator.setIndex ( pPrettyCharIterator.getIndex ( ) + pCount ) ;
pResult.append ( FONT_BOLD_BEGIN ) ;
pResult.append ( pColor ) ;
pResult.append ( FONT_AFTER_COLOR ) ;
while ( charIndex < pCharIndex + pCount )
{
if ( this.currentOutlineBreak.isBreak ( charIndex ) )
{
pResult.append ( FONT_BOLD_END ) ;
pResult.append ( BREAK ) ;
pResult.append ( this.prefix ) ;
pResult.append ( FONT_BOLD_BEGIN ) ;
pResult.append ( pColor ) ;
pResult.append ( FONT_AFTER_COLOR ) ;
}
pResult.append ( getHTMLCode ( this.prettyString.charAt ( charIndex ) ) ) ;
// Next character
charIndex ++ ;
}
pResult.append ( FONT_BOLD_END ) ;
return charIndex ;
}
/**
* Updates the caption of the node.
*
* @param pCharIndex The char index.
* @param pSelectionEnd The end index of the selection.
* @param pPrettyCharIterator The {@link PrettyCharIterator}.
* @param pResult The result {@link StringBuilder}.
* @param pColor The {@link Color} of the characters.
* @return The charIndex at the end of this method.
*/
private final int updateCaptionSelection ( int pCharIndex ,
int pSelectionEnd , PrettyCharIterator pPrettyCharIterator ,
StringBuilder pResult , String pColor )
{
int charIndex = pCharIndex ;
pPrettyCharIterator.setIndex ( pSelectionEnd + 1 ) ;
pResult.append ( FONT_BOLD_BEGIN ) ;
pResult.append ( pColor ) ;
pResult.append ( FONT_AFTER_COLOR ) ;
// Replace selected Expression
if ( ( replace ) && ( this.replaceInThisNode ) )
{
pResult.append ( REPLACE ) ;
}
while ( charIndex <= pSelectionEnd )
{
if ( ( this.currentOutlineBreak.isBreak ( charIndex ) )
&& ( ! ( replace && this.replaceInThisNode ) ) )
{
pResult.append ( FONT_BOLD_END ) ;
pResult.append ( BREAK ) ;
pResult.append ( this.prefix ) ;
pResult.append ( FONT_BOLD_BEGIN ) ;
pResult.append ( pColor ) ;
pResult.append ( FONT_AFTER_COLOR ) ;
}
if ( ! ( replace && this.replaceInThisNode ) )
{
pResult
.append ( getHTMLCode ( this.prettyString.charAt ( charIndex ) ) ) ;
}
// Next character
charIndex ++ ;
}
pResult.append ( FONT_BOLD_END ) ;
return charIndex ;
}
/**
* Updates the caption of the node.
*
* @param pCharIndex The char index.
* @param pBold True if bold is active.
* @param pPrettyStyle The {@link PrettyStyle}.
* @param pPrettyCharIterator The {@link PrettyCharIterator}.
* @param pResult The result {@link StringBuilder}.
* @param pColor The {@link Color} of the characters.
* @return The charIndex at the end of this method.
*/
private final int updateCaptionStyle ( int pCharIndex , boolean pBold ,
PrettyStyle pPrettyStyle , PrettyCharIterator pPrettyCharIterator ,
StringBuilder pResult , String pColor )
{
int charIndex = pCharIndex ;
if ( pBold )
{
pResult.append ( FONT_BOLD_BEGIN ) ;
}
else
{
pResult.append ( FONT_BEGIN ) ;
}
pResult.append ( pColor ) ;
pResult.append ( FONT_AFTER_COLOR ) ;
while ( pPrettyStyle.equals ( pPrettyCharIterator.getStyle ( ) ) )
{
if ( this.currentOutlineBreak.isBreak ( charIndex ) )
{
pResult.append ( FONT_BOLD_END ) ;
pResult.append ( BREAK ) ;
pResult.append ( this.prefix ) ;
pResult.append ( FONT_BOLD_BEGIN ) ;
pResult.append ( pColor ) ;
pResult.append ( FONT_AFTER_COLOR ) ;
}
pResult.append ( getHTMLCode ( this.prettyString.charAt ( charIndex ) ) ) ;
// Next character
charIndex ++ ;
pPrettyCharIterator.next ( ) ;
}
if ( pBold )
{
pResult.append ( FONT_BOLD_END ) ;
}
else
{
pResult.append ( FONT_END ) ;
}
return charIndex ;
}
}