package org.eclipse.jst.jsf.facelet.ui.internal.contentassist; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IProject; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.contentassist.CompletionProposal; 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.jsf.common.runtime.internal.view.model.common.ITagElement; import org.eclipse.jst.jsf.common.runtime.internal.view.model.common.Namespace; import org.eclipse.jst.jsf.context.resolver.structureddocument.IDOMContextResolver; import org.eclipse.jst.jsf.context.resolver.structureddocument.IStructuredDocumentContextResolverFactory; import org.eclipse.jst.jsf.context.resolver.structureddocument.IWorkspaceContextResolver; import org.eclipse.jst.jsf.context.resolver.structureddocument.internal.ITextRegionContextResolver; import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContext; import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContextFactory; import org.eclipse.jst.jsf.designtime.internal.view.model.ITagRegistry; import org.eclipse.jst.jsf.designtime.internal.view.model.TagRegistryFactory.TagRegistryFactoryException; import org.eclipse.jst.jsf.facelet.core.internal.registry.FaceletRegistryManager.MyRegistryFactory; import org.eclipse.jst.jsf.facelet.ui.internal.FaceletUiPlugin; import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; /** * Temporary. * * @author cbateman * */ public class XHTMLContentAssistProcessor2 implements IContentAssistProcessor { private final static ICompletionProposal[] NO_PROPOSALS = new ICompletionProposal[0]; public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>(); final IStructuredDocumentContext context = IStructuredDocumentContextFactory.INSTANCE .getContext(viewer, offset); if (context != null) { final IDOMContextResolver domContextResolver = IStructuredDocumentContextResolverFactory.INSTANCE .getDOMContextResolver(context); final Document doc = domContextResolver.getDOMDocument(); if (doc == null) { return NO_PROPOSALS; } // get the namespaces that are already declared final Map<String, PrefixEntry> documentNamespaces = getDocumentNamespaces(doc); final ITextRegionContextResolver resolver = IStructuredDocumentContextResolverFactory.INSTANCE .getTextRegionResolver(context); if (resolver != null) { final String regionType = resolver.getRegionType(); if (DOMRegionContext.XML_CONTENT.equals(regionType)) { // TODO: this may be in the open it may occur on the inside // of a // "<" that doesn't have any further tag name yet proposals = getTagCompletionsForDocument(context, documentNamespaces, TagPrefix.NO_PREFIX); } else if (DOMRegionContext.XML_TAG_NAME.equals(regionType)) { final TagPrefix tagPrefix = new TagPrefix(resolver .getRegionText()); proposals = getTagCompletionsForDocument(context, documentNamespaces, tagPrefix); } else { System.out.println(regionType); } } } return proposals.toArray(NO_PROPOSALS); } private List<ICompletionProposal> getTagCompletionsForDocument( final IStructuredDocumentContext context, final Map<String, PrefixEntry> namespaces, final TagPrefix tagPrefix) { final List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>(); final IWorkspaceContextResolver wkspaceResolver = IStructuredDocumentContextResolverFactory.INSTANCE .getWorkspaceContextResolver(context); final IProject project = wkspaceResolver.getProject(); MyRegistryFactory factory = new MyRegistryFactory(); ITagRegistry registry; try { registry = factory.createTagRegistry(project); if (registry == null) { return proposals; } final Collection<? extends Namespace> tagLibs = registry .getAllTagLibraries(); for (final Namespace tagLib : tagLibs) { final PrefixEntry ns = namespaces.get(tagLib.getNSUri()); // if the tag library is not initialized, don't trigger // a potentially expensive operation during the content assist if (ns != null && tagLib.isInitialized()) { // only add if this namespace's prefix starts with // the prefix that the user provided if (ns._prefix.startsWith(tagPrefix.getPrefix())) { final Collection<?> tags = tagLib.getViewElements(); for (final Iterator<?> it = tags.iterator(); it .hasNext();) { final ITagElement tagElement = (ITagElement) it .next(); // only add an element it starts with the prefix // provided if (tagElement.getName().startsWith( tagPrefix.getLocalName())) { final String userPrefix = tagPrefix .getUserPrefix(); final String tagName = ns._prefix + ":" + tagElement.getName(); String replacementText = ""; if ("".equals(userPrefix)) { replacementText = "<" + tagName + "></" + tagName + ">"; } else { replacementText = tagName .substring(userPrefix.length()); } proposals.add(new CompletionProposal( replacementText, context .getDocumentPosition(), 0, 0, null, tagName, null, null)); } } } } } } catch (TagRegistryFactoryException e) { FaceletUiPlugin.log(e); } return proposals; } private Map<String, PrefixEntry> getDocumentNamespaces(Document doc) { final Map<String, PrefixEntry> namespaces = new HashMap<String, PrefixEntry>(); Element rootElement = doc.getDocumentElement(); if (rootElement != null) { NamedNodeMap attrs = rootElement.getAttributes(); for (int i = 0; i < attrs.getLength(); i++) { Attr a = (Attr) attrs.item(i); PrefixEntry ns = PrefixEntry.parseNamespace(a); if (ns != null) { namespaces.put(ns.getUri(), ns); } } } return namespaces; } private static class TagPrefix { public final static TagPrefix NO_PREFIX = new TagPrefix(""); private final String _prefix; private final String _localName; private final boolean _hasColon; public TagPrefix(final String tagName) { int prefixIdx = tagName.indexOf(':'); if (prefixIdx != -1) { _prefix = tagName.substring(0, prefixIdx); _hasColon = true; if (tagName.length() > prefixIdx) { _localName = tagName.substring(prefixIdx + 1); } else { _localName = ""; } } else { _hasColon = false; _prefix = tagName; _localName = ""; } } public String getUserPrefix() { String userPrefix = _prefix; if (_hasColon) { userPrefix += ":"; userPrefix += _localName; } return userPrefix; } public String getPrefix() { return _prefix; } public String getLocalName() { return _localName; } } private static class PrefixEntry { private final String _uri; private final String _prefix; public static PrefixEntry parseNamespace(Attr attr) { final String prefix = attr.getPrefix(); if ("xmlns".equals(prefix)) { final String prefixName = attr.getLocalName(); if (prefixName != null) { final String uri = attr.getNodeValue(); if (uri != null) { return new PrefixEntry(uri, prefixName); } } } return null; } public PrefixEntry(final String uri, final String prefix) { _uri = uri; _prefix = prefix; } public final String getUri() { return _uri; } public int hashCode() { return _uri.hashCode(); } public boolean equals(Object obj) { return _uri.equals(obj); } } public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { return null; } public char[] getCompletionProposalAutoActivationCharacters() { return null; } public char[] getContextInformationAutoActivationCharacters() { return null; } public IContextInformationValidator getContextInformationValidator() { return null; } public String getErrorMessage() { return null; } }