@Override
  protected ContentAssistRequest computeCompletionProposals(
      String matchString,
      ITextRegion completionRegion,
      IDOMNode treeNode,
      IDOMNode xmlnode,
      CompletionProposalInvocationContext context) {
    ContentAssistRequest contentAssistRequest =
        super.computeCompletionProposals(matchString, completionRegion, treeNode, xmlnode, context);
    if (contentAssistRequest != null) return contentAssistRequest;

    String regionType = completionRegion.getType();
    if (DOMRegionContext.XML_CDATA_TEXT.equals(regionType)) {
      Node parentNode = xmlnode.getParentNode();
      Node statementNode = MybatipseXmlUtil.findEnclosingStatementNode(parentNode);
      if (statementNode == null) return null;

      int offset = context.getInvocationOffset();
      ITextViewer viewer = context.getViewer();
      contentAssistRequest =
          new ContentAssistRequest(
              xmlnode,
              parentNode,
              ContentAssistUtils.getStructuredDocumentRegion(viewer, offset),
              completionRegion,
              offset,
              0,
              matchString);
      proposeStatementText(contentAssistRequest, statementNode);
    }
    return contentAssistRequest;
  }
 private void proposeStatementId(
     ContentAssistRequest contentAssistRequest,
     IJavaProject project,
     String matchString,
     int start,
     int length,
     IDOMNode node)
     throws JavaModelException, XPathExpressionException {
   final List<ICompletionProposal> results = new ArrayList<ICompletionProposal>();
   final List<MapperMethodInfo> methodInfos = new ArrayList<MapperMethodInfo>();
   String qualifiedName = MybatipseXmlUtil.getNamespace(node.getOwnerDocument());
   JavaMapperUtil.findMapperMethod(
       methodInfos, project, qualifiedName, matchString, false, new RejectStatementAnnotation());
   for (MapperMethodInfo methodInfo : methodInfos) {
     String methodName = methodInfo.getMethodName();
     results.add(
         new CompletionProposal(
             methodName,
             start,
             length,
             methodName.length(),
             Activator.getIcon(),
             methodName,
             null,
             null));
   }
   addProposals(contentAssistRequest, results);
 }
  @Override
  protected void addTagInsertionProposals(
      ContentAssistRequest contentAssistRequest,
      int childPosition,
      CompletionProposalInvocationContext context) {
    int offset = contentAssistRequest.getReplacementBeginPosition();
    int length = contentAssistRequest.getReplacementLength();
    Node node = contentAssistRequest.getNode();
    // Current node can be 'parent' when the cursor is just before the end tag of the parent.
    Node parentNode = node.getNodeType() == Node.ELEMENT_NODE ? node : node.getParentNode();
    if (parentNode.getNodeType() != Node.ELEMENT_NODE) return;

    String tagName = parentNode.getNodeName();
    NamedNodeMap tagAttrs = parentNode.getAttributes();
    // Result mapping proposals.
    if ("resultMap".equals(tagName))
      generateResults(
          contentAssistRequest, offset, length, parentNode, tagAttrs.getNamedItem("type"));
    else if ("collection".equals(tagName))
      generateResults(
          contentAssistRequest, offset, length, parentNode, tagAttrs.getNamedItem("ofType"));
    else if ("association".equals(tagName))
      generateResults(
          contentAssistRequest, offset, length, parentNode, tagAttrs.getNamedItem("javaType"));

    Node statementNode = MybatipseXmlUtil.findEnclosingStatementNode(parentNode);
    if (statementNode == null) return;
    proposeStatementText(contentAssistRequest, statementNode);
  }
 private IJavaProject getJavaProject(ContentAssistRequest request) {
   if (request != null) {
     IStructuredDocumentRegion region = request.getDocumentRegion();
     if (region != null) {
       IDocument document = region.getParentDocument();
       return MybatipseXmlUtil.getJavaProject(document);
     }
   }
   return null;
 }
 private void proposeProperty(
     ContentAssistRequest contentAssistRequest,
     String matchString,
     int start,
     int length,
     IDOMNode node)
     throws JavaModelException {
   String javaType = MybatipseXmlUtil.findEnclosingType(node);
   if (javaType != null && !MybatipseXmlUtil.isDefaultTypeAlias(javaType)) {
     IJavaProject project = getJavaProject(contentAssistRequest);
     IType type = project.findType(javaType);
     if (type == null) {
       javaType = TypeAliasCache.getInstance().resolveAlias(project, javaType, null);
       if (javaType == null) return;
     }
     addProposals(
         contentAssistRequest,
         ProposalComputorHelper.proposePropertyFor(
             project, start, length, javaType, false, -1, matchString));
   }
 }
  private List<ICompletionProposal> proposeParameter(
      IJavaProject project,
      final int offset,
      final int length,
      Node statementNode,
      final boolean searchReadable,
      final String matchString) {
    List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
    if (statementNode == null) return proposals;
    String statementId = null;
    String paramType = null;
    NamedNodeMap statementAttrs = statementNode.getAttributes();
    for (int i = 0; i < statementAttrs.getLength(); i++) {
      Node attr = statementAttrs.item(i);
      String attrName = attr.getNodeName();
      if ("id".equals(attrName)) statementId = attr.getNodeValue();
      else if ("parameterType".equals(attrName)) paramType = attr.getNodeValue();
    }
    if (statementId == null || statementId.length() == 0) return proposals;

    if (paramType != null) {
      String resolved = TypeAliasCache.getInstance().resolveAlias(project, paramType, null);
      proposals =
          ProposalComputorHelper.proposePropertyFor(
              project,
              offset,
              length,
              resolved != null ? resolved : paramType,
              searchReadable,
              -1,
              matchString);
    } else {
      try {
        final List<MapperMethodInfo> methodInfos = new ArrayList<MapperMethodInfo>();
        String mapperFqn = MybatipseXmlUtil.getNamespace(statementNode.getOwnerDocument());
        JavaMapperUtil.findMapperMethod(
            methodInfos, project, mapperFqn, statementId, true, new RejectStatementAnnotation());
        if (methodInfos.size() > 0) {
          proposals =
              ProposalComputorHelper.proposeParameters(
                  project,
                  offset,
                  length,
                  methodInfos.get(0).getParams(),
                  searchReadable,
                  matchString);
        }
      } catch (XPathExpressionException e) {
        Activator.log(Status.ERROR, e.getMessage(), e);
      }
    }
    return proposals;
  }
 private void proposeMapperNamespace(
     ContentAssistRequest contentAssistRequest, IJavaProject project, int start, int length) {
   String namespace = MybatipseXmlUtil.getNamespaceFromActiveEditor(project);
   ICompletionProposal proposal =
       new CompletionProposal(
           namespace,
           start,
           length,
           namespace.length(),
           Activator.getIcon("/icons/mybatis-ns.png"),
           namespace,
           null,
           null);
   contentAssistRequest.addProposal(proposal);
 }
  protected void addAttributeValueProposals(
      ContentAssistRequest contentAssistRequest, CompletionProposalInvocationContext context) {
    IDOMNode node = (IDOMNode) contentAssistRequest.getNode();
    String tagName = node.getNodeName();
    IStructuredDocumentRegion open = node.getFirstStructuredDocumentRegion();
    ITextRegionList openRegions = open.getRegions();
    int i = openRegions.indexOf(contentAssistRequest.getRegion());
    if (i < 0) return;
    ITextRegion nameRegion = null;
    while (i >= 0) {
      nameRegion = openRegions.get(i--);
      if (nameRegion.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_NAME) break;
    }

    // get the attribute in question (first attr name to the left of the cursor)
    String attributeName = null;
    if (nameRegion != null) attributeName = open.getText(nameRegion);

    ProposalType proposalType = resolveProposalType(tagName, attributeName);
    if (ProposalType.None.equals(proposalType)) {
      return;
    }

    String currentValue = null;
    if (contentAssistRequest.getRegion().getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE)
      currentValue = contentAssistRequest.getText();
    else currentValue = "";

    String matchString = null;
    int matchStrLen = contentAssistRequest.getMatchString().length();
    int start = contentAssistRequest.getReplacementBeginPosition();
    int length = contentAssistRequest.getReplacementLength();
    if (currentValue.length() > StringUtils.strip(currentValue).length()
        && (currentValue.startsWith("\"") || currentValue.startsWith("'"))
        && matchStrLen > 0) {
      // Value is surrounded by (double) quotes.
      matchString = currentValue.substring(1, matchStrLen);
      start++;
      length = currentValue.length() - 2;
      currentValue = currentValue.substring(1, length + 1);
    } else {
      matchString = currentValue.substring(0, matchStrLen);
    }

    IJavaProject project = getJavaProject(contentAssistRequest);
    try {
      switch (proposalType) {
        case Package:
          proposePackage(contentAssistRequest, project, matchString, start, length);
          break;
        case TypeAlias:
          addProposals(
              contentAssistRequest,
              ProposalComputorHelper.proposeJavaType(project, start, length, false, matchString));
          break;
        case ResultType:
          addProposals(
              contentAssistRequest,
              ProposalComputorHelper.proposeJavaType(project, start, length, true, matchString));
          break;
        case ResultProperty:
          proposeProperty(contentAssistRequest, matchString, start, length, node);
          break;
        case TypeHandlerType:
          addProposals(
              contentAssistRequest,
              ProposalComputorHelper.proposeTypeHandler(project, start, length, matchString));
          break;
        case CacheType:
          addProposals(
              contentAssistRequest,
              ProposalComputorHelper.proposeCacheType(project, start, length, matchString));
          break;
        case SettingName:
          addProposals(
              contentAssistRequest,
              ProposalComputorHelper.proposeSettingName(start, length, matchString));
          break;
        case ObjectFactory:
          addProposals(
              contentAssistRequest,
              ProposalComputorHelper.proposeObjectFactory(project, start, length, matchString));
          break;
        case ObjectWrapperFactory:
          addProposals(
              contentAssistRequest,
              ProposalComputorHelper.proposeObjectWrapperFactory(
                  project, start, length, matchString));
          break;
        case StatementId:
          proposeStatementId(contentAssistRequest, project, matchString, start, length, node);
          break;
        case MapperNamespace:
          proposeMapperNamespace(contentAssistRequest, project, start, length);
          break;
        case ResultMap:
          String ownId =
              "resultMap".equals(tagName) && "extends".equals(attributeName)
                  ? XpathUtil.xpathString(node, "@id")
                  : null;
          addProposals(
              contentAssistRequest,
              proposeResultMapReference(
                  project,
                  node.getOwnerDocument(),
                  start,
                  currentValue,
                  matchString.length(),
                  ownId));
          break;
        case Include:
          addProposals(
              contentAssistRequest,
              ProposalComputorHelper.proposeReference(
                  project, node.getOwnerDocument(), matchString, start, length, "sql", null));
          break;
        case SelectId:
          // TODO: include mapper methods with @Select.
          addProposals(
              contentAssistRequest,
              ProposalComputorHelper.proposeReference(
                  project, node.getOwnerDocument(), matchString, start, length, "select", null));
          break;
        case KeyProperty:
          String nodeName = node.getNodeName();
          Node statementNode =
              "update".equals(nodeName) || "insert".equals(nodeName)
                  ? node
                  : MybatipseXmlUtil.findEnclosingStatementNode(node.getParentNode());
          addProposals(
              contentAssistRequest,
              proposeParameter(project, start, length, statementNode, false, matchString));
          break;
        case ParamProperty:
          addProposals(
              contentAssistRequest,
              proposeParameter(
                  project,
                  start,
                  length,
                  MybatipseXmlUtil.findEnclosingStatementNode(node),
                  true,
                  matchString));
          break;
        case ParamPropertyPartial:
          AttrTextParser parser = new AttrTextParser(currentValue, matchString.length());
          addProposals(
              contentAssistRequest,
              proposeParameter(
                  project,
                  start + parser.getMatchStringStart(),
                  parser.getReplacementLength(),
                  MybatipseXmlUtil.findEnclosingStatementNode(node.getParentNode()),
                  true,
                  parser.getMatchString()));
          break;
        default:
          break;
      }
    } catch (Exception e) {
      Activator.log(Status.ERROR, e.getMessage(), e);
    }
  }