Package org.eclipse.wst.xml.ui.internal.contentassist

Source Code of org.eclipse.wst.xml.ui.internal.contentassist.XMLTemplateCompletionProcessor

/*******************************************************************************
* Copyright (c) 2001, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*     Jens Lukowski/Innoopract - initial renaming/restructuring
*     gavingui2011@gmail.com - Add TapestryTools features
*    
*******************************************************************************/
package org.eclipse.wst.xml.ui.internal.contentassist;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.core.ClassFile;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.templates.ContextTypeRegistry;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.text.templates.TemplateCompletionProcessor;
import org.eclipse.jface.text.templates.TemplateContext;
import org.eclipse.jface.text.templates.TemplateContextType;
import org.eclipse.jface.text.templates.TemplateException;
import org.eclipse.jface.text.templates.TemplateProposal;
import org.eclipse.jface.text.templates.persistence.TemplateStore;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.internal.Workbench;
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils;
import org.eclipse.wst.xml.core.internal.contentmodel.tapestry.TapestryElementCollection;
import org.eclipse.wst.xml.core.internal.contentmodel.tapestry.travelpackage.CoreComponentsUtil;
import org.eclipse.wst.xml.core.internal.contentmodel.tapestry.travelpackage.TapestryClassLoader;
import org.eclipse.wst.xml.core.internal.contentmodel.tapestry.travelpackage.TapestryCoreComponents;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.eclipse.wst.xml.ui.internal.XMLUIPlugin;
import org.eclipse.wst.xml.ui.internal.contentassist.tapestry.TapestryComponentCompletionProposalComputer;
import org.eclipse.wst.xml.ui.internal.contentassist.tapestry.TapestryRootComponentsProposalComputer;
import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper;
import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;


/**
* <p>Completion computer for XML templates</p>
*/
class XMLTemplateCompletionProcessor extends TemplateCompletionProcessor {
  //Represent Tapestry component when try to pop up attributes list in components
  private Node currentTapestryComponent = null;
  private TapestryElementCollection collection = new TapestryElementCollection();
  private HashMap<String, TapestryCoreComponents[]> templateCacheMap = new HashMap<String, TapestryCoreComponents[]>();
  private TapestryClassLoader tapestryClassLoader = new TapestryClassLoader();
  private TapestryRootComponentsProposalComputer tapestryRootComponentsProposalComputer = new TapestryRootComponentsProposalComputer();
  private static final class ProposalComparator implements Comparator {
    public int compare(Object o1, Object o2) {
      return ((TemplateProposal) o2).getRelevance() - ((TemplateProposal) o1).getRelevance();
    }
  }

  private static final Comparator fgProposalComparator = new ProposalComparator();
  private String fContextTypeId = null;

  /**
   * This method is used to generate content assit for:
   * 1. blank space to list Tapestry components
   * 2. input '<' to list Tapestry components
   * 3. int '<t:' to list Tapestry components
   * 4. list attributes for Tapestry component
   * 5. list attributes values
   */
  public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {

    ITextSelection selection = (ITextSelection) viewer.getSelectionProvider().getSelection();

    // adjust offset to end of normalized selection
    if (selection.getOffset() == offset) {
      offset = selection.getOffset() + selection.getLength();
    }

    String prefix = extractPrefix(viewer, offset);
    Region region = new Region(offset - prefix.length(), prefix.length());
    TemplateContext context = createContext(viewer, region, offset);
    if (context == null) {
      return new ICompletionProposal[0];
    }

    IndexedRegion treeNode = ContentAssistUtils.getNodeAt(viewer, offset);

    currentTapestryComponent = (Node) treeNode; 
    char preChar=0,preChar2=0;
    //In situation user input <, we should store the char before cursor into preChar and even preChar2
    if(currentTapestryComponent.getNodeValue() != null){
      for(int i=offset-treeNode.getStartOffset()-1; i>=0; i--){
        char temp = currentTapestryComponent.getNodeValue().charAt(i);
        if(temp != 9 && temp != 10 && temp != 32){
          if(preChar == 0)
            preChar = temp;
          else{
            preChar2 = temp;
            break;
          }
        }
      }
    }
   
    while ((currentTapestryComponent != null) && (currentTapestryComponent.getNodeType() == Node.TEXT_NODE) && (currentTapestryComponent.getParentNode() != null)) {
      currentTapestryComponent = currentTapestryComponent.getParentNode();
    }

    // name of the selection variables {line, word}_selection
    context.setVariable("selection", selection.getText()); //$NON-NLS-1$
   
    System.out.println(">>>>> Get template list by context id:" + context.getContextType().getId() + "  selection:" + selection.getText());
   
    Template[] templates = getTemplates((IDOMNode) treeNode, offset, context.getContextType().getId(), preChar, preChar2);

    List matches = new ArrayList();
    for (int i = 0; i < templates.length; i++) {
      Template template = templates[i];
      try {
        context.getContextType().validate(template.getPattern());
      }
      catch (TemplateException e) {
        continue;
      }
      if (template.matches(prefix, context.getContextType().getId())) {
        int place = getRelevance(template, prefix);
        matches.add(createProposal(template, context, (IRegion) region, place));
      }
    }

    Collections.sort(matches, fgProposalComparator);

    return (ICompletionProposal[]) matches.toArray(new ICompletionProposal[matches.size()]);
  }

