/******************************************************************************* * Copyright (c) 2011-2014 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is 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: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.jsf.text.ext.hyperlink; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMAttr; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMElement; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; import org.jboss.tools.common.el.core.resolver.ELContext; import org.jboss.tools.common.model.XModelObject; import org.jboss.tools.common.text.ext.util.StructuredModelWrapper; import org.jboss.tools.common.text.ext.util.Utils; import org.jboss.tools.jst.web.ui.internal.editor.jspeditor.JSPTextEditor.JSPStructuredTextViewer; import org.jboss.tools.jst.web.ui.internal.text.ext.util.TaglibManagerWrapper; import org.jboss.tools.jst.web.kb.IPageContext; import org.jboss.tools.jst.web.kb.KbQuery; import org.jboss.tools.jst.web.kb.PageContextFactory; import org.jboss.tools.jst.web.kb.PageProcessor; import org.jboss.tools.jst.web.kb.internal.taglib.AbstractAttribute; import org.jboss.tools.jst.web.kb.internal.taglib.AbstractComponent; import org.jboss.tools.jst.web.kb.internal.taglib.TLDTag; import org.jboss.tools.jst.web.kb.taglib.IAttribute; import org.jboss.tools.jst.web.kb.taglib.IComponent; import org.jboss.tools.jst.web.kb.taglib.INameSpace; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @SuppressWarnings("restriction") public class JsfJSPTagNameHyperlinkDetector extends AbstractHyperlinkDetector { public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { if(!(textViewer instanceof JSPStructuredTextViewer)) return null; StructuredModelWrapper smw = new StructuredModelWrapper(); smw.init(textViewer.getDocument()); try { Document xmlDocument = smw.getDocument(); if (xmlDocument == null) return null; Node n = Utils.findNodeForOffset(xmlDocument, region.getOffset()); IRegion reg = getRegion(n, region.getOffset()); boolean prefixExist = false; if(reg != null && n instanceof IDOMElement) { String tagName = n.getNodeName(); int i = tagName.indexOf(":"); KbQuery query = new KbQuery(); query.setType(KbQuery.Type.TAG_NAME); if(i > 0){ query.setPrefix(tagName.substring(0, i)); prefixExist = true; }else{ query.setPrefix(""); } query.setOffset(reg.getOffset()); query.setValue(tagName); query.setUri(getURI(region, textViewer.getDocument())); query.setMask(false); ELContext context = PageContextFactory.createPageContext(textViewer.getDocument()); if(context instanceof IPageContext){ IComponent[] components = PageProcessor.getInstance().getComponents(query, (IPageContext)context); ArrayList<IHyperlink> hyperlinks = new ArrayList<IHyperlink>(); for(IComponent component : components){ if(!component.isExtended() && validateComponent(component, ((IPageContext)context).getNameSpaces(reg.getOffset()), query.getPrefix())){ TLDTagHyperlink link = new TLDTagHyperlink((AbstractComponent)component, reg); link.setDocument(textViewer.getDocument()); hyperlinks.add(link); } } sortHyperlinks(hyperlinks); if(hyperlinks.size() > 0) return (IHyperlink[]) hyperlinks.toArray(new IHyperlink[hyperlinks.size()]); } } else if(reg != null && n instanceof IDOMAttr) { String tagName = ((IDOMAttr)n).getOwnerElement().getNodeName(); int i = tagName.indexOf(":"); KbQuery query = new KbQuery(); query.setType(KbQuery.Type.ATTRIBUTE_NAME); if(i > 0){ query.setPrefix(tagName.substring(0, i)); prefixExist = true; }else{ query.setPrefix(""); } query.setUri(getURI(region, textViewer.getDocument())); query.setParentTags(new String[]{tagName}); query.setParent(tagName); query.setOffset(reg.getOffset()); query.setValue(n.getNodeName()); query.setMask(false); ELContext context = PageContextFactory.createPageContext(textViewer.getDocument()); if(context instanceof IPageContext){ IAttribute[] attributes = PageProcessor.getInstance().getAttributes(query, (IPageContext)context); ArrayList<IHyperlink> hyperlinks = new ArrayList<IHyperlink>(); for(IAttribute attribute : attributes){ if(!attribute.isExtended() && validateComponent(attribute.getComponent(), ((IPageContext)context).getNameSpaces(reg.getOffset()), query.getPrefix()) && attribute instanceof AbstractAttribute){ TLDAttributeHyperlink link = new TLDAttributeHyperlink((AbstractAttribute)attribute, reg); link.setDocument(textViewer.getDocument()); hyperlinks.add(link); } } sortHyperlinks(hyperlinks); if(hyperlinks.size() > 0) return (IHyperlink[]) hyperlinks.toArray(new IHyperlink[hyperlinks.size()]); } } if(prefixExist){ return parse(textViewer.getDocument(), xmlDocument, region); } return null; } finally { smw.dispose(); } } private boolean validateComponent(IComponent component, Map<String, List<INameSpace>> nameSpaces, String prefix){ if(!validateNameSpace(component, nameSpaces, prefix)) return false; if(component instanceof AbstractComponent){ IFile file = TLDTagHyperlink.getFile((AbstractComponent)component); if(file != null && file.getFullPath() != null && file.getFullPath().toString().endsWith(".jar")) { XModelObject xmodelObject = TLDTagHyperlink.getXModelObject((AbstractComponent)component); if(xmodelObject != null) if(TLDTagHyperlink.getFileName(xmodelObject) != null) return true; }else if(file != null) return true; } return false; } private boolean validateNameSpace(IComponent component, Map<String, List<INameSpace>> nameSpaces, String prefix){ if (component != null) { String uri = component.getTagLib().getURI(); List<INameSpace> list = nameSpaces.get(uri); if(list != null){ for(INameSpace nameSpace : list){ if(nameSpace.getPrefix().equals(prefix)) return true; } } } return false; } private void sortHyperlinks(ArrayList<IHyperlink> hyperlinks){ for(IHyperlink link : hyperlinks){ if(link instanceof TLDTagHyperlink){ AbstractComponent tag = ((TLDTagHyperlink)link).getComponent(); if(tag instanceof TLDTag){ int index = hyperlinks.indexOf(link); if(index != 0){ IHyperlink first = hyperlinks.get(0); hyperlinks.set(0,link); hyperlinks.set(index, first); } } } } } private IHyperlink[] parse(IDocument document, Document xmlDocument, IRegion superRegion) { Node n = Utils.findNodeForOffset(xmlDocument, superRegion.getOffset()); IRegion r = getRegion(n, superRegion.getOffset()); if (r == null) return null; JsfJSPTagNameHyperlink link = new JsfJSPTagNameHyperlink(r); link.setDocument(document); return new IHyperlink[]{link}; } private IRegion getRegion(Node n, int offset) { if (n == null || !(n instanceof IDOMNode)) return null; int nameStart, nameEnd; if(n instanceof IDOMAttr) { IDOMAttr attr = (IDOMAttr)n; String attrName = attr.getName(); int start = attr.getStartOffset(); nameStart = start; nameEnd = nameStart + attrName.length(); } else if(n instanceof IDOMElement) { IDOMElement elem = (IDOMElement)n; String tagName = elem.getTagName(); if(offset >= elem.getStartOffset() && offset <= elem.getStartEndOffset()){ int start = elem.getStartOffset(); nameStart = start + "<".length(); //$NON-NLS-1$ nameEnd = nameStart + tagName.length(); }else if(offset >= elem.getEndStartOffset() && offset <= (elem.getEndStartOffset() + elem.getLength())) { int start = elem.getEndStartOffset(); nameStart = start + "</".length(); //$NON-NLS-1$ nameEnd = nameStart + tagName.length(); }else return null; } else return null; if(offset < nameEnd) return new Region(nameStart, nameEnd - nameStart); else return null; } private String getURI(IRegion region, IDocument document) { StructuredModelWrapper smw = new StructuredModelWrapper(); smw.init(document); try { Document xmlDocument = smw.getDocument(); if (xmlDocument == null) return null; Node n = Utils.findNodeForOffset(xmlDocument, region.getOffset()); Node node = null; if (n instanceof Attr) { node = ((Attr)n).getOwnerElement(); } else { node = n; } if (!(node instanceof Element)) return null; String nodeName = node.getNodeName(); if (nodeName.indexOf(':') == -1) return null; String nodePrefix = nodeName.substring(0, nodeName.indexOf(":")); //$NON-NLS-1$ if (nodePrefix == null || nodePrefix.length() == 0) return null; TaglibManagerWrapper tmw = new TaglibManagerWrapper(); tmw.init(document, region.getOffset()); if (!tmw.exists()) return null; return tmw.getUri(nodePrefix); } finally { smw.dispose(); } } }