/*******************************************************************************
* 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();
}
}
}