/******************************************************************************* * This file is part of the Symfony eclipse plugin. * * (c) Robert Gruendler <r.gruendler@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. ******************************************************************************/ package com.dubture.symfony.ui.editor.hyperlink; import org.eclipse.core.filebuffers.ITextFileBuffer; import org.eclipse.core.internal.filebuffers.FileBuffersPlugin; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.IType; import org.eclipse.dltk.core.index2.search.ISearchEngine.MatchRule; import org.eclipse.dltk.core.search.IDLTKSearchScope; import org.eclipse.dltk.core.search.SearchEngine; import org.eclipse.dltk.internal.ui.editor.ModelElementHyperlink; import org.eclipse.dltk.ui.actions.OpenAction; import org.eclipse.jface.text.BadLocationException; 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.php.internal.core.model.PHPModelAccess; import org.eclipse.php.internal.core.project.PHPNature; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.internal.Workbench; import com.dubture.symfony.core.log.Logger; @SuppressWarnings("restriction") public class XmlHyperlinkDetector extends AbstractHyperlinkDetector { private static String PHP_SOURCE = "org.eclipse.php.core.phpsource"; @Override public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { IDocument document = textViewer.getDocument(); int offset = region.getOffset(); ITextFileBuffer textFileBuffer = FileBuffersPlugin.getDefault().getFileBufferManager().getTextFileBuffer(document); if (textFileBuffer == null || textFileBuffer.getFileStore() == null) { return null; } try { if (PHP_SOURCE.equals(textFileBuffer.getContentType().getId())) { // PHP Editor is resolved as XML due WTP extension return null; } IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(textFileBuffer.getFileStore().toURI(), IWorkspaceRoot.INCLUDE_HIDDEN); if (files == null || files.length != 1 || files[0].getProject() == null || !files[0].getProject().hasNature(PHPNature.ID)) { return null; } IDLTKSearchScope scope = SearchEngine.createSearchScope(DLTKCore.create(files[0].getProject())); IRegion wordRegion = findWord(document, offset); if (wordRegion == null) return null; String path = document.get(wordRegion.getOffset(), wordRegion.getLength()); PHPModelAccess model = PHPModelAccess.getDefault(); if (path == null || path.length() == 0) { return null; } IType[] types = model.findTypes(path, MatchRule.EXACT, 0, 0, scope, new NullProgressMonitor()); IWorkbenchPartSite site = Workbench.getInstance().getActiveWorkbenchWindow().getActivePage().getActiveEditor().getSite(); if (types.length > 10) { Logger.debugMSG("Found more than ten (" + types.length + ") types during xml hyperlink detection..."); return null; } if (types != null && types.length > 0) { IHyperlink[] links = new IHyperlink[types.length]; for (int i = 0; i < types.length; i++) { links[i] = new ModelElementHyperlink(wordRegion, types[i], new OpenAction(site)); } return links; } } catch (Exception e) { Logger.logException(e); } return null; } public static IRegion findWord(IDocument document, int offset) { int start = -2; int end = -1; try { int pos = offset; char c; char separator = '>'; int length = document.getLength(); // search backwards until a string delimiter // to find the start position while (pos >= 0) { c = document.getChar(pos); if (c == '"' || c == ' ' || c == '>') { separator = c; break; } --pos; } start = pos; pos++; if (separator == '>') { separator = '<'; } // search forward until a string delimiter // to find the end position while (pos < length) { c = document.getChar(pos); if (c == separator) { end = pos; break; } ++pos; } if (start >= 0 && end != 0) { start++; int rlength = end - start; return new Region(start, rlength); } } catch (BadLocationException x) { } return null; } }