package de.unisiegen.tpml.graphics.outline.node ; import java.util.ArrayList ; import de.unisiegen.tpml.core.expressions.Expression ; import de.unisiegen.tpml.core.interfaces.DefaultTypes ; import de.unisiegen.tpml.core.interfaces.ExpressionOrType ; import de.unisiegen.tpml.core.prettyprinter.PrettyAnnotation ; import de.unisiegen.tpml.core.types.MonoType ; import de.unisiegen.tpml.core.types.Type ; /** * In this class the breaks of the {@link OutlineNode}s are saved. * * @author Christian Fehler */ public final class OutlineBreak { /** * The list of breaks. */ private ArrayList < Integer > breakList ; /** * The list of child {@link OutlineBreak}s. */ private ArrayList < OutlineBreak > outlineBreakList ; /** * Initilizes the {@link OutlineBreak}. */ public OutlineBreak ( ) { this.breakList = new ArrayList < Integer > ( ) ; this.outlineBreakList = new ArrayList < OutlineBreak > ( ) ; } /** * Initilizes the {@link OutlineBreak} with the given {@link ExpressionOrType}. * * @param pExpressionOrType The input {@link ExpressionOrType}. */ public OutlineBreak ( ExpressionOrType pExpressionOrType ) { this.breakList = new ArrayList < Integer > ( ) ; this.outlineBreakList = new ArrayList < OutlineBreak > ( ) ; if ( pExpressionOrType instanceof Expression ) { calculate ( ( Expression ) pExpressionOrType ) ; } else if ( pExpressionOrType instanceof Type ) { calculate ( ( Type ) pExpressionOrType ) ; } } /** * Adds the given offset to the own breaks and the breaks of all children * {@link OutlineBreak}s. * * @param pOffset The offset, which should be added. */ private final void addOffset ( int pOffset ) { for ( int i = 0 ; i < this.breakList.size ( ) ; i ++ ) { this.breakList.set ( i , new Integer ( this.breakList.get ( i ) .intValue ( ) + pOffset ) ) ; } for ( int i = 0 ; i < this.outlineBreakList.size ( ) ; i ++ ) { this.outlineBreakList.get ( i ).addOffset ( pOffset ) ; } } /** * Calculates the breaks. * * @param pExpression The input {@link Expression}. */ private final void calculate ( Expression pExpression ) { PrettyAnnotation prettyAnnotation = pExpression.toPrettyString ( ) .getAnnotationForPrintable ( pExpression ) ; int [ ] breaks = prettyAnnotation.getBreakOffsets ( ) ; for ( int i = 0 ; i < breaks.length ; i ++ ) { this.breakList.add ( new Integer ( breaks [ i ] ) ) ; } ArrayList < Expression > children = pExpression.children ( ) ; for ( Expression expr : children ) { PrettyAnnotation prettyAnnotationChild ; try { prettyAnnotationChild = pExpression.toPrettyString ( ) .getAnnotationForPrintable ( expr ) ; } catch ( IllegalArgumentException e ) { continue ; } OutlineBreak outlineBreakChild = new OutlineBreak ( expr ) ; outlineBreakChild.addOffset ( prettyAnnotationChild.getStartOffset ( ) ) ; if ( breaks.length > 0 ) { this.outlineBreakList.add ( outlineBreakChild ) ; } else { for ( int i = 0 ; i < outlineBreakChild.breakList.size ( ) ; i ++ ) { this.breakList.add ( outlineBreakChild.breakList.get ( i ) ) ; } for ( int i = 0 ; i < outlineBreakChild.outlineBreakList.size ( ) ; i ++ ) { this.outlineBreakList.add ( outlineBreakChild.outlineBreakList .get ( i ) ) ; } } } if ( pExpression instanceof DefaultTypes ) { MonoType [ ] types = ( ( DefaultTypes ) pExpression ).getTypes ( ) ; for ( MonoType tau : types ) { PrettyAnnotation prettyAnnotationChild ; try { prettyAnnotationChild = pExpression.toPrettyString ( ) .getAnnotationForPrintable ( tau ) ; } catch ( IllegalArgumentException e ) { continue ; } OutlineBreak outlineBreakChild = new OutlineBreak ( tau ) ; outlineBreakChild.addOffset ( prettyAnnotationChild.getStartOffset ( ) ) ; if ( breaks.length > 0 ) { this.outlineBreakList.add ( outlineBreakChild ) ; } else { for ( int i = 0 ; i < outlineBreakChild.breakList.size ( ) ; i ++ ) { this.breakList.add ( outlineBreakChild.breakList.get ( i ) ) ; } for ( int i = 0 ; i < outlineBreakChild.outlineBreakList.size ( ) ; i ++ ) { this.outlineBreakList.add ( outlineBreakChild.outlineBreakList .get ( i ) ) ; } } } } } /** * Calculates the breaks. * * @param pType The input {@link Type}. */ private final void calculate ( Type pType ) { PrettyAnnotation prettyAnnotation = pType.toPrettyString ( ) .getAnnotationForPrintable ( pType ) ; int [ ] breaks = prettyAnnotation.getBreakOffsets ( ) ; for ( int i = 0 ; i < breaks.length ; i ++ ) { this.breakList.add ( new Integer ( breaks [ i ] ) ) ; } ArrayList < Type > children = pType.children ( ) ; for ( Type child : children ) { PrettyAnnotation prettyAnnotationChild ; try { prettyAnnotationChild = pType.toPrettyString ( ) .getAnnotationForPrintable ( child ) ; } catch ( IllegalArgumentException e ) { continue ; } OutlineBreak outlineBreakChild = new OutlineBreak ( child ) ; outlineBreakChild.addOffset ( prettyAnnotationChild.getStartOffset ( ) ) ; if ( breaks.length > 0 ) { this.outlineBreakList.add ( outlineBreakChild ) ; } else { for ( int i = 0 ; i < outlineBreakChild.breakList.size ( ) ; i ++ ) { this.breakList.add ( outlineBreakChild.breakList.get ( i ) ) ; } for ( int i = 0 ; i < outlineBreakChild.outlineBreakList.size ( ) ; i ++ ) { this.outlineBreakList.add ( outlineBreakChild.outlineBreakList .get ( i ) ) ; } } } } /** * Returns the number of breaks of this {@link OutlineBreak}, including the * breaks of children {@link OutlineBreak}s. * * @return The number of breaks of this {@link OutlineBreak}, including the * breaks of children {@link OutlineBreak}s. */ public final int getBreakCountAll ( ) { int result = 0 ; result += this.breakList.size ( ) ; for ( int i = 0 ; i < this.outlineBreakList.size ( ) ; i ++ ) { result += this.outlineBreakList.get ( i ).getBreakCountAll ( ) ; } return result ; } /** * Returns the number of breaks of this {@link OutlineBreak}, without the * breaks of children {@link OutlineBreak}s. * * @return The number of breaks of this {@link OutlineBreak}, without the * breaks of children {@link OutlineBreak}s. */ public final int getBreakCountOwn ( ) { return this.breakList.size ( ) ; } /** * Returns a new {@link OutlineBreak}, which has the breaks of the children * of this {@link OutlineBreak}, but only children within the depth. * * @param pDepth The depth. * @return A new {@link OutlineBreak}, which has the breaks of the children * of this {@link OutlineBreak}, but only children within the depth. */ public final OutlineBreak getBreaks ( int pDepth ) { OutlineBreak result = new OutlineBreak ( ) ; if ( pDepth == 0 ) { return result ; } if ( pDepth == 1 ) { result.breakList.addAll ( this.breakList ) ; result.outlineBreakList.addAll ( this.outlineBreakList ) ; return result ; } result.breakList.addAll ( this.breakList ) ; for ( int i = 0 ; i < this.outlineBreakList.size ( ) ; i ++ ) { OutlineBreak child = this.outlineBreakList.get ( i ).getBreaks ( pDepth - 1 ) ; result.breakList.addAll ( child.breakList ) ; result.outlineBreakList.addAll ( child.outlineBreakList ) ; } return result ; } /** * Returns true, if this {@link OutlineBreak} has a break, or some children * has a break. Otherwise false. * * @return True, if this {@link OutlineBreak} has a break, or some children * has a break. Otherwise false. */ public final boolean hasBreaksAll ( ) { if ( this.breakList.size ( ) > 0 ) { return true ; } boolean found ; for ( int i = 0 ; i < this.outlineBreakList.size ( ) ; i ++ ) { found = this.outlineBreakList.get ( i ).hasBreaksAll ( ) ; if ( found ) { return true ; } } return false ; } /** * Returns true, if there is a break at the given char index. Otherwise false. * * @param pCharIndex The char index. * @return True, if there is a break at the given char index. Otherwise false. */ public final boolean isBreak ( int pCharIndex ) { return this.breakList.contains ( new Integer ( pCharIndex ) ) ; } }