/******************************************************************************* * Copyright (c) 2005 - 2013 Spring IDE Developers * 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: * Spring IDE Developers - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.beans.ui.editor.hover; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextHover; import org.eclipse.jface.text.ITextViewer; import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; 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.ITextRegion; import org.eclipse.wst.sse.ui.internal.StructuredTextViewer; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext; import org.eclipse.wst.xml.ui.internal.taginfo.XMLTagInfoHoverProcessor; import org.springframework.ide.eclipse.beans.core.model.IBean; import org.springframework.ide.eclipse.beans.ui.editor.util.BeansEditorUtils; import org.springframework.ide.eclipse.beans.ui.editor.util.BeansJavaDocUtils; import org.springframework.ide.eclipse.core.java.Introspector; import org.springframework.ide.eclipse.core.java.Introspector.Public; import org.springframework.ide.eclipse.core.java.Introspector.Static; import org.springframework.ide.eclipse.core.java.JdtUtils; import org.springframework.util.StringUtils; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; /** * Hover information processor to create hover information for the spring beans * editor * @author Christian Dupuis * @author Torsten Juergeleit * @author Leo Dos Santos */ @SuppressWarnings("restriction") public class BeansTextHoverProcessor extends XMLTagInfoHoverProcessor implements ITextHover { @Override public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { String displayText = null; int documentOffset = hoverRegion.getOffset(); displayText = computeHoverHelp(textViewer, documentOffset); if (displayText != null) { return displayText; } return super.getHoverInfo(textViewer, hoverRegion); } /** * Retrieves documentation to display in the hover help popup. * * @return String any documentation information to display <code>null</code> * if there is nothing to display. * */ @Override protected String computeHoverHelp(ITextViewer textViewer, int documentPosition) { String result = null; IndexedRegion treeNode = BeansEditorUtils.getNodeAt( (StructuredTextViewer) textViewer, documentPosition); if (treeNode == null) return null; Node node = (Node) treeNode; while (node != null && node.getNodeType() == Node.TEXT_NODE && node.getParentNode() != null) node = node.getParentNode(); IDOMNode parentNode = (IDOMNode) node; IStructuredDocumentRegion flatNode = ((IStructuredDocument) textViewer .getDocument()).getRegionAtCharacterOffset(documentPosition); if (flatNode != null) { ITextRegion region = flatNode .getRegionAtCharacterOffset(documentPosition); if (region != null) { result = computeRegionHelp(treeNode, parentNode, flatNode, region, textViewer.getDocument()); } } return result; } /** * Computes the hoverhelp based on region * * @return String hoverhelp */ protected String computeRegionHelp(IndexedRegion treeNode, IDOMNode parentNode, IStructuredDocumentRegion flatNode, ITextRegion region, IDocument document) { String result = null; if (region == null) return null; String regionType = region.getType(); if (regionType == DOMRegionContext.XML_TAG_NAME) result = computeTagNameHelp((IDOMNode) treeNode, parentNode, flatNode, region); else if (regionType == DOMRegionContext.XML_TAG_ATTRIBUTE_NAME) result = computeTagAttNameHelp((IDOMNode) treeNode, parentNode, flatNode, region); else if (regionType == DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE) result = computeTagAttValueHelp((IDOMNode) treeNode, parentNode, flatNode, region, document); return result; } /** * Computes the hover help for the attribute value (this is the same as the * attribute name's help) */ protected String computeTagAttValueHelp(IDOMNode xmlnode, IDOMNode parentNode, IStructuredDocumentRegion flatNode, ITextRegion region, IDocument document) { IFile file = BeansEditorUtils.getFile(document); ITextRegion attrNameRegion = getAttrNameRegion(xmlnode, region); String attName = flatNode.getText(attrNameRegion); NamedNodeMap attributes = xmlnode.getAttributes(); String result = null; if ("class".equals(attName) && attributes.getNamedItem("class") != null) { String className = attributes.getNamedItem("class").getNodeValue(); if (className != null && file != null) { IType type = JdtUtils.getJavaType(file.getProject(), className); if (type != null) { BeansJavaDocUtils utils = new BeansJavaDocUtils(type); result = utils.getJavaDoc(); } } } else if ("name".equals(attName) && "property".equals(xmlnode.getNodeName())) { String propertyName = attributes.getNamedItem(attName) .getNodeValue(); String[] paths = StringUtils.split(propertyName, "."); if (paths == null) { paths = new String[] { propertyName }; } List<String> propertyPaths = Arrays.asList(paths); List classNames = BeansEditorUtils.getClassNamesOfBean(file, xmlnode.getParentNode()); List<IMethod> methods = new ArrayList<IMethod>(); BeansEditorUtils.extractAllMethodsFromPropertyPathElements( propertyPaths, classNames, file, 0, methods); StringBuffer buf = new StringBuffer(); for (int i = 0; i < methods.size(); i++) { IMethod method = methods.get(i); if (method != null) { BeansJavaDocUtils utils = new BeansJavaDocUtils(method); buf.append(utils.getJavaDoc() + "<br>"); } } result = buf.toString(); } else if ("local".equals(attName) && attributes.getNamedItem(attName) != null) { Element ref = xmlnode.getOwnerDocument().getElementById( attributes.getNamedItem(attName).getNodeValue()); result = BeansEditorUtils.createAdditionalProposalInfo(ref, file); } else if ("bean".equals(attName) && attributes.getNamedItem(attName) != null) { String target = attributes.getNamedItem(attName).getNodeValue(); // assume this is an external reference Iterator beans = BeansEditorUtils.getBeansFromConfigSets(file) .iterator(); while (beans.hasNext()) { IBean modelBean = (IBean) beans.next(); if (modelBean.getElementName().equals(target)) { result = BeansEditorUtils .createAdditionalProposalInfo(modelBean); } } } else if (("ref".equals(attName) || "local".equals(attName) || "parent".equals(attName) || "depends-on".equals(attName) || "factory-bean".equals(attName) || "key-ref".equals(attName) || "value-ref".equals(attName) || attName.endsWith("-ref") || ("name".equals(attName) && "alias".equals(xmlnode .getNodeName())) || ("bean".equals(attName) && "ref" .equals(xmlnode.getNodeName()))) && attributes.getNamedItem(attName) != null) { Element ref = xmlnode.getOwnerDocument().getElementById( attributes.getNamedItem(attName).getNodeValue()); if (ref != null) { result = BeansEditorUtils.createAdditionalProposalInfo(ref, file); } else { String target = attributes.getNamedItem(attName).getNodeValue(); // assume this is an external reference Iterator beans = BeansEditorUtils.getBeansFromConfigSets(file) .iterator(); while (beans.hasNext()) { IBean modelBean = (IBean) beans.next(); if (modelBean.getElementName().equals(target)) { result = BeansEditorUtils .createAdditionalProposalInfo(modelBean); } } } } else if (("factory-method").equals(attName)) { String factoryMethod = attributes.getNamedItem(attName) .getNodeValue(); String className = BeansEditorUtils.getClassNameForBean( file, xmlnode.getOwnerDocument(), xmlnode); if (file != null && file.exists()) { IType type = JdtUtils.getJavaType(file.getProject(), className); if (type != null) { try { IMethod[] methods = type.getMethods(); for (IMethod method : methods) { if (method.getElementName().equals(factoryMethod)) { BeansJavaDocUtils utils = new BeansJavaDocUtils( method); result = utils.getJavaDoc(); } } } catch (JavaModelException e) { } } } } if ("init-method".equals(attName) || "destroy-method".equals(attName)) { String factoryMethod = attributes.getNamedItem(attName) .getNodeValue(); String className = BeansEditorUtils.getClassNameForBean( file, xmlnode.getOwnerDocument(), xmlnode); if (file != null && file.exists()) { IType type = JdtUtils.getJavaType(file.getProject(), className); try { IMethod method = Introspector.findMethod(type, factoryMethod, 0, Public.DONT_CARE, Static.DONT_CARE); if (method != null) { BeansJavaDocUtils utils = new BeansJavaDocUtils(method); result = utils.getJavaDoc(); } } catch (JavaModelException e) { } } } else if (("lookup-method".equals(xmlnode.getNodeName()) && "name" .equals(attName)) || ("replaced-method".equals(xmlnode.getNodeName()) && "name" .equals(attName))) { String factoryMethod = attributes.getNamedItem(attName) .getNodeValue(); String className = BeansEditorUtils.getClassNameForBean( file, xmlnode.getOwnerDocument(), xmlnode.getParentNode()); if (file != null && file.exists()) { IType type = JdtUtils.getJavaType(file.getProject(), className); try { IMethod method = Introspector.findMethod(type, factoryMethod, 0, Public.DONT_CARE, Static.DONT_CARE); if (method != null) { BeansJavaDocUtils utils = new BeansJavaDocUtils(method); result = utils.getJavaDoc(); } } catch (JavaModelException e) { } } } if (result != null && !"".equals(result)) { return result; } else { return super.computeTagAttValueHelp(xmlnode, parentNode, flatNode, attrNameRegion); } } }