/******************************************************************************* * 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.runtime.CoreException; import org.eclipse.dltk.core.IMethod; import org.eclipse.dltk.core.IScriptFolder; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.IType; import org.eclipse.dltk.internal.ui.editor.EditorUtility; import org.eclipse.dltk.internal.ui.editor.ModelElementHyperlink; import org.eclipse.dltk.ui.actions.OpenAction; 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.IHyperlink; import org.eclipse.php.internal.ui.editor.PHPStructuredEditor; import com.dubture.symfony.core.builder.SymfonyNature; import com.dubture.symfony.core.log.Logger; import com.dubture.symfony.core.model.SymfonyModelAccess; import com.dubture.symfony.core.model.ViewPath; /** * * {@link ViewpathHyperlinkDetector} links viewPaths to the corresponding * template / action / controller. * * * * @author "Robert Gruendler <r.gruendler@gmail.com>" * */ @SuppressWarnings("restriction") public class ViewpathHyperlinkDetector extends StringHyperlinkDetector { private ISourceModule input; private PHPStructuredEditor editor; private IHyperlink getControllerlink(ViewPath viewPath, IRegion wordRegion) { IType controller = SymfonyModelAccess.getDefault().findController(viewPath.getBundle(), viewPath.getController(), input.getScriptProject()); if (controller != null) { String tpl = viewPath.getTemplate(); // try to open a corresponding action try { String action = tpl.substring(0, tpl.indexOf(".")); if (action.length() > 0) { IMethod method = controller.getMethod(action + "Action"); return new ModelElementHyperlink(wordRegion, method, new OpenAction(editor)); } } catch (Exception e) { // ignore and open the controller } return new ModelElementHyperlink(wordRegion, controller, new OpenAction(editor)); } return null; } private IHyperlink getTemplateLink(ViewPath viewPath, IRegion wordRegion) { IScriptFolder folder = SymfonyModelAccess.getDefault().findBundleFolder(viewPath.getBundle(), input.getScriptProject()); if (folder == null) { Logger.debugMSG("Unable to resolve template link: " + viewPath); return null; } String path = "Resources/views/"; if (viewPath.getController() != null) { path += viewPath.getController() + "/"; } path += viewPath.getTemplate(); ISourceModule module = folder.getSourceModule(path); if (module != null) { return new ModelElementHyperlink(wordRegion, module, new OpenAction(editor)); } return null; } @Override public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { editor = org.eclipse.php.internal.ui.util.EditorUtility .getPHPEditor(textViewer); if (editor == null || region == null) { return null; } input = EditorUtility.getEditorInputModelElement(editor, false); if (input == null) { editor = null; return null; } try { if (input.getScriptProject() == null || !input.getScriptProject().getProject().hasNature(SymfonyNature.NATURE_ID)) { return null; } } catch (CoreException e1) { return null; } IDocument document = textViewer.getDocument(); int offset = region.getOffset(); try { IRegion wordRegion = findWord(document, offset); if (wordRegion == null) { return null; } String path = document.get(wordRegion.getOffset(), wordRegion.getLength()); if (wordRegion.getOffset() > 0) { String start = document.get(wordRegion.getOffset() - 1, 1); if (!start.equals("'") && !start.equals("\"") && !start.equals(",")) { // this is not a string. Might be static member access return null; } } ViewPath viewPath = new ViewPath(path); // "AcmeDemoBundle::layout.html.twig" 2 part viewpath // link the whole thing to the template if (path.contains("::")) { String[] parts = path.split("::"); if (parts.length == 2) { IHyperlink link = getTemplateLink(viewPath, wordRegion); if (link != null) { return new IHyperlink[] { link }; } } // "AcmeDemoBundle:Demo:index.html.twig" 3 part viewpath // link the controller and the template separately } else if (path.contains(":")) { String[] parts = path.split(":"); if (parts.length == 3) { int controllerLength = parts[0].length() + parts[1].length() + 1; int deltaOffset = offset - wordRegion.getOffset(); if (deltaOffset < controllerLength) { Region controllerRegion = new Region(wordRegion.getOffset(), controllerLength); IHyperlink link = getControllerlink(viewPath, controllerRegion); if (link != null) { return new IHyperlink[] { link }; } } else { Region templateRegion = new Region(wordRegion.getOffset() + controllerLength + 1, parts[2].length()); IHyperlink link = getTemplateLink(viewPath, templateRegion); if (link != null) { return new IHyperlink[] { link }; } } } } } catch (Exception e) { Logger.logException(e); } finally { input = null; editor = null; } return null; } }