/*******************************************************************************
* Copyright (c) 2004 Coffee-Bytes.com and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.opensource.org/licenses/cpl.php
*
* Contributors:
* Coffee-Bytes.com - initial API and implementation
*******************************************************************************/
package com.cb.eclipse.folding.java.calculation;
import java.util.Set;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.ITerminalSymbols;
import com.cb.eclipse.folding.EnhancedPosition;
import com.cb.eclipse.folding.FoldingPlugin;
import com.cb.eclipse.folding.java.JavaPositionMetadata;
import com.cb.eclipse.folding.java.preferences.PreferenceKeys;
import com.cb.eclipse.folding.util.IntStack;
/**
* A generic implementation of CalculationStrategy that processes based on block
* identifiers (e.g. { and } ).
*
* This class provides nested block handling capabilities by using stack
* mathematics.
*
* @author RJ
*/
public abstract class AbstractBlockStrategy extends AbstractCalculationStrategy {
private IntStack braceStack = new IntStack();
private boolean digestComments = false;
private int lastValidOpener = -1;
private CommentHelper helper;
public AbstractBlockStrategy(boolean digestComments) {
super();
this.helper = new CommentHelper();
this.digestComments = digestComments;
}
/**
* Push left braces, pop right braces and calculate the distance in between
* as a region.
*
* @see com.cb.eclipse.folding.java.calculation.RegionCalculationStrategy#handle(int,
* int, int, org.eclipse.jdt.core.IJavaElement)
*/
public void handle(int token, int start, int end, IJavaElement owner) throws JavaModelException {
boolean collapseComments = FoldingPlugin.getPrefs().getBoolean(PreferenceKeys.COLLAPSE_COMMENT_BLOCKS);
boolean collapseJavadoc = FoldingPlugin.getPrefs().getBoolean(PreferenceKeys.COLLAPSE_JAVADOCS);
switch (token) {
case ITerminalSymbols.TokenNameLBRACE: {
pushBrace(start);
helper.end();
break;
}
case ITerminalSymbols.TokenNameRBRACE: {
if(hasUsablePeer()) {
int oldStart = popBrace();
helper.end();
if (shouldFold(owner, token)) {
boolean doCollapse = shouldCollapse(owner, token);
boolean shouldNegate = shouldFilterLastLine(owner, token);
addRegion(new EnhancedPosition(oldStart, end - oldStart, new JavaPositionMetadata(false, shouldNegate, doCollapse, true, getClass().getName())));
}
}
else {
System.out.println("Bad brace found... omitting!");
}
break;
}
default: {
if (digestComments) helper.handle(token, start, end, owner);
}
}
}
/**
* Currently designed to process until EOF is hit.
*
* @see com.cb.eclipse.folding.java.calculation.CalculationStrategy#keepProcessing(int)
*/
public boolean keepProcessing(int nextToken) {
return true;
}
/**
* Push another left brace location on to the stack, and grow the left-brace
* location stack if neccessary.
*
* @param location
*/
private void pushBrace(int location) {
braceStack.push(location);
}
/**
* Pop a left-brace location off of the stack.
*
* @return a left brace location.
*/
private int popBrace() {
int location;
if(isEmpty()) {
location = lastValidOpener;
}
else {
location = braceStack.pop();
if(isEmpty()) {
lastValidOpener = location;
}
}
return location;
}
/**
* Ensures that one way or another the brace being matched has a usable peer.
*
* This may mean that in the case of mismatched braces we are looking for the broadest
* set of braces, or it may simply mean that it is looking for a matching brace.
* @return
*/
private boolean hasUsablePeer() {
return !isEmpty() || lastValidOpener >= 0;
}
/**
* Determine if we have any braces pushed on the stack.
*
* @return
*/
protected boolean isEmpty() {
return braceStack.isEmpty();
}
protected int getLevel() {
return braceStack.size();
}
/*
* (non-Javadoc)
*
* @see com.cb.eclipse.folding.calculation.RegionCalculationStrategy#result()
*/
public Set result() throws JavaModelException {
super.addAllRegions(helper.result());
return super.result();
}
public abstract boolean shouldFold(IJavaElement owner, int token) throws JavaModelException;
public abstract boolean shouldFilterLastLine(IJavaElement owner, int token) throws JavaModelException;
public abstract boolean shouldCollapse(IJavaElement owner, int token) throws JavaModelException;
}