Package com.cb.eclipse.folding.java.calculation

Source Code of com.cb.eclipse.folding.java.calculation.JavaProjectionCalculator

/*******************************************************************************
* 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.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IParent;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.ToolFactory;
import org.eclipse.jdt.core.compiler.IScanner;
import org.eclipse.jdt.core.compiler.ITerminalSymbols;
import org.eclipse.jdt.core.compiler.InvalidInputException;
import org.eclipse.jface.text.BadLocationException;

import com.cb.eclipse.folding.EnhancedPosition;
import com.cb.eclipse.folding.java.JavaPositionMetadata;
import com.cb.eclipse.folding.java.JavaProjectionAnnotation;

/**
* The JavaProjectionCalculator implements the algorithm for recursively
* processing an IJavaElement tree and providing a group of positions that
* represent the foldable structures of that tree.
*
* @author R.J. Lorimer
*/
public class JavaProjectionCalculator {

  private boolean enableCollapsing;

  public JavaProjectionCalculator() {

  }

  /**
   * This ensures that collapsing is disabled temporarily for all elements.
   *
   * @param collapseOn
   */
  public void setCollapsing(boolean collapseOn) {
    enableCollapsing = collapseOn;
  }

  /**
   * Produces an map of annotations to positions for a Java editor.
   *
   * @see com.cb.eclipse.folding.ProjectionAnnotationFactory#findAnnotations(org.eclipse.jdt.core.IParent)
   */
  public Map findAnnotations(IJavaElement parentElement) {

    try {
      Map result = new HashMap();

      findAnnotations((IJavaElement) parentElement, result);
      return result;
    }
    catch (JavaModelException e) {
    }
    catch (InvalidInputException e) {
    }
    catch (BadLocationException e) {
    }
    return null;
  }

  /**
   * Finds all JavaProjectionAnnotation positions for <code>elem</code> and
   * places them into the result map.
   *
   * @param elem
   * @param result
   * @throws JavaModelException
   * @throws InvalidInputException
   */
  private Set findAnnotations(IJavaElement elem, Map result) throws JavaModelException, InvalidInputException, BadLocationException {

    boolean doCollapse = false;
    int elemType = elem.getElementType();

    Set regions = null;
    try {
      regions = computeProjections(elem);
    }
    catch(RuntimeException e) {
      e.printStackTrace();
      throw e;
    }
   
    // Recursively process
    if (elem instanceof IParent) {
      IJavaElement[] children = ((IParent) elem).getChildren();
      for (int i = 0; i < children.length; i++) {
        IJavaElement aChild = children[i];
        Set childRegions = findAnnotations(aChild, result);
        removeCollisions(regions, childRegions);
      }

    }

   

    constructAnnotations(elem, result, regions);

    return regions;

  }

  /**
   * Determines what regions in the parent list collide with regions in the
   * child list and removes them.
   *
   * The nature of the java elements are to contain other elements. If, for
   * some reason, the parent element's calculation strategy returned regions
   * that are conflicting with the child element's calculation strategy's
   * returned regions, we throw away the parent region's results for that
   * area.
   *
   * The assumption is that if the child region had visibility to a particular
   * region, it is up to the child region to determine what to do with it.
   *
   * @param parentSet
   * @param childSet
   */
  private void removeCollisions(Set parentSet, Set childSet) {
    if (parentSet == null || childSet == null) return;

    Iterator parents = parentSet.iterator();
    while (parents.hasNext()) {
      EnhancedPosition parentRegion = (EnhancedPosition) parents.next();
      if ( ((JavaPositionMetadata)parentRegion.getMetadata()).isOverlap() && hasCollision(parentRegion, childSet)) {
        parents.remove();
      }
    }
  }

  private boolean hasCollision(EnhancedPosition parentRegion, Set childSet) {

    Iterator children = childSet.iterator();
    while (children.hasNext()) {
      EnhancedPosition childRegion = (EnhancedPosition) children.next();
      if (parentRegion.collidesWith(childRegion) || childRegion.contains(parentRegion) && !((JavaPositionMetadata)parentRegion.getMetadata()).isUserDefined()) { return true; }
    }
    return false;
  }

  /**
   * Associates JavaProjectionAnnotations with Positions in the result map.
   *
   * @param elem
   * @param result
   * @param positions
   * @throws BadLocationException
   */
  private void constructAnnotations(IJavaElement elem, Map result, Set positions) throws BadLocationException, JavaModelException {
    ISourceReference reference = (ISourceReference) elem;

    if (positions != null) {

      for (Iterator iter = positions.iterator(); iter.hasNext();) {
        EnhancedPosition aPosition = (EnhancedPosition) iter.next();
        result.put(new JavaProjectionAnnotation(0, aPosition, elem, enableCollapsing && ((JavaPositionMetadata)aPosition.getMetadata()).isCollapse()), aPosition);
      }
    }
  }

  protected boolean enableCollapsing() {
    return enableCollapsing;
  }

  /**
   * The core logic of this class.
   *
   * Computes using the strategy objects what regions are available as
   * projections for this particular element.
   *
   * @param elem
   * @return @throws
   *         JavaModelException
   * @throws InvalidInputException
   */
  private Set computeProjections(IJavaElement elem) throws JavaModelException, InvalidInputException {
    if (!(elem instanceof ISourceReference)) return null;

   
    RegionCalculationStrategy strategy = StrategyFactory.instance(this, elem);
    strategy.initialize();
    Set regionSet;
    if (!strategy.shouldScan(elem)) {
      regionSet = strategy.result(); // call immediately...
    }
    else {
      ISourceReference reference = (ISourceReference) elem;
      ISourceRange range = reference.getSourceRange();

      // All other element types require some parsing...
      String contents = reference.getSource();

      if (contents == null) return null;

      IScanner scanner = ToolFactory.createScanner(true, false, false, false);
      scanner.setSource(contents.toCharArray());

      int shift = range.getOffset();
      int start = shift;

      while (true) {
        int token = scanner.getNextToken();

        start = shift + scanner.getCurrentTokenStartPosition();
        int end = shift + scanner.getCurrentTokenEndPosition() + 1;

        if (!strategy.keepProcessing(token) || token == ITerminalSymbols.TokenNameEOF) {
          break; // end case.
        }

        strategy.handle(token, start, end, elem);

      }

      strategy.postScan(start, elem);

      regionSet = strategy.result();

    }

    if (regionSet == null) {
      regionSet = Collections.EMPTY_SET;
    }
   
   
   
   
    strategy.dispose();

    return regionSet;

  }

}
TOP

Related Classes of com.cb.eclipse.folding.java.calculation.JavaProjectionCalculator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.