  /**
   * Creates a concrete template context for the given region in the
   * document. This involves finding out which context type is valid at the
   * given location, and then creating a context of this type. The default
   * implementation returns a <code>SmartReplaceTemplateContext</code> for
   * the context type at the given location. This takes the offset at which
   * content assist was invoked into consideration.
   *
   * @param viewer
   *            the viewer for which the context is created
   * @param region
   *            the region into <code>document</code> for which the
   *            context is created
   * @param offset
   *            the original offset where content assist was invoked
   * @return a template context that can handle template insertion at the
   *         given location, or <code>null</code>
   */
  private TemplateContext createContext(ITextViewer viewer, IRegion region, int offset) {
    // pretty much same code as super.createContext except create
    // SmartReplaceTemplateContext
    TemplateContextType contextType = getContextType(viewer, region);
    if (contextType != null) {
      IDocument document = viewer.getDocument();
      return new ReplaceNameTemplateContext(contextType, document, region.getOffset(), region.getLength(), offset);
    }
    return null;
  }

  protected ICompletionProposal createProposal(Template template, TemplateContext context, IRegion region, int relevance) {
    return new CustomTemplateProposal(template, context, region, getImage(template), relevance);
  }

  protected TemplateContextType getContextType(ITextViewer viewer, IRegion region) {
    TemplateContextType type = null;

    ContextTypeRegistry registry = getTemplateContextRegistry();
    if (registry != null) {
      type = registry.getContextType(fContextTypeId);
    }

    return type;
  }

