/******************************************************************************* * Copyright (c) 2000, 2010 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.wst.jsdt.internal.ui.javaeditor; import org.eclipse.jface.action.IAction; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.wst.jsdt.core.IJavaScriptElement; import org.eclipse.wst.jsdt.core.dom.ASTNode; import org.eclipse.wst.jsdt.core.dom.ASTVisitor; import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit; import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin; import org.eclipse.wst.jsdt.internal.ui.text.JavaWordFinder; /** * Java element hyperlink detector. * * */ public class JavaElementHyperlinkDetector extends AbstractHyperlinkDetector { /** * * @param textViewer * @param region * @param canShowMultipleHyperlinks * @param ast * @return */ public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks, JavaScriptUnit ast) { ITextEditor textEditor= (ITextEditor)getAdapter(ITextEditor.class); if (region == null || !(textEditor instanceof JavaEditor)) return null; IAction openAction= textEditor.getAction("OpenEditor"); //$NON-NLS-1$ if (openAction == null) return null; int offset= region.getOffset(); IJavaScriptElement input= EditorUtility.getEditorInputJavaElement(textEditor, false); if (input == null) return null; //get the possibly hyperlink word region IDocument document= textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput()); IRegion wordRegion= JavaWordFinder.findWord(document, offset); if (wordRegion == null) return null; if(ast==null) { //search the AST for the word region to determine if it is a candidate for a link ast = JavaScriptPlugin.getDefault().getASTProvider().getAST( input, ASTProvider.WAIT_NO, null); } if(ast != null) { int start = wordRegion.getOffset(); int end = start + wordRegion.getLength(); HyperlinkCandidateVisitor visitor = new HyperlinkCandidateVisitor(start, end); try { ast.accept(visitor); } catch(HyperlinkCandidateVisitor.HyperlinkCandidateFoundException e) { //just means the visiting has been cut off early } if(visitor.fFoundCandidate) { return new IHyperlink[] {new JavaElementHyperlink(wordRegion, openAction)}; } } return null; } /* * @see org.eclipse.jface.text.hyperlink.IHyperlinkDetector#detectHyperlinks(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion, boolean) */ public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { ITextEditor textEditor= (ITextEditor)getAdapter(ITextEditor.class); if (region == null || !(textEditor instanceof JavaEditor)) return null; IAction openAction= textEditor.getAction("OpenEditor"); //$NON-NLS-1$ if (openAction == null) return null; int offset= region.getOffset(); IJavaScriptElement input= EditorUtility.getEditorInputJavaElement(textEditor, false); if (input == null) return null; //get the possibly hyperlink word region IDocument document= textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput()); IRegion wordRegion= JavaWordFinder.findWord(document, offset); if (wordRegion == null) return null; //search the AST for the word region to determine if it is a candidate for a link JavaScriptUnit ast = JavaScriptPlugin.getDefault().getASTProvider().getAST( input, ASTProvider.WAIT_NO, null); if(ast != null) { int start = wordRegion.getOffset(); int end = start + wordRegion.getLength(); HyperlinkCandidateVisitor visitor = new HyperlinkCandidateVisitor(start, end); try { ast.accept(visitor); } catch(HyperlinkCandidateVisitor.HyperlinkCandidateFoundException e) { //just means the visiting has been cut off early } if(visitor.fFoundCandidate) { return new IHyperlink[] {new JavaElementHyperlink(wordRegion, openAction)}; } } return null; } /** * <p>Visits an AST looking for a node between the given start and end offsets * that could be a hyperlink candidate.</p> * * @throws HyperlinkCandidateFoundException once a candidate has been found this is thrown to * short cut any further visiting */ private class HyperlinkCandidateVisitor extends ASTVisitor { /** <code>true</code> if a hyperlink candidate is found, <code>false</code> otherwise.</p> */ protected boolean fFoundCandidate; /** Start offset where the candidate should start after. */ private int fStartOffset; /** End offset where the candidate should end before. */ private int fEndOffset; /** * @param start Start offset where the candidate should start after * @param end End offset where the candidate should end before */ protected HyperlinkCandidateVisitor(int start, int end) { this.fFoundCandidate = false; this.fStartOffset = start; this.fEndOffset = end; } /** * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#preVisit(org.eclipse.wst.jsdt.core.dom.ASTNode) */ public void preVisit(ASTNode node) { switch(node.getNodeType()) { case ASTNode.SIMPLE_NAME: case ASTNode.QUALIFIED_NAME: isCandidate(node); break; } } /** * <p>Determines if the given node is a hyperlink candidate based on the start * and end offsets. </p> * * @param n Determine if this {@link ASTNode} is a candidate for a hyperlink based * on the start and end offsets * * @throws HyperlinkCandidateFoundException */ private void isCandidate(ASTNode n) { if(!this.fFoundCandidate) { int start = n.getStartPosition(); int end = start + n.getLength(); if(start >= this.fStartOffset && end <= this.fEndOffset) { this.fFoundCandidate = true; throw new HyperlinkCandidateFoundException(); } } } /** * <p>Used to cancel visiting after a candidate has been found.</p> */ private class HyperlinkCandidateFoundException extends RuntimeException { private static final long serialVersionUID = 1L; } } }