| /******************************************************************************* |
| * Copyright (c) 2004 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 |
| *******************************************************************************/ |
| package org.eclipse.jst.jsp.ui.internal.contentassist; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Vector; |
| |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.ITextViewer; |
| import org.eclipse.jface.text.TextUtilities; |
| import org.eclipse.jface.text.contentassist.ICompletionProposal; |
| import org.eclipse.jface.text.contentassist.IContentAssistProcessor; |
| import org.eclipse.jface.text.contentassist.IContextInformation; |
| import org.eclipse.jface.text.contentassist.IContextInformationValidator; |
| import org.eclipse.jst.jsp.core.internal.contentmodel.TaglibController; |
| import org.eclipse.jst.jsp.core.internal.contentmodel.tld.TLDCMDocumentManager; |
| import org.eclipse.jst.jsp.core.internal.document.PageDirectiveAdapter; |
| import org.eclipse.jst.jsp.core.internal.document.PageDirectiveAdapterFactory; |
| import org.eclipse.jst.jsp.core.internal.provisional.JSP11Namespace; |
| import org.eclipse.jst.jsp.core.internal.provisional.JSP12Namespace; |
| import org.eclipse.jst.jsp.core.internal.provisional.contenttype.ContentTypeIdForJSP; |
| import org.eclipse.jst.jsp.core.internal.provisional.text.IJSPPartitionTypes; |
| import org.eclipse.jst.jsp.core.internal.regions.DOMJSPRegionContexts; |
| import org.eclipse.jst.jsp.ui.internal.JSPUIPlugin; |
| import org.eclipse.jst.jsp.ui.internal.Logger; |
| import org.eclipse.jst.jsp.ui.internal.editor.JSPEditorPluginImageHelper; |
| import org.eclipse.jst.jsp.ui.internal.editor.JSPEditorPluginImages; |
| import org.eclipse.jst.jsp.ui.internal.preferences.JSPUIPreferenceNames; |
| import org.eclipse.jst.jsp.ui.internal.templates.TemplateContextTypeIdsJSP; |
| import org.eclipse.wst.css.ui.internal.contentassist.CSSContentAssistProcessor; |
| import org.eclipse.wst.html.core.internal.contentmodel.HTMLCMDocumentFactory; |
| import org.eclipse.wst.html.core.internal.contentmodel.HTMLElementDeclaration; |
| import org.eclipse.wst.html.core.internal.contentmodel.JSPCMDocument; |
| import org.eclipse.wst.html.core.internal.provisional.HTMLCMProperties; |
| import org.eclipse.wst.html.core.internal.provisional.text.IHTMLPartitionTypes; |
| import org.eclipse.wst.html.ui.internal.contentassist.HTMLContentAssistProcessor; |
| import org.eclipse.wst.javascript.ui.internal.common.contentassist.JavaScriptContentAssistProcessor; |
| import org.eclipse.wst.sse.core.internal.ltk.parser.BlockMarker; |
| import org.eclipse.wst.sse.core.internal.provisional.IModelManager; |
| import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier; |
| import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; |
| import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; |
| import org.eclipse.wst.sse.core.internal.provisional.StructuredModelManager; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredPartitionTypes; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredPartitioning; |
| import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; |
| import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionContainer; |
| import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList; |
| import org.eclipse.wst.sse.core.internal.util.StringUtils; |
| import org.eclipse.wst.sse.ui.internal.IReleasable; |
| import org.eclipse.wst.sse.ui.internal.StructuredTextViewer; |
| import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils; |
| import org.eclipse.wst.sse.ui.internal.contentassist.CustomCompletionProposal; |
| import org.eclipse.wst.sse.ui.internal.contentassist.IRelevanceCompletionProposal; |
| import org.eclipse.wst.sse.ui.internal.contentassist.IRelevanceConstants; |
| import org.eclipse.wst.sse.ui.internal.contentassist.IResourceDependentProcessor; |
| import org.eclipse.wst.sse.ui.internal.provisional.registry.AdapterFactoryProvider; |
| import org.eclipse.wst.sse.ui.internal.provisional.registry.AdapterFactoryRegistry; |
| import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument; |
| import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration; |
| import org.eclipse.wst.xml.core.internal.contentmodel.CMNamedNodeMap; |
| import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.ModelQuery; |
| import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.ModelQueryAction; |
| import org.eclipse.wst.xml.core.internal.modelquery.ModelQueryUtil; |
| import org.eclipse.wst.xml.core.internal.parser.XMLSourceParser; |
| import org.eclipse.wst.xml.core.internal.provisional.contentmodel.CMDocType; |
| import org.eclipse.wst.xml.core.internal.provisional.contentmodel.CMDocumentTracker; |
| import org.eclipse.wst.xml.core.internal.provisional.contentmodel.CMNodeWrapper; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; |
| import org.eclipse.wst.xml.core.internal.provisional.text.IXMLPartitions; |
| import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext; |
| import org.eclipse.wst.xml.core.internal.ssemodelquery.ModelQueryAdapter; |
| import org.eclipse.wst.xml.ui.internal.contentassist.AbstractContentAssistProcessor; |
| import org.eclipse.wst.xml.ui.internal.contentassist.ContentAssistRequest; |
| import org.eclipse.wst.xml.ui.internal.contentassist.NonValidatingModelQueryAction; |
| import org.eclipse.wst.xml.ui.internal.contentassist.ProposalComparator; |
| import org.eclipse.wst.xml.ui.internal.contentassist.XMLContentAssistProcessor; |
| import org.eclipse.wst.xml.ui.internal.contentassist.XMLContentAssistUtilities; |
| import org.eclipse.wst.xml.ui.internal.contentassist.XMLRelevanceConstants; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| |
| /** |
| * Adds proposals not normally covered by the generic behavior with the |
| * content model |
| * |
| * @plannedfor 1.0 |
| */ |
| public class JSPContentAssistProcessor extends AbstractContentAssistProcessor implements IResourceDependentProcessor { |
| |
| protected int depthCount = 0; |
| protected ITextViewer fViewer = null; |
| protected boolean useEmbeddedResults = true; |
| protected boolean isInternalAdapter = false; |
| protected HashMap fNameToProcessorMap = null; |
| protected HashMap fPartitionToProcessorMap = null; |
| private final ICompletionProposal[] EMPTY_PROPOSAL_SET = new ICompletionProposal[0]; |
| protected IResource fResource = null; |
| private JSPTemplateCompletionProcessor fTemplateProcessor = null; |
| private List fTemplateContexts = new ArrayList(); |
| |
| public JSPContentAssistProcessor() { |
| super(); |
| initNameToProcessorMap(); |
| initPartitionToProcessorMap(); |
| } |
| |
| /** |
| * init map for extra content assist processors (useBean, |
| * get/setProperty). points [tagname > processor] |
| */ |
| protected void initNameToProcessorMap() { |
| fNameToProcessorMap = new HashMap(); |
| JSPPropertyContentAssistProcessor jspPropertyCAP = new JSPPropertyContentAssistProcessor(); |
| fNameToProcessorMap.put(JSP11Namespace.ElementName.SETPROPERTY, jspPropertyCAP); |
| fNameToProcessorMap.put(JSP11Namespace.ElementName.GETPROPERTY, jspPropertyCAP); |
| fNameToProcessorMap.put(JSP11Namespace.ElementName.USEBEAN, new JSPUseBeanContentAssistProcessor()); |
| } |
| |
| /** |
| * int map that points [partition > processor]. This takes place of |
| * embedded adapters for now. |
| */ |
| protected void initPartitionToProcessorMap() { |
| fPartitionToProcessorMap = new HashMap(); |
| HTMLContentAssistProcessor htmlProcessor = new HTMLContentAssistProcessor(); |
| JSPJavaContentAssistProcessor jspJavaProcessor = new JSPJavaContentAssistProcessor(); |
| XMLContentAssistProcessor xmlProcessor = new XMLContentAssistProcessor(); |
| JavaScriptContentAssistProcessor javascriptProcessor = new JavaScriptContentAssistProcessor(); |
| |
| fPartitionToProcessorMap.put(IHTMLPartitionTypes.HTML_DEFAULT, htmlProcessor); |
| fPartitionToProcessorMap.put(IXMLPartitions.XML_DEFAULT, xmlProcessor); |
| fPartitionToProcessorMap.put(IStructuredPartitionTypes.DEFAULT_PARTITION, htmlProcessor); |
| fPartitionToProcessorMap.put(IJSPPartitionTypes.JSP_DEFAULT, jspJavaProcessor); |
| fPartitionToProcessorMap.put(IJSPPartitionTypes.JSP_DIRECTIVE, xmlProcessor); |
| fPartitionToProcessorMap.put(IHTMLPartitionTypes.HTML_COMMENT, htmlProcessor); |
| fPartitionToProcessorMap.put(IJSPPartitionTypes.JSP_CONTENT_JAVASCRIPT, javascriptProcessor); |
| fPartitionToProcessorMap.put(IJSPPartitionTypes.JSP_DEFAULT_EL, jspJavaProcessor); |
| fPartitionToProcessorMap.put(IHTMLPartitionTypes.SCRIPT, javascriptProcessor); // default |
| // to |
| // javascript |
| // for |
| // all |
| // script |
| } |
| |
| protected void addCommentProposal(ContentAssistRequest contentAssistRequest) { |
| // do nothing |
| } |
| |
| protected void addDocTypeProposal(ContentAssistRequest contentAssistRequest) { |
| // do nothing |
| } |
| |
| protected void addEmptyDocumentProposals(ContentAssistRequest contentAssistRequest) { |
| addTemplates(contentAssistRequest, TemplateContextTypeIdsJSP.NEW); |
| |
| super.addEmptyDocumentProposals(contentAssistRequest); |
| addTagInsertionProposals(contentAssistRequest, 0); |
| } |
| |
| protected void addEndTagNameProposals(ContentAssistRequest contentAssistRequest) { |
| // do nothing |
| } |
| |
| protected void addPCDATAProposal(String nodeName, ContentAssistRequest contentAssistRequest) { |
| // do nothing |
| } |
| |
| protected void addStartDocumentProposals(ContentAssistRequest contentAssistRequest) { |
| // do nothing |
| } |
| |
| protected void addTagCloseProposals(ContentAssistRequest contentAssistRequest) { |
| // do nothing |
| } |
| |
| protected void addXMLProposal(ContentAssistRequest contentAssistRequest) { |
| // do nothing |
| } |
| |
| protected void addEndTagProposals(ContentAssistRequest contentAssistRequest) { |
| // do nothing |
| } |
| |
| protected void addAttributeNameProposals(ContentAssistRequest contentAssistRequest) { |
| addTemplates(contentAssistRequest, TemplateContextTypeIdsJSP.ATTRIBUTE); |
| |
| // specific fix for CMVC 274033 |
| // no attribute proposals for <jsp:useBean /> |
| String nodeName = contentAssistRequest.getNode().getNodeName(); |
| if (nodeName.indexOf(':') != -1) { //$NON-NLS-1$ |
| super.addAttributeNameProposals(contentAssistRequest); |
| } |
| } |
| |
| /** |
| * add proposals for tags in attribute values |
| */ |
| protected void addAttributeValueProposals(ContentAssistRequest contentAssistRequest) { |
| addTemplates(contentAssistRequest, TemplateContextTypeIdsJSP.ATTRIBUTE_VALUE); |
| |
| IDOMNode node = (IDOMNode) contentAssistRequest.getNode(); |
| |
| // add JSP extra proposals from JSPBeanInfoContentAssistProcessor |
| // JSPPropertyContentAssistProcessor |
| |
| // 2.1 |
| // get results from JSPUseBean and JSPProperty here |
| // (look up processor in a map based on node name) |
| JSPDummyContentAssistProcessor extraProcessor = (JSPDummyContentAssistProcessor) fNameToProcessorMap.get(node.getNodeName()); |
| if (extraProcessor != null && contentAssistRequest != null) { |
| extraProcessor.initialize(fResource); |
| extraProcessor.addAttributeValueProposals(contentAssistRequest); |
| } |
| |
| ModelQuery mq = ModelQueryUtil.getModelQuery(node.getOwnerDocument()); |
| if (mq != null) { |
| CMDocument doc = mq.getCorrespondingCMDocument(node); |
| // this shouldn't have to have the prefix coded in |
| if (doc instanceof JSPCMDocument || doc instanceof CMNodeWrapper || node.getNodeName().startsWith("jsp:")) //$NON-NLS-1$ |
| return; |
| } |
| |
| // Find the attribute name for which this position should have a value |
| 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; |
| } |
| |
| String attributeName = null; |
| if (nameRegion != null) |
| attributeName = open.getText(nameRegion); |
| String currentValue = null; |
| if (attributeName != null) |
| currentValue = node.getAttributes().getNamedItem(attributeName).getNodeValue(); |
| |
| // on an empty value, add all the JSP and taglib tags |
| if ((contentAssistRequest.getRegion().getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_EQUALS && contentAssistRequest.getReplacementLength() == 0) || (contentAssistRequest.getRegion().getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE && (currentValue == null || currentValue.length() == 0))) { |
| List rejectElements = new ArrayList(); |
| rejectElements.add(JSP12Namespace.ElementName.SCRIPTLET); |
| rejectElements.add(JSP12Namespace.ElementName.EXPRESSION); |
| rejectElements.add(JSP12Namespace.ElementName.DECLARATION); |
| rejectElements.add(JSP12Namespace.ElementName.DIRECTIVE_INCLUDE); |
| rejectElements.add(JSP12Namespace.ElementName.DIRECTIVE_PAGE); |
| rejectElements.add(JSP12Namespace.ElementName.DIRECTIVE_TAGLIB); |
| rejectElements.add(JSP12Namespace.ElementName.FALLBACK); |
| rejectElements.add(JSP12Namespace.ElementName.USEBEAN); |
| rejectElements.add(JSP12Namespace.ElementName.SETPROPERTY); |
| rejectElements.add(JSP12Namespace.ElementName.FORWARD); |
| rejectElements.add(JSP12Namespace.ElementName.PLUGIN); |
| rejectElements.add(JSP12Namespace.ElementName.FALLBACK); |
| rejectElements.add(JSP12Namespace.ElementName.PARAMS); |
| |
| List additionalElements = getAdditionalChildren(new ArrayList(), node, -1); |
| for (i = 0; i < additionalElements.size(); i++) { |
| CMElementDeclaration ed = (CMElementDeclaration) additionalElements.get(i); |
| if (rejectElements.contains(ed.getNodeName())) |
| continue; |
| String tagname = getContentGenerator().getRequiredName(node, ed); |
| StringBuffer contents = new StringBuffer("\""); //$NON-NLS-1$ |
| getContentGenerator().generateTag(node, ed, contents); |
| contents.append('"'); |
| CustomCompletionProposal proposal = new CustomCompletionProposal(contents.toString(), contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), contents.length(), JSPEditorPluginImageHelper.getInstance().getImage(JSPEditorPluginImages.IMG_OBJ_TAG_GENERIC), tagname, null, null, XMLRelevanceConstants.R_JSP_ATTRIBUTE_VALUE); |
| contentAssistRequest.addProposal(proposal); |
| } |
| } |
| |
| else if (contentAssistRequest.getRegion().getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE) { |
| try { |
| // Create a new model for Content Assist to operate on. This |
| // will simulate |
| // a full Document and then adjust the offset numbers in the |
| // list of results. |
| IStructuredModel internalModel = null; |
| IModelManager mmanager = StructuredModelManager.getModelManager(); |
| internalModel = mmanager.createUnManagedStructuredModelFor(ContentTypeIdForJSP.ContentTypeID_JSP); |
| IDOMNode xmlNode = null; |
| IDOMModel xmlOuterModel = null; |
| if (contentAssistRequest.getNode() instanceof IDOMNode) { |
| xmlNode = (IDOMNode) contentAssistRequest.getNode(); |
| xmlOuterModel = xmlNode.getModel(); |
| internalModel.setResolver(xmlOuterModel.getResolver()); |
| internalModel.setBaseLocation(xmlOuterModel.getBaseLocation()); |
| } |
| String contents = StringUtils.strip(contentAssistRequest.getText()); |
| if (xmlNode != null && contents != null) { |
| int additionalShifts = 0; |
| // Be sure that custom tags from taglibs also show up |
| // by |
| // adding taglib declarations to the internal model. |
| TLDCMDocumentManager mgr = TaglibController.getTLDCMDocumentManager(xmlOuterModel.getStructuredDocument()); |
| if (mgr != null) { |
| List trackers = mgr.getCMDocumentTrackers(contentAssistRequest.getReplacementBeginPosition()); |
| if (trackers != null) { |
| for (i = 0; i < trackers.size(); i++) { |
| CMDocumentTracker tracker = (CMDocumentTracker) trackers.get(i); |
| String declaration = tracker.getStructuredDocumentRegion().getText(); |
| if (declaration != null) { |
| contents = declaration + contents; |
| additionalShifts += declaration.length(); |
| } |
| } |
| } |
| } |
| // Also copy any jsp:useBean tags so that |
| // jsp:[gs]etProperty will function |
| Document doc = null; |
| if (contentAssistRequest.getNode().getNodeType() == Node.DOCUMENT_NODE) |
| doc = (Document) node; |
| else |
| doc = node.getOwnerDocument(); |
| NodeList useBeans = doc.getElementsByTagName(JSP12Namespace.ElementName.USEBEAN); |
| for (int k = 0; k < useBeans.getLength(); k++) { |
| IDOMNode useBean = (IDOMNode) useBeans.item(k); |
| if (useBean.getStartOffset() < contentAssistRequest.getReplacementBeginPosition()) { |
| StringBuffer useBeanText = new StringBuffer("<jsp:useBean"); //$NON-NLS-1$ |
| for (int j = 0; j < useBean.getAttributes().getLength(); j++) { |
| Attr attr = (Attr) useBean.getAttributes().item(j); |
| useBeanText.append(' '); |
| useBeanText.append(attr.getName()); |
| useBeanText.append("=\""); //$NON-NLS-1$ |
| useBeanText.append(attr.getValue()); |
| useBeanText.append('"'); |
| } |
| useBeanText.append("/>"); //$NON-NLS-1$ |
| additionalShifts += useBeanText.length(); |
| contents = useBeanText.toString() + contents; |
| } |
| } |
| internalModel.getStructuredDocument().set(contents); |
| int internalOffset = 0; |
| boolean quoted = false; |
| // if quoted, use position inside and shift by one |
| if (contentAssistRequest.getMatchString().length() > 0 && (contentAssistRequest.getMatchString().charAt(0) == '\'' || contentAssistRequest.getMatchString().charAt(0) == '"')) { |
| internalOffset = contentAssistRequest.getMatchString().length() - 1 + additionalShifts; |
| quoted = true; |
| } |
| // if unquoted, use position inside |
| else if (contentAssistRequest.getMatchString().length() > 0 && contentAssistRequest.getMatchString().charAt(0) == '<') |
| internalOffset = contentAssistRequest.getMatchString().length() + additionalShifts; |
| else |
| internalOffset = contentAssistRequest.getReplacementBeginPosition() - contentAssistRequest.getStartOffset() + additionalShifts; |
| depthCount++; |
| IndexedRegion internalNode = null; |
| int tmpOffset = internalOffset; |
| while (internalNode == null && tmpOffset >= 0) |
| internalNode = internalModel.getIndexedRegion(tmpOffset--); |
| |
| if (internalModel.getFactoryRegistry() != null) { |
| // set up the internal model |
| if (internalModel.getFactoryRegistry().getFactoryFor(PageDirectiveAdapter.class) == null) { |
| internalModel.getFactoryRegistry().addFactory(new PageDirectiveAdapterFactory()); |
| } |
| PageDirectiveAdapter outerEmbeddedTypeAdapter = (PageDirectiveAdapter) xmlOuterModel.getDocument().getAdapterFor(PageDirectiveAdapter.class); |
| PageDirectiveAdapter internalEmbeddedTypeAdapter = (PageDirectiveAdapter) ((INodeNotifier) ((Node) internalNode).getOwnerDocument()).getAdapterFor(PageDirectiveAdapter.class); |
| internalEmbeddedTypeAdapter.setEmbeddedType(outerEmbeddedTypeAdapter.getEmbeddedType()); |
| } |
| |
| AdapterFactoryRegistry adapterRegistry = JSPUIPlugin.getDefault().getAdapterFactoryRegistry(); |
| Iterator adapterList = adapterRegistry.getAdapterFactories(); |
| // And all those appropriate for this particular type |
| // of content |
| while (adapterList.hasNext()) { |
| try { |
| AdapterFactoryProvider provider = (AdapterFactoryProvider) adapterList.next(); |
| if (provider.isFor(internalModel.getModelHandler())) { |
| provider.addAdapterFactories(internalModel); |
| } |
| } catch (Exception e) { |
| Logger.logException(e); |
| } |
| } |
| |
| /** |
| * the internal adapter does all the real work of using |
| * the JSP content model to form proposals |
| */ |
| ICompletionProposal[] results = null; |
| depthCount--; |
| if (results != null) { |
| for (i = 0; i < results.length; i++) { |
| contentAssistRequest.addProposal(new CustomCompletionProposal(((CustomCompletionProposal) results[i]).getReplacementString(), ((CustomCompletionProposal) results[i]).getReplacementOffset() - additionalShifts + contentAssistRequest.getStartOffset() + (quoted ? 1 : 0), ((CustomCompletionProposal) results[i]).getReplacementLength(), ((CustomCompletionProposal) results[i]).getCursorPosition(), results[i].getImage(), results[i].getDisplayString(), ((CustomCompletionProposal) results[i]).getContextInformation(), ((CustomCompletionProposal) results[i]).getAdditionalProposalInfo(), (results[i] instanceof IRelevanceCompletionProposal) ? ((IRelevanceCompletionProposal) results[i]).getRelevance() : IRelevanceConstants.R_NONE)); |
| } |
| } |
| } |
| } catch (Exception e) { |
| Logger.logException("Error in embedded JSP Content Assist", e); //$NON-NLS-1$ |
| } |
| } |
| |
| |
| } |
| |
| private List getAdditionalChildren(List elementDecls, Node node, int childIndex) { |
| if (node instanceof IDOMNode) { |
| /* |
| * find the location of the intended insertion as it will give us |
| * the correct offset for checking position dependent CMDocuments |
| */ |
| int textInsertionOffset = 0; |
| NodeList children = node.getChildNodes(); |
| if (children.getLength() >= childIndex && childIndex >= 0) { |
| Node nodeAlreadyAtIndex = children.item(childIndex); |
| if (nodeAlreadyAtIndex instanceof IDOMNode) |
| textInsertionOffset = ((IDOMNode) nodeAlreadyAtIndex).getEndOffset(); |
| } else { |
| textInsertionOffset = ((IDOMNode) node).getStartOffset(); |
| } |
| TLDCMDocumentManager mgr = TaglibController.getTLDCMDocumentManager(((IDOMNode) node).getStructuredDocument()); |
| if (mgr != null) { |
| List moreCMDocuments = mgr.getCMDocumentTrackers(textInsertionOffset); |
| if (moreCMDocuments != null) { |
| for (int i = 0; i < moreCMDocuments.size(); i++) { |
| CMDocument doc = (CMDocument) moreCMDocuments.get(i); |
| CMNamedNodeMap elements = doc.getElements(); |
| if (elements != null) { |
| for (int j = 0; j < elements.getLength(); j++) { |
| CMElementDeclaration ed = (CMElementDeclaration) elements.item(j); |
| elementDecls.add(ed); |
| } |
| } |
| } |
| } |
| } |
| |
| // get position dependent CMDocuments and insert their tags as |
| // proposals |
| |
| ModelQueryAdapter mqAdapter = null; |
| if (node.getNodeType() == Node.DOCUMENT_NODE) |
| mqAdapter = (ModelQueryAdapter) ((IDOMNode) node).getAdapterFor(ModelQueryAdapter.class); |
| else |
| mqAdapter = (ModelQueryAdapter) ((IDOMNode) node.getOwnerDocument()).getAdapterFor(ModelQueryAdapter.class); |
| |
| if (mqAdapter != null) { |
| CMDocument doc = mqAdapter.getModelQuery().getCorrespondingCMDocument(node); |
| // this shouldn't have to have the prefix coded in |
| if (!(doc != null && (doc instanceof JSPCMDocument || doc instanceof CMNodeWrapper || node.getNodeName().startsWith("jsp:")))) { //$NON-NLS-1$ |
| // get jsp namespace elements and insert their contents |
| CMDocument JCMDoc = HTMLCMDocumentFactory.getCMDocument(CMDocType.JSP11_DOC_TYPE); |
| CMNamedNodeMap jspelements = JCMDoc.getElements(); |
| |
| if (jspelements != null) { |
| List rejectElements = new ArrayList(); |
| |
| // determine if the document is in XML form |
| Document domDoc = null; |
| if (node.getNodeType() == Node.DOCUMENT_NODE) |
| domDoc = (Document) node; |
| else |
| domDoc = node.getOwnerDocument(); |
| // Show XML tag forms of JSP markers if jsp:root is |
| // the document element OR it's HTML but |
| // isn't really in the text. |
| // If the document isn't strictly XML, pull out the |
| // XML tag forms |
| if (!isXMLFormat(domDoc)) { |
| rejectElements.add(JSP12Namespace.ElementName.SCRIPTLET); |
| rejectElements.add(JSP12Namespace.ElementName.EXPRESSION); |
| rejectElements.add(JSP12Namespace.ElementName.DECLARATION); |
| rejectElements.add(JSP12Namespace.ElementName.DIRECTIVE_INCLUDE); |
| rejectElements.add(JSP12Namespace.ElementName.DIRECTIVE_PAGE); |
| rejectElements.add(JSP12Namespace.ElementName.TEXT); |
| } |
| // always exclude jsp:directive.taglib |
| if (isInternalAdapter) { |
| rejectElements.add(JSP12Namespace.ElementName.DIRECTIVE_TAGLIB); |
| rejectElements.add(JSP12Namespace.ElementName.DIRECTIVE_TAGLIB); |
| rejectElements.add(JSP12Namespace.ElementName.FALLBACK); |
| rejectElements.add(JSP12Namespace.ElementName.USEBEAN); |
| rejectElements.add(JSP12Namespace.ElementName.SETPROPERTY); |
| rejectElements.add(JSP12Namespace.ElementName.FORWARD); |
| rejectElements.add(JSP12Namespace.ElementName.PLUGIN); |
| rejectElements.add(JSP12Namespace.ElementName.FALLBACK); |
| rejectElements.add(JSP12Namespace.ElementName.PARAMS); |
| } |
| |
| // don't show jsp:root if a document element already |
| // exists |
| Element docElement = domDoc.getDocumentElement(); |
| if (docElement != null && ((docElement.getNodeName().equals("jsp:root")) || ((((IDOMNode) docElement).getStartStructuredDocumentRegion() != null || ((IDOMNode) docElement).getEndStructuredDocumentRegion() != null)))) //$NON-NLS-1$ |
| rejectElements.add(JSP12Namespace.ElementName.ROOT); |
| |
| for (int j = 0; j < jspelements.getLength(); j++) { |
| CMElementDeclaration ed = (CMElementDeclaration) jspelements.item(j); |
| if (rejectElements.contains(ed.getNodeName())) |
| continue; |
| elementDecls.add(ed); |
| } |
| } |
| } |
| } |
| } |
| return elementDecls; |
| } |
| |
| protected List getAvailableChildrenAtIndex(Element parent, int index) { |
| List list = new ArrayList(); |
| List additionalElements = getAdditionalChildren(new ArrayList(), parent, index); |
| for (int i = 0; i < additionalElements.size(); i++) { |
| ModelQueryAction insertAction = new NonValidatingModelQueryAction((CMElementDeclaration) additionalElements.get(i), ModelQueryAction.INSERT, 0, parent.getChildNodes().getLength(), null); |
| list.add(insertAction); |
| } |
| |
| // add allowed children of implicit tags that don't already exist |
| NodeList children = parent.getChildNodes(); |
| List childNames = new ArrayList(); |
| if (children != null) { |
| for (int i = 0; i < children.getLength(); i++) { |
| Node child = children.item(i); |
| if (child.getNodeType() == Node.ELEMENT_NODE) |
| childNames.add(child.getNodeName().toLowerCase()); |
| } |
| } |
| List allActions = new ArrayList(); |
| Iterator iterator = list.iterator(); |
| ModelQuery modelQuery = ModelQueryUtil.getModelQuery(parent.getOwnerDocument()); |
| while (iterator.hasNext()) { |
| ModelQueryAction action = (ModelQueryAction) iterator.next(); |
| allActions.add(action); |
| if (action.getCMNode() instanceof HTMLElementDeclaration) { |
| HTMLElementDeclaration ed = (HTMLElementDeclaration) action.getCMNode(); |
| String ommission = (String) ed.getProperty(HTMLCMProperties.OMIT_TYPE); |
| if (!childNames.contains(ed.getNodeName().toLowerCase()) && ((ommission != null) && (ommission.equals(HTMLCMProperties.Values.OMIT_BOTH)))) { |
| List implicitValidActions = new ArrayList(); |
| modelQuery.getInsertActions(parent, ed, 0, ModelQuery.INCLUDE_CHILD_NODES, ModelQuery.VALIDITY_NONE, implicitValidActions); |
| if (implicitValidActions != null) { |
| Iterator implicitValidActionsIterator = implicitValidActions.iterator(); |
| while (implicitValidActionsIterator.hasNext()) { |
| ModelQueryAction insertAction = new NonValidatingModelQueryAction(((ModelQueryAction) implicitValidActionsIterator.next()).getCMNode(), ModelQueryAction.INSERT, 0, parent.getChildNodes().getLength(), null); |
| allActions.add(insertAction); |
| } |
| } |
| } |
| } |
| } |
| return allActions; |
| } |
| |
| protected List getAvailableRootChildren(Document document, int childIndex) { |
| List list = new ArrayList(); |
| if (!isXMLFormat(document)) |
| getAdditionalChildren(list, document, childIndex); |
| return list; |
| } |
| |
| protected void init() { |
| super.init(); |
| } |
| |
| public void setErrorMessage(String errorMessage) { |
| if (depthCount == 0) |
| fErrorMessage = errorMessage; |
| } |
| |
| /** |
| * This method is acting as a "catch all" for pulling together content |
| * assist proposals from different Processors when document partitioning |
| * alone couldn't determine definitively what content assist should show |
| * up at that particular position in the document |
| * |
| * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeCompletionProposals(ITextViewer, |
| * int) |
| */ |
| public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int documentPosition) { |
| fTemplateContexts.clear(); |
| |
| IStructuredDocumentRegion sdRegion = ContentAssistUtils.getStructuredDocumentRegion((StructuredTextViewer) viewer, documentPosition); |
| fViewer = viewer; |
| ICompletionProposal[] jspResults = EMPTY_PROPOSAL_SET; |
| ICompletionProposal[] embeddedResults = EMPTY_PROPOSAL_SET; |
| |
| // check the actual partition type |
| String partitionType = getPartitionType((StructuredTextViewer) viewer, documentPosition); |
| IStructuredDocument structuredDocument = (IStructuredDocument)viewer.getDocument(); |
| |
| IStructuredDocumentRegion fn = structuredDocument.getRegionAtCharacterOffset(documentPosition); |
| |
| // //////////////////////////////////////////////////////////////////////////// |
| // ANOTHER WORKAROUND UNTIL PARTITIONING TAKES CARE OF THIS |
| // check for xml-jsp tags... |
| // CMVC 243657 |
| if (partitionType == IJSPPartitionTypes.JSP_DIRECTIVE && fn != null) { |
| IStructuredDocumentRegion possibleXMLJSP = ((fn.getType() == DOMRegionContext.XML_CONTENT) && fn.getPrevious() != null) ? fn.getPrevious() : fn; |
| ITextRegionList regions = possibleXMLJSP.getRegions(); |
| if (regions.size() > 1) { |
| // check bounds cases |
| ITextRegion xmlOpenOrClose = regions.get(0); |
| if (xmlOpenOrClose.getType() == DOMRegionContext.XML_TAG_OPEN && documentPosition == possibleXMLJSP.getStartOffset()) { |
| // do regular jsp content assist |
| } else if (xmlOpenOrClose.getType() == DOMRegionContext.XML_END_TAG_OPEN && documentPosition > possibleXMLJSP.getStartOffset()) { |
| // do regular jsp content assist |
| } else { |
| // possible xml-jsp |
| ITextRegion nameRegion = regions.get(1); |
| String name = possibleXMLJSP.getText(nameRegion); |
| if (name.equals("jsp:scriptlet") || name.equals("jsp:expression") || name.equals("jsp:declaration")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| return getJSPJavaCompletionProposals(viewer, documentPosition); |
| } |
| } |
| } |
| } |
| |
| // //////////////////////////////////////////////////////////////////////////// |
| // ** THIS IS A TEMP FIX UNTIL PARTITIONING TAKES CARE OF THIS... |
| // CMVC 241882 |
| // check for XML-JSP in a <script> region |
| if (partitionType == IJSPPartitionTypes.JSP_CONTENT_JAVASCRIPT || partitionType == IHTMLPartitionTypes.SCRIPT) { |
| // fn should be block text |
| IStructuredDocumentRegion decodedSDRegion = decodeScriptBlock(fn.getFullText()); |
| // System.out.println("decoded > " + |
| // blockOfText.substring(decodedSDRegion.getStartOffset(), |
| // decodedSDRegion.getEndOffset())); |
| if (decodedSDRegion != null) { |
| IStructuredDocumentRegion sdr = decodedSDRegion; |
| while (sdr != null) { |
| // System.out.println("sdr " + sdr.getType()); |
| // System.out.println("sdr > " + |
| // blockOfText.substring(sdr.getStartOffset(), |
| // sdr.getEndOffset())); |
| if (sdr.getType() == DOMJSPRegionContexts.JSP_CONTENT) { |
| if (documentPosition >= fn.getStartOffset() + sdr.getStartOffset() && documentPosition <= fn.getStartOffset() + sdr.getEndOffset()) { |
| return getJSPJavaCompletionProposals(viewer, documentPosition); |
| } |
| } else if (sdr.getType() == DOMRegionContext.XML_TAG_NAME) { |
| if (documentPosition > fn.getStartOffset() + sdr.getStartOffset() && documentPosition < fn.getStartOffset() + sdr.getEndOffset()) { |
| return EMPTY_PROPOSAL_SET; |
| } else if (documentPosition == fn.getStartOffset() + sdr.getEndOffset() && sdr.getNext() != null && sdr.getNext().getType() == DOMJSPRegionContexts.JSP_CONTENT) { |
| // the end of an open tag <script> |
| // <jsp:scriptlet>| blah </jsp:scriptlet> |
| return getJSPJavaCompletionProposals(viewer, documentPosition); |
| } else if (documentPosition == fn.getStartOffset() + sdr.getStartOffset() && sdr.getPrevious() != null && sdr.getPrevious().getType() == DOMRegionContext.XML_TAG_NAME) { |
| return getJSPJavaCompletionProposals(viewer, documentPosition); |
| } |
| } |
| sdr = sdr.getNext(); |
| } |
| } |
| } |
| // ///////////////////////////////////////////////////////////////////////// |
| |
| // check special JSP delimiter cases |
| if (fn != null && partitionType == IJSPPartitionTypes.JSP_CONTENT_DELIMITER) { |
| IStructuredDocumentRegion fnDelim = fn; |
| |
| // if it's a nested JSP region, need to get the correct |
| // StructuredDocumentRegion |
| // not sure why this check was there... |
| // if (fnDelim.getType() == XMLRegionContext.BLOCK_TEXT) { |
| Iterator blockRegions = fnDelim.getRegions().iterator(); |
| ITextRegion temp = null; |
| ITextRegionContainer trc; |
| while (blockRegions.hasNext()) { |
| temp = (ITextRegion) blockRegions.next(); |
| // we hit a nested |
| if (temp instanceof ITextRegionContainer) { |
| trc = (ITextRegionContainer) temp; |
| // it's in this region |
| if (documentPosition >= trc.getStartOffset() && documentPosition < trc.getEndOffset()) { |
| Iterator nestedJSPRegions = trc.getRegions().iterator(); |
| while (nestedJSPRegions.hasNext()) { |
| temp = (ITextRegion) nestedJSPRegions.next(); |
| if (XMLContentAssistUtilities.isJSPOpenDelimiter(temp.getType()) && documentPosition == trc.getStartOffset(temp)) { |
| // HTML content assist |
| // we actually want content assist for the |
| // previous type of region, |
| // well get those proposals from the embedded |
| // adapter |
| if (documentPosition > 0) { |
| partitionType = getPartitionType((StructuredTextViewer) viewer, documentPosition - 1); |
| break; |
| } |
| } else if (XMLContentAssistUtilities.isJSPCloseDelimiter(temp.getType()) && documentPosition == trc.getStartOffset(temp)) { |
| // JSP content assist |
| return getJSPJavaCompletionProposals(viewer, documentPosition); |
| } |
| } |
| } |
| } |
| // } |
| } |
| |
| // take care of XML-JSP delimter cases |
| if (XMLContentAssistUtilities.isXMLJSPDelimiter(fnDelim)) { |
| // since it's a delimiter, we know it's a ITextRegionContainer |
| ITextRegion firstRegion = fnDelim.getRegions().get(0); |
| if (fnDelim.getStartOffset() == documentPosition && (firstRegion.getType() == DOMRegionContext.XML_TAG_OPEN)) { |
| // |<jsp:scriptlet> </jsp:scriptlet> |
| // (pa) commented out so that we get regular behavior JSP |
| // macros etc... |
| // return getHTMLCompletionProposals(viewer, |
| // documentPosition); |
| } else if (fnDelim.getStartOffset() == documentPosition && (firstRegion.getType() == DOMRegionContext.XML_END_TAG_OPEN)) { |
| // <jsp:scriptlet> |</jsp:scriptlet> |
| // check previous partition type to see if it's JAVASCRIPT |
| // if it is, we're just gonna let the embedded JAVASCRIPT |
| // adapter get the proposals |
| if (documentPosition > 0) { |
| String checkType = getPartitionType((StructuredTextViewer) viewer, documentPosition - 1); |
| if (checkType != IJSPPartitionTypes.JSP_CONTENT_JAVASCRIPT) { // this |
| // check |
| // is |
| // failing |
| // for |
| // XML-JSP |
| // (region |
| // is |
| // not |
| // javascript...) |
| return getJSPJavaCompletionProposals(viewer, documentPosition); |
| } |
| partitionType = IJSPPartitionTypes.JSP_CONTENT_JAVASCRIPT; |
| } |
| } else if ((firstRegion.getType() == DOMRegionContext.XML_TAG_OPEN) && documentPosition >= fnDelim.getEndOffset()) { |
| // anything else inbetween |
| return getJSPJavaCompletionProposals(viewer, documentPosition); |
| } |
| } else if (XMLContentAssistUtilities.isJSPDelimiter(fnDelim)) { |
| // the delimiter <%, <%=, <%!, ... |
| if (XMLContentAssistUtilities.isJSPCloseDelimiter(fnDelim)) { |
| if (documentPosition == fnDelim.getStartOffset()) { |
| // check previous partition type to see if it's |
| // JAVASCRIPT |
| // if it is, we're just gonna let the embedded |
| // JAVASCRIPT adapter get the proposals |
| if (documentPosition > 0) { |
| String checkType = getPartitionType((StructuredTextViewer) viewer, documentPosition - 1); |
| if (checkType != IJSPPartitionTypes.JSP_CONTENT_JAVASCRIPT) { |
| return getJSPJavaCompletionProposals(viewer, documentPosition); |
| } |
| partitionType = IJSPPartitionTypes.JSP_CONTENT_JAVASCRIPT; |
| } |
| } |
| } else if (XMLContentAssistUtilities.isJSPOpenDelimiter(fnDelim)) { |
| // if it's the first position of open delimiter |
| // use embedded HTML results |
| if (documentPosition == fnDelim.getStartOffset()) { |
| embeddedResults = getHTMLCompletionProposals(viewer, documentPosition); |
| } else if (documentPosition == fnDelim.getEndOffset()) { |
| // it's at the EOF <%| |
| return getJSPJavaCompletionProposals(viewer, documentPosition); |
| } |
| } |
| } |
| } |
| |
| // need to check if it's JSP region inside of CDATA w/ no region |
| // <![CDATA[ <%|%> ]]> |
| // or a comment region |
| // <!-- <% |%> --> |
| if (fn != null && (fn.getType() == DOMRegionContext.XML_CDATA_TEXT || fn.getType() == DOMRegionContext.XML_COMMENT_TEXT)) { |
| if (fn instanceof ITextRegionContainer) { |
| Object[] cdataRegions = fn.getRegions().toArray(); |
| ITextRegion r = null; |
| ITextRegion jspRegion = null; |
| for (int i = 0; i < cdataRegions.length; i++) { |
| r = (ITextRegion) cdataRegions[i]; |
| if (r instanceof ITextRegionContainer) { |
| // CDATA embedded container, or comment container |
| Object[] jspRegions = ((ITextRegionContainer) r).getRegions().toArray(); |
| for (int j = 0; j < jspRegions.length; j++) { |
| jspRegion = (ITextRegion) jspRegions[j]; |
| if (jspRegion.getType() == DOMJSPRegionContexts.JSP_CLOSE) { |
| if (sdRegion.getStartOffset(jspRegion) == documentPosition) |
| return getJSPJavaCompletionProposals(viewer, documentPosition); |
| } |
| } |
| } |
| } |
| |
| } |
| } |
| |
| // check if it's in an attribute value, if so, don't add CDATA |
| // proposal |
| ITextRegion attrContainer = (fn != null) ? fn.getRegionAtCharacterOffset(documentPosition) : null; |
| if (attrContainer != null && attrContainer instanceof ITextRegionContainer) { |
| if (attrContainer.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE) { |
| // test location of the cursor |
| // return null if it's in the middle of an open/close |
| // delimeter |
| Iterator attrRegions = ((ITextRegionContainer) attrContainer).getRegions().iterator(); |
| ITextRegion testRegion = null; |
| while (attrRegions.hasNext()) { |
| testRegion = (ITextRegion) attrRegions.next(); |
| // need to check for other valid attribute regions |
| if (XMLContentAssistUtilities.isJSPOpenDelimiter(testRegion.getType())) { |
| if (!(((ITextRegionContainer) attrContainer).getEndOffset(testRegion) <= documentPosition)) |
| return EMPTY_PROPOSAL_SET; |
| } else if (XMLContentAssistUtilities.isJSPCloseDelimiter(testRegion.getType())) { |
| if (!(((ITextRegionContainer) attrContainer).getStartOffset(testRegion) >= documentPosition)) |
| return EMPTY_PROPOSAL_SET; |
| } |
| } |
| // TODO: handle non-Java code such as nested tags |
| if (testRegion.getType().equals(DOMJSPRegionContexts.JSP_CONTENT)) |
| return getJSPJavaCompletionProposals(viewer, documentPosition); |
| return EMPTY_PROPOSAL_SET; |
| } |
| } |
| |
| IContentAssistProcessor p = (IContentAssistProcessor) fPartitionToProcessorMap.get(partitionType); |
| if (p != null) { |
| embeddedResults = p.computeCompletionProposals(viewer, documentPosition); |
| // get bean methods, objects, and constants if there are any... |
| if (partitionType == IJSPPartitionTypes.JSP_CONTENT_JAVASCRIPT || partitionType == IHTMLPartitionTypes.SCRIPT) { |
| ICompletionProposal[] beanResults = getJSPJavaBeanProposals(viewer, documentPosition); |
| if (beanResults != null && beanResults.length > 0) { |
| ICompletionProposal[] added = new ICompletionProposal[beanResults.length + embeddedResults.length]; |
| System.arraycopy(beanResults, 0, added, 0, beanResults.length); |
| System.arraycopy(embeddedResults, 0, added, beanResults.length, embeddedResults.length); |
| embeddedResults = added; |
| } |
| } |
| } else { |
| // the partition type is probably not mapped |
| } |
| |
| // fix for CMVC 253000 |
| if (!(p instanceof JavaScriptContentAssistProcessor || p instanceof CSSContentAssistProcessor)) { |
| fTemplateContexts.clear(); |
| jspResults = super.computeCompletionProposals(viewer, documentPosition); |
| } |
| if (useEmbeddedResults) { |
| if (embeddedResults != null && embeddedResults.length > 0) { |
| List results = new ArrayList(); |
| for (int i = 0; i < embeddedResults.length; i++) |
| results.add(embeddedResults[i]); |
| if (jspResults != null) { |
| for (int i = 0; i < jspResults.length; i++) |
| results.add(jspResults[i]); |
| } |
| jspResults = new ICompletionProposal[results.size()]; |
| Collections.sort(results, new ProposalComparator()); |
| for (int i = 0; i < results.size(); i++) |
| jspResults[i] = (ICompletionProposal) results.get(i); |
| |
| } |
| } |
| if (jspResults == null) |
| jspResults = EMPTY_PROPOSAL_SET; |
| setErrorMessage(jspResults.length == 0 ? UNKNOWN_CONTEXT : null); |
| |
| // CMVC 269718 |
| // check for |<%-- --%> first position of jsp comment |
| if (partitionType == IJSPPartitionTypes.JSP_COMMENT) { |
| if (sdRegion.getStartOffset() == documentPosition) { |
| ICompletionProposal[] htmlResults = getHTMLCompletionProposals(viewer, documentPosition); |
| jspResults = merge(jspResults, htmlResults); |
| } |
| } |
| return jspResults; |
| } |
| |
| /** |
| * Adds 2 arrays of ICompletionProposals and sorts them with a |
| * ProposalComparator. |
| * |
| * @param jspResults |
| * @param htmlResults |
| * @return |
| */ |
| private ICompletionProposal[] merge(ICompletionProposal[] jspResults, ICompletionProposal[] htmlResults) { |
| List results = new ArrayList(); |
| List jsps = Arrays.asList(jspResults); |
| List htmls = Arrays.asList(htmlResults); |
| |
| results.addAll(jsps); |
| results.addAll(htmls); |
| |
| Collections.sort(results, new ProposalComparator()); |
| return (ICompletionProposal[]) results.toArray(new ICompletionProposal[results.size()]); |
| } |
| |
| /* |
| * This method will return JSPJava Proposals that are relevant to any java |
| * beans that in scope at the documentPosition |
| * |
| * TODO (pa) are taglib vars getting filtered? |
| * |
| * @param viewer @param documentPosition @return ICompletionProposal[] |
| */ |
| private ICompletionProposal[] getJSPJavaBeanProposals(ITextViewer viewer, int documentPosition) { |
| ICompletionProposal[] regularJSPResults = getJSPJavaCompletionProposals(viewer, documentPosition); |
| Vector filteredProposals = new Vector(); |
| ICompletionProposal[] finalResults = EMPTY_PROPOSAL_SET; |
| for (int i = 0; i < regularJSPResults.length; i++) { |
| ICompletionProposal test = regularJSPResults[i]; |
| |
| System.out.println("proposal > " + test.getDisplayString()); //$NON-NLS-1$ |
| System.out.println("relevance > " + ((CustomCompletionProposal) test).getRelevance()); //$NON-NLS-1$ |
| |
| if (isRelevanceAllowed(((CustomCompletionProposal) test).getRelevance())) { |
| filteredProposals.add(test); |
| } |
| } |
| if (filteredProposals.size() > 0) { |
| finalResults = new ICompletionProposal[filteredProposals.size()]; |
| Iterator it = filteredProposals.iterator(); |
| int j = 0; |
| while (it.hasNext()) { |
| finalResults[j++] = (ICompletionProposal) it.next(); |
| } |
| } |
| return finalResults; |
| } |
| |
| // These are the only things I'm allowing for use bean if the language is |
| // JAVASCRIPT |
| // I'm filtering based on JavaContentAssistProposal relevance |
| // |
| // 485 > method that belongs to the bean |
| // 486 > bean object |
| // 386 > bean CONSTANT |
| private boolean isRelevanceAllowed(int relevance) { |
| return (relevance == 485 || relevance == 486 || relevance == 326); |
| } |
| |
| |
| /** |
| * |
| * @param viewer |
| * @param documentPosition |
| * @return ICompletionProposal[] |
| */ |
| private ICompletionProposal[] getHTMLCompletionProposals(ITextViewer viewer, int documentPosition) { |
| |
| IContentAssistProcessor p = (IContentAssistProcessor) fPartitionToProcessorMap.get(IHTMLPartitionTypes.HTML_DEFAULT); |
| return p.computeCompletionProposals(viewer, documentPosition); |
| } |
| |
| /** |
| * |
| * @param viewer |
| * @param documentPosition |
| * @return ICompletionProposal[] |
| */ |
| protected ICompletionProposal[] getJSPJavaCompletionProposals(ITextViewer viewer, int documentPosition) { |
| JSPJavaContentAssistProcessor p = (JSPJavaContentAssistProcessor) fPartitionToProcessorMap.get(IJSPPartitionTypes.JSP_DEFAULT); |
| p.initialize(fResource); |
| return p.computeCompletionProposals(viewer, documentPosition); |
| } |
| |
| /** |
| * @param viewer |
| * @param documentPosition |
| * @return String |
| */ |
| protected String getPartitionType(StructuredTextViewer viewer, int documentPosition) { |
| String partitionType = null; |
| try { |
| partitionType = TextUtilities.getContentType(viewer.getDocument(), IStructuredPartitioning.DEFAULT_STRUCTURED_PARTITIONING, viewer.modelOffset2WidgetOffset(documentPosition), false); |
| } catch (BadLocationException e) { |
| partitionType = IDocument.DEFAULT_CONTENT_TYPE; |
| } |
| return partitionType; |
| } |
| |
| /* |
| * ** TEMP WORKAROUND FOR CMVC 241882 Takes a String and blocks out |
| * jsp:scriptlet, jsp:expression, and jsp:declaration @param blockText |
| * @return |
| */ |
| private IStructuredDocumentRegion decodeScriptBlock(String blockText) { |
| XMLSourceParser parser = new XMLSourceParser(); |
| // use JSP_CONTENT for region type |
| parser.addBlockMarker(new BlockMarker("jsp:scriptlet", null, DOMJSPRegionContexts.JSP_CONTENT, false, false)); //$NON-NLS-1$ |
| parser.addBlockMarker(new BlockMarker("jsp:expression", null, DOMJSPRegionContexts.JSP_CONTENT, false, false)); //$NON-NLS-1$ |
| parser.addBlockMarker(new BlockMarker("jsp:declaration", null, DOMJSPRegionContexts.JSP_CONTENT, false, false)); //$NON-NLS-1$ |
| parser.reset(blockText); |
| return parser.getDocumentRegions(); |
| } |
| |
| /* |
| * @see ContentAssistAdapter#computeContextInformation(ITextViewer, int, |
| * IndexedRegion) |
| */ |
| public IContextInformation[] computeContextInformation(ITextViewer viewer, int documentOffset, IndexedRegion indexedNode) { |
| return super.computeContextInformation(viewer, documentOffset); |
| } |
| |
| /* |
| * @see ContentAssistAdapter#getContextInformationAutoActivationCharacters() |
| */ |
| public char[] getContextInformationAutoActivationCharacters() { |
| return super.getContextInformationAutoActivationCharacters(); |
| } |
| |
| |
| public char[] getCompletionProposalAutoActivationCharacters() { |
| IPreferenceStore store = JSPUIPlugin.getDefault().getPreferenceStore(); |
| String key = JSPUIPreferenceNames.AUTO_PROPOSE_CODE; |
| |
| String chars = store.getString(key); |
| return (chars != null) ? chars.toCharArray() : new char[0]; |
| } |
| |
| /* |
| * @see ContentAssistAdapter#getContextInformationValidator() |
| */ |
| public IContextInformationValidator getContextInformationValidator() { |
| return super.getContextInformationValidator(); |
| } |
| |
| /* |
| * @see ContentAssistAdapter#initialize(IResource) |
| */ |
| public void initialize(IResource resourceToInit) { |
| fResource = resourceToInit; |
| if (fNameToProcessorMap != null) { |
| |
| if (fNameToProcessorMap.isEmpty()) |
| initNameToProcessorMap(); |
| |
| // init some embedded processors |
| JSPUseBeanContentAssistProcessor useBeanProcessor = (JSPUseBeanContentAssistProcessor) fNameToProcessorMap.get(JSP11Namespace.ElementName.USEBEAN); |
| JSPPropertyContentAssistProcessor propProcessor = (JSPPropertyContentAssistProcessor) fNameToProcessorMap.get(JSP11Namespace.ElementName.SETPROPERTY); |
| useBeanProcessor.initialize(resourceToInit); |
| propProcessor.initialize(resourceToInit); |
| } |
| if (fPartitionToProcessorMap != null) { |
| if (fPartitionToProcessorMap.isEmpty()) |
| initPartitionToProcessorMap(); |
| } |
| } |
| |
| protected boolean isXMLFormat(Document doc) { |
| if (doc == null) |
| return false; |
| Element docElement = doc.getDocumentElement(); |
| return docElement != null && ((docElement.getNodeName().equals("jsp:root")) || ((((IDOMNode) docElement).getStartStructuredDocumentRegion() == null && ((IDOMNode) docElement).getEndStructuredDocumentRegion() == null))); //$NON-NLS-1$ |
| } |
| |
| /* |
| * @see ContentAssistAdapter#release() |
| */ |
| public void release() { |
| super.release(); |
| // release *ContentAssistProcessors in maps |
| // CMVC 254023 |
| releasePartitionToProcessorMap(); |
| releaseNameToProcessorMap(); |
| } |
| |
| protected void releasePartitionToProcessorMap() { |
| releaseMap(fPartitionToProcessorMap); |
| } |
| |
| protected void releaseNameToProcessorMap() { |
| releaseMap(fNameToProcessorMap); |
| } |
| |
| protected void releaseMap(HashMap map) { |
| if (map != null) { |
| if (!map.isEmpty()) { |
| Iterator it = map.keySet().iterator(); |
| Object key = null; |
| while (it.hasNext()) { |
| key = it.next(); |
| if (map.get(key) instanceof IReleasable ) { |
| ((IReleasable) map.get(key)).release(); |
| } |
| } |
| } |
| map.clear(); |
| map = null; |
| } |
| } |
| |
| /** |
| * @see AbstractContentAssistProcessor#computeCompletionProposals(int, |
| * String, ITextRegion, IDOMNode, IDOMNode) |
| */ |
| protected ContentAssistRequest computeCompletionProposals(int documentPosition, String matchString, ITextRegion completionRegion, IDOMNode treeNode, IDOMNode xmlnode) { |
| |
| ContentAssistRequest request = super.computeCompletionProposals(documentPosition, matchString, completionRegion, treeNode, xmlnode); |
| IStructuredDocumentRegion sdRegion = ContentAssistUtils.getStructuredDocumentRegion((StructuredTextViewer) fTextViewer, documentPosition); |
| |
| Document doc = null; |
| if (xmlnode != null) { |
| if (xmlnode.getNodeType() == Node.DOCUMENT_NODE) |
| doc = (Document) xmlnode; |
| else |
| doc = xmlnode.getOwnerDocument(); |
| } |
| String[] directiveNames = {"page", "include", "taglib"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| // suggest JSP Expression inside of XML comments |
| if (completionRegion.getType() == DOMRegionContext.XML_COMMENT_TEXT && !isXMLFormat(doc)) { |
| if (request == null) |
| request = newContentAssistRequest(treeNode, xmlnode, sdRegion, completionRegion, documentPosition, 0, ""); //$NON-NLS-1$ |
| request.addProposal(new CustomCompletionProposal("<%= %>", documentPosition, 0, 4, JSPEditorPluginImageHelper.getInstance().getImage(JSPEditorPluginImages.IMG_OBJ_TAG_GENERIC), "jsp:expression", null, "<%= %>", XMLRelevanceConstants.R_JSP)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| } |
| // handle proposals in and around JSP_DIRECTIVE_OPEN and |
| // JSP_DIRECTIVE_NAME |
| else if ((completionRegion.getType() == DOMJSPRegionContexts.JSP_DIRECTIVE_OPEN && documentPosition >= sdRegion.getTextEndOffset(completionRegion)) || (completionRegion.getType() == DOMJSPRegionContexts.JSP_DIRECTIVE_NAME && documentPosition <= sdRegion.getTextEndOffset(completionRegion))) { |
| if (completionRegion.getType() == DOMJSPRegionContexts.JSP_DIRECTIVE_OPEN) { |
| if (request == null) |
| request = newContentAssistRequest(xmlnode, xmlnode, sdRegion, completionRegion, documentPosition, 0, matchString); |
| Iterator regions = sdRegion.getRegions().iterator(); |
| String nameString = null; |
| int begin = request.getReplacementBeginPosition(); |
| int length = request.getReplacementLength(); |
| while (regions.hasNext()) { |
| ITextRegion region = (ITextRegion) regions.next(); |
| if (region.getType() == DOMJSPRegionContexts.JSP_DIRECTIVE_NAME) { |
| nameString = sdRegion.getText(region); |
| begin = sdRegion.getStartOffset(region); |
| length = region.getTextLength(); |
| break; |
| } |
| } |
| if (nameString == null) |
| nameString = ""; //$NON-NLS-1$ |
| for (int i = 0; i < directiveNames.length; i++) { |
| if (directiveNames[i].startsWith(nameString) || documentPosition <= begin) |
| request.addProposal(new CustomCompletionProposal(directiveNames[i], begin, length, directiveNames[i].length(), JSPEditorPluginImageHelper.getInstance().getImage(JSPEditorPluginImages.IMG_OBJ_TAG_GENERIC), directiveNames[i], null, null, XMLRelevanceConstants.R_JSP)); |
| } |
| } else { // by default, JSP_DIRECTIVE_NAME |
| if (request == null) |
| request = newContentAssistRequest(xmlnode, xmlnode, sdRegion, completionRegion, sdRegion.getStartOffset(completionRegion), completionRegion.getTextLength(), matchString); |
| for (int i = 0; i < directiveNames.length; i++) { |
| if (directiveNames[i].startsWith(matchString)) |
| request.addProposal(new CustomCompletionProposal(directiveNames[i], request.getReplacementBeginPosition(), request.getReplacementLength(), directiveNames[i].length(), JSPEditorPluginImageHelper.getInstance().getImage(JSPEditorPluginImages.IMG_OBJ_TAG_GENERIC), directiveNames[i], null, null, XMLRelevanceConstants.R_JSP)); |
| } |
| } |
| } else if ((completionRegion.getType() == DOMJSPRegionContexts.JSP_DIRECTIVE_NAME && documentPosition > sdRegion.getTextEndOffset(completionRegion)) || (completionRegion.getType() == DOMJSPRegionContexts.JSP_DIRECTIVE_CLOSE && documentPosition <= sdRegion.getStartOffset(completionRegion))) { |
| if (request == null) |
| request = computeAttributeProposals(documentPosition, matchString, completionRegion, treeNode, xmlnode); |
| super.addTagCloseProposals(request); |
| // CMVC 274033, this is being added for all <jsp:* tags |
| // in addAttributeNameProposals(contentAssistRequest) |
| // super.addAttributeNameProposals(request); |
| } |
| // no name?: <%@ %> |
| else if (completionRegion.getType() == DOMJSPRegionContexts.JSP_DIRECTIVE_CLOSE && documentPosition <= sdRegion.getStartOffset(completionRegion)) { |
| if (request != null) |
| request = computeAttributeProposals(documentPosition, matchString, completionRegion, treeNode, xmlnode); |
| Iterator regions = sdRegion.getRegions().iterator(); |
| String nameString = null; |
| while (regions.hasNext()) { |
| ITextRegion region = (ITextRegion) regions.next(); |
| if (region.getType() == DOMJSPRegionContexts.JSP_DIRECTIVE_NAME) { |
| nameString = sdRegion.getText(region); |
| break; |
| } |
| } |
| if (nameString == null) { |
| for (int i = 0; i < directiveNames.length; i++) { |
| request.addProposal(new CustomCompletionProposal(directiveNames[i], request.getReplacementBeginPosition(), request.getReplacementLength(), directiveNames[i].length(), JSPEditorPluginImageHelper.getInstance().getImage(JSPEditorPluginImages.IMG_OBJ_TAG_GENERIC), directiveNames[i], null, null, XMLRelevanceConstants.R_JSP)); |
| } |
| } |
| } |
| |
| addTemplates(request, TemplateContextTypeIdsJSP.ALL); |
| return request; |
| } |
| |
| private JSPTemplateCompletionProcessor getTemplateCompletionProcessor() { |
| if (fTemplateProcessor == null) { |
| fTemplateProcessor = new JSPTemplateCompletionProcessor(); |
| } |
| return fTemplateProcessor; |
| } |
| |
| /** |
| * Adds templates to the list of proposals |
| * |
| * @param contentAssistRequest |
| * @param context |
| */ |
| private void addTemplates(ContentAssistRequest contentAssistRequest, String context) { |
| if (contentAssistRequest == null) |
| return; |
| |
| // if already adding template proposals for a certain context type, do |
| // not add again |
| if (!fTemplateContexts.contains(context)) { |
| fTemplateContexts.add(context); |
| boolean useProposalList = !contentAssistRequest.shouldSeparate(); |
| |
| if (getTemplateCompletionProcessor() != null) { |
| getTemplateCompletionProcessor().setContextType(context); |
| ICompletionProposal[] proposals = getTemplateCompletionProcessor().computeCompletionProposals(fTextViewer, contentAssistRequest.getReplacementBeginPosition()); |
| for (int i = 0; i < proposals.length; ++i) { |
| if (useProposalList) |
| contentAssistRequest.addProposal(proposals[i]); |
| else |
| contentAssistRequest.addMacro(proposals[i]); |
| } |
| } |
| } |
| } |
| |
| |
| protected void addEntityProposals(ContentAssistRequest contentAssistRequest, int documentPosition, ITextRegion completionRegion, IDOMNode treeNode) { |
| // ignore |
| } |
| |
| protected void addTagInsertionProposals(ContentAssistRequest contentAssistRequest, int childPosition) { |
| addTemplates(contentAssistRequest, TemplateContextTypeIdsJSP.TAG); |
| |
| super.addTagInsertionProposals(contentAssistRequest, childPosition); |
| if (isInternalAdapter) |
| useEmbeddedResults = false; |
| } |
| } |