  protected Image getImage(Template template) {
    if(template.getContextTypeId().equals(TapestryElementCollection.componentsContextTypeId))
      return XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_TAPESTRY_DEFAULT);
    else if(template.getContextTypeId().equals(TapestryElementCollection.attributesContextTypeId))
      return XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_TAPESTRY_ATTRIBUTE);
    else if(template.getContextTypeId().equals(TapestryElementCollection.entitiesContextTypeId))
      return XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_TAPESTRY_ENTITY);
    else if(template.getContextTypeId().equals(TapestryElementCollection.attributesValueContextTypeId))
      return XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_TAPESTRY_DEFAULT);
    else
      return XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_MACRO);
  }

  private ContextTypeRegistry getTemplateContextRegistry() {
    return XMLUIPlugin.getDefault().getTemplateContextRegistry();
  }

  /**
   * This method does not used, just implement abstract method
   */
  protected Template[] getTemplates(String contextTypeId) {
   
    return null;
  }
 
  private IProject getCurrentProject(){
    IEditorPart editorPart = Workbench.getInstance()
        .getActiveWorkbenchWindow().getActivePage().getActiveEditor();
    IFileEditorInput input = (IFileEditorInput) editorPart.getEditorInput();
    IFile file = input.getFile();
    return file.getProject();
  }
 
  private PackageFragment getTapestryCoreLibrary() {
    IPackageFragmentRoot root = tapestryClassLoader.getTapestryCoreJar(getCurrentProject());
    if(root == null)
      return null;
    IPackageFragment pack = root.getPackageFragment("org.apache.tapestry5.corelib.components");
    if(pack != null && pack instanceof PackageFragment)
      return (PackageFragment) pack;
    return null;
  }
 
  /**
   * Get templates entrance method
   *
   * @param node
   * @param offset
   * @param contextTypeId
   * @param preChar
   * @param preChar2
   * @return
   */
  protected Template[] getTemplates(IDOMNode node, int offset, String contextTypeId, char preChar, char preChar2) {
    IProject project = getCurrentProject();
    String mapKey = project.getName();
    TapestryCoreComponents[] coreList = this.templateCacheMap.get(mapKey);
    if(coreList == null || coreList.length <= 0){
      //Get tapestry components from classpath
      List<TapestryCoreComponents> list = new ArrayList<TapestryCoreComponents>();
      PackageFragment tapestryCorePackage = getTapestryCoreLibrary();
      try {
        if(tapestryCorePackage !=null)
          for(Object packo : tapestryCorePackage.getChildrenOfType(IJavaElement.CLASS_FILE)){
            ClassFile packi = (ClassFile) packo;
            if(packi.getElementName().indexOf('$') < 0){
              TapestryCoreComponents component = tapestryClassLoader.loadComponentAttributesFromClassFile(tapestryClassLoader.getTapestryCoreJar(project), "t", packi);
              if(component != null)
                list.add(component);
            }
          }
      } catch (JavaModelException e) {
        e.printStackTrace();
      } catch (ClassFormatException e) {
        e.printStackTrace();
      }
      if(list != null && list.size() > 0){
        coreList = list.toArray(new TapestryCoreComponents[0]);
        this.templateCacheMap.put(mapKey, coreList);
      }
    }
   
    if(coreList == null)
      return new Template[0];
   
    if(contextTypeId.equals(TapestryElementCollection.componentsContextTypeId) ){     
      boolean customComponent = false;
      int type = 1;
      if(preChar == '<')
        type = 2;
      else if(currentTapestryComponent.getPrefix() != null){
        customComponent = tapestryRootComponentsProposalComputer.getComponentsPrefixList(this.getCurrentProject()).contains(currentTapestryComponent.getPrefix());
        if(customComponent)
          type = 3;
      }
      List<Template> components = new ArrayList<Template>();
      if(currentTapestryComponent.getPrefix() != null && !customComponent)
        return components.toArray(new Template[0]);
     
      if(type!=3 || currentTapestryComponent.getNodeName().equals("t:")){
        List<Template> buildInList = CoreComponentsUtil.buildTemplateListFromComponents(coreList, contextTypeId, type);
        if(buildInList != null && buildInList.size() > 0)
          components.addAll(buildInList);
        List<Template> rootComponents = tapestryRootComponentsProposalComputer.getRootComponentsTemplates(this.getCurrentProject(), contextTypeId, type);
        if(rootComponents != null && rootComponents.size() > 0)
          components.addAll(rootComponents);
      }
     
      if(currentTapestryComponent.getPrefix() == null || (currentTapestryComponent.getPrefix() + ":").equals(currentTapestryComponent.getNodeName())){
        List<Template> customComponents = tapestryRootComponentsProposalComputer.getCustomComponentsTemplates(this.getCurrentProject(), contextTypeId, type, currentTapestryComponent.getPrefix());
        if(customComponents != null && customComponents.size() > 0)
          components.addAll(customComponents);
      }
     
      return components == null ? null : components.toArray(new Template[0]);
    }else if(contextTypeId.equals(TapestryElementCollection.attributesContextTypeId)){
      String tapestryComponentName = getTapestryComponentName(node);
      //In condition <t:ActionLink
      if(tapestryComponentName == null)
        tapestryComponentName = currentTapestryComponent.getNodeName().toLowerCase();
      //In condition <t:html.Message
      if(tapestryComponentName.indexOf('.') > -1 && currentTapestryComponent.getPrefix()!= null && currentTapestryComponent.getPrefix().equals("t"))
        tapestryComponentName = tapestryComponentName.substring(2).replace('.', ':');
       
      List<Template> tapestryTemplates = CoreComponentsUtil.getAttributeList(coreList, contextTypeId, tapestryComponentName);
      if(tapestryTemplates == null || tapestryTemplates.size() ==0)
        tapestryTemplates = tapestryRootComponentsProposalComputer.getRootComponentsAttributes(project, contextTypeId, tapestryComponentName);
      if(tapestryTemplates == null || tapestryTemplates.size() ==0)
        tapestryTemplates = tapestryRootComponentsProposalComputer.getCustomComponentsAttributes(project, contextTypeId, tapestryComponentName, tapestryClassLoader);
     
      return tapestryTemplates == null ? null : tapestryTemplates.toArray(new Template[0]);
    }else if(contextTypeId.equals(TapestryElementCollection.attributesValueContextTypeId)){
      List<Template> tapestryTemplates = null;
      if(isComponentTypeContentAssist(node, offset)){
        tapestryTemplates = CoreComponentsUtil.getTapestryComponentNameList(coreList, contextTypeId);
        List<Template> rootComponents = tapestryRootComponentsProposalComputer.getRootComponentsNameTemplates(this.getCurrentProject(), contextTypeId);
        if(rootComponents != null && rootComponents.size() > 0)
          tapestryTemplates.addAll(rootComponents);
        List<Template> customComponents = tapestryRootComponentsProposalComputer.getCustomComponentsNameTemplates(this.getCurrentProject(), contextTypeId);
        if(customComponents != null && customComponents.size() > 0)
          tapestryTemplates.addAll(customComponents);
      }else if(isComponentContentassist(node, offset)){
        tapestryTemplates = TapestryComponentCompletionProposalComputer.getInstance().computeCompletionProposals("", node, offset);
      }else{
        tapestryTemplates = collection.getAttributeValueList(contextTypeId, currentTapestryComponent);
      }
      return tapestryTemplates == null ? null : tapestryTemplates.toArray(new Template[0]);
    }
    else{
      Template templates[] = null;
      TemplateStore store = getTemplateStore();
      if (store != null) {
        templates = store.getTemplates(contextTypeId);
      }

      return templates;
    }
  }
 
  /**
   * Get component name such as "ActionLink" in this condition <a t:type="ActionLink"></a>
   *
   * @param node
   * @return
   */
  private String getTapestryComponentName(IDOMNode node){
    NamedNodeMap attributes = node.getAttributes();
    if(attributes != null && attributes.getLength() > 0){
      for(int i=0; i<attributes.getLength(); i++){
        if(attributes.item(i).getNodeName().equals("t:type")){
          String value = attributes.item(i).getNodeValue();
          if(value.indexOf('/') > -1){
            return value.replace('/', ':').toLowerCase();
          }else
            return "t:" + value.toLowerCase();
        }
      }
    }
    return null;
  }
 
  //Decide whether in condition <span t:id="
  private boolean isComponentContentassist(IDOMNode node, int offset){
    int sp=0, ep=0;
    for (int i = offset - node.getStartOffset() - 1; i >= 0; i--) {
      char temp = node.getSource().charAt(i);
      if(ep ==0 && temp == '=')
        ep = i;
      else if(sp ==0 && temp == ' ')
        sp = i;
      if(sp != 0 && ep != 0)
        break;
    }
    if(sp == 0 || ep == 0)
      return false;
    else{
      if(node.getSource().substring(sp, ep).trim().equals("t:id"))
        return true;
      else
        return false;
    }
  }
 
  //Decide whether in condition <a t:type=""></a>
  private boolean isComponentTypeContentAssist(IDOMNode node, int offset){
    int sp=0, ep=0;
    for (int i = offset - node.getStartOffset() - 1; i >= 0; i--) {
      char temp = node.getSource().charAt(i);
      if(ep ==0 && temp == '=')
        ep = i;
      else if(sp ==0 && temp == ' ')
        sp = i;
      if(sp != 0 && ep != 0)
        break;
    }
    if(sp == 0 || ep == 0)
      return false;
    else{
      if(node.getSource().substring(sp, ep).trim().equals("t:type"))
        return true;
      else
        return false;
    }
  }

  private TemplateStore getTemplateStore() {
    return XMLUIPlugin.getDefault().getTemplateStore();
  }

  void setContextType(String contextTypeId) {
    fContextTypeId = contextTypeId;
  }


}
TOP

Related Classes of org.eclipse.wst.xml.ui.internal.contentassist.XMLTemplateCompletionProcessor

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.