/******************************************************************************* * Copyright (c) 2008 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.seam.ui.handlers; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IStatus; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor; import org.eclipse.jdt.internal.ui.search.SearchMessages; import org.eclipse.jdt.internal.ui.search.SearchUtil; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.MultiPageEditorPart; import org.eclipse.ui.progress.IProgressService; import org.eclipse.ui.texteditor.AbstractTextEditor; import org.jboss.tools.common.el.core.model.ELInvocationExpression; import org.jboss.tools.common.model.ui.editor.EditorPartWrapper; import org.jboss.tools.common.model.ui.texteditors.xmleditor.XMLTextEditor; import org.jboss.tools.jst.web.ui.internal.editor.jspeditor.JSPMultiPageEditor; import org.jboss.tools.seam.core.ISeamContextVariable; import org.jboss.tools.seam.core.ISeamProject; import org.jboss.tools.seam.core.SeamCorePlugin; import org.jboss.tools.seam.internal.core.el.SeamELCompletionEngine; import org.jboss.tools.seam.ui.SeamGuiPlugin; import org.jboss.tools.seam.ui.search.SeamSearchQuery; import org.jboss.tools.seam.ui.search.SeamSearchScope; abstract public class FindSeamHandler extends AbstractHandler implements ISelectionListener{ public FindSeamHandler(){ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (window != null) { window.getSelectionService().addSelectionListener(this); } } /** * @Override */ public void run() { } /* * Returns editor from a given workbench window * * @param window * @return */ private IEditorPart getCurrentEditor(IWorkbenchWindow window) { if (window == null || window.getActivePage() == null) return null; return window.getActivePage().getActiveEditor(); } /* * Returns viewer for a given editor * * @param editor * @return */ private ISourceViewer getEditorViewer(IWorkbenchPart editor) { ISourceViewer viewer = null; if (editor instanceof EditorPartWrapper) { editor = ((EditorPartWrapper)editor).getEditor(); } if (editor instanceof JSPMultiPageEditor) { viewer = ((JSPMultiPageEditor)editor).getJspEditor().getTextViewer(); } else if (editor instanceof XMLTextEditor) { viewer = ((XMLTextEditor)editor).getTextViewer(); } else if (editor instanceof MultiPageEditorPart) { IEditorPart activeEditor = getActiveEditor((MultiPageEditorPart)editor); if (activeEditor instanceof AbstractTextEditor) { viewer = getSourceViewer((AbstractTextEditor)activeEditor); } } else if (editor instanceof AbstractTextEditor ) { viewer = getSourceViewer((AbstractTextEditor)editor); } else if (editor instanceof CompilationUnitEditor) { viewer = ((CompilationUnitEditor)editor).getViewer(); } return viewer; } /* * Returns {@link ITextSelection} for a given viewer * * @param viewer * @return */ private ITextSelection getTextSelection(ITextViewer viewer) { if (viewer == null || viewer.getSelectionProvider() == null) return null; return getTextSelection(viewer.getSelectionProvider().getSelection()); } /* * Returns {@link ITextSelection} for a given {@link ISelection} * * @param selection * @return */ private ITextSelection getTextSelection(ISelection selection) { if (selection == null || selection.isEmpty()) return null; if (selection instanceof ITextSelection) { return (ITextSelection)selection; } return null; } public Object execute(ExecutionEvent event) throws ExecutionException { IWorkbenchPart activeWorkbenchPart = getCurrentEditor(getActiveWorkbenchWindow()); if (activeWorkbenchPart == null) return null; IEditorInput input = (activeWorkbenchPart instanceof IEditorPart ? ((IEditorPart)activeWorkbenchPart).getEditorInput() : null); ISourceViewer viewer = getEditorViewer(activeWorkbenchPart); if (viewer == null) return null; ITextSelection selection = getTextSelection(viewer); if (selection == null) return null; int selectionOffset = selection.getOffset(); IDocument document = viewer.getDocument(); IFile file = null; if (input instanceof IFileEditorInput) { file = ((IFileEditorInput)input).getFile(); } IProject project = (file == null ? null : file.getProject()); ISeamProject seamProject = SeamCorePlugin.getSeamProject(project, true); if (seamProject == null) return null; ELInvocationExpression expression = SeamELCompletionEngine.findExpressionAtOffset( document, selectionOffset, 0, document.getLength()); if (expression == null) return null; // No EL Operand found try { performNewSearch(expression, file); } catch (JavaModelException jme) { SeamGuiPlugin.getPluginLog().logError(jme); } catch (InterruptedException ie) { SeamGuiPlugin.getPluginLog().logError(ie); } return null; } /** * Finds the variable names for the selected ELOperandToken tokens * * @param seamProject * @param document * @param tokens * @return */ public static String[] findVariableNames(ISeamProject seamProject, IDocument document, ELInvocationExpression tokens) { String[] varNames = null; if(tokens == null) return varNames; // Define the Seam project variables to search for declarations List<ISeamContextVariable> variables = new ArrayList<ISeamContextVariable>(); while(tokens != null) { try { int start = tokens.getStartPosition(); int end = tokens.getEndPosition(); String variationText = document.get(start, end - start); Set<ISeamContextVariable> vars = seamProject.getVariablesByName(variationText); if (vars != null) variables.addAll(vars); } catch (BadLocationException e1) { SeamGuiPlugin.getPluginLog().logError(e1); } tokens = tokens.getLeft(); } if (!variables.isEmpty()) { // Some variable/variables are found - perform search for their declarations varNames = new String[variables.size()]; for (int i = 0; i < variables.size(); i++) { varNames[i] = variables.get(i).getName(); } } return varNames; } /** * @Override */ public void selectionChanged(IAction action, ISelection selection) { selectionChanged(getCurrentEditor(getActiveWorkbenchWindow()), selection); } private SeamSearchQuery createQuery(ELInvocationExpression tokens, IFile sourceFile) throws JavaModelException, InterruptedException { SeamSearchScope scope = new SeamSearchScope(new IProject[] {sourceFile.getProject()}, getLimitTo()); return new SeamSearchQuery(tokens, sourceFile, scope); } /** * Returns the limitTo flag. The possible values are: * - SeamSearchScope.SEARCH_FOR_DECLARATIONS * - SeamSearchScope.SEARCH_FOR_REFERENCES * @return */ abstract protected int getLimitTo(); private void performNewSearch(ELInvocationExpression tokens, IFile sourceFile) throws JavaModelException, InterruptedException { SeamSearchQuery query= createQuery(tokens, sourceFile); if (query.canRunInBackground()) { /* * This indirection with Object as parameter is needed to prevent the loading * of the Search plug-in: the VM verifies the method call and hence loads the * types used in the method signature, eventually triggering the loading of * a plug-in (in this case ISearchQuery results in Search plug-in being loaded). */ SearchUtil.runQueryInBackground(query); } else { IProgressService progressService= PlatformUI.getWorkbench().getProgressService(); /* * This indirection with Object as parameter is needed to prevent the loading * of the Search plug-in: the VM verifies the method call and hence loads the * types used in the method signature, eventually triggering the loading of * a plug-in (in this case it would be ISearchQuery). */ IStatus status= SearchUtil.runQueryInForeground(progressService, query); if (status.matches(IStatus.ERROR | IStatus.INFO | IStatus.WARNING)) { ErrorDialog.openError(getShell(), SearchMessages.Search_Error_search_title, SearchMessages.Search_Error_search_message, status); } } } /** * Returns the active editor from active MultipageEditor * * @param multiPageEditor * @return */ public static IEditorPart getActiveEditor(MultiPageEditorPart multiPageEditor) { Class editorClass = multiPageEditor.getClass(); while (editorClass != null) { try { Method m = editorClass.getDeclaredMethod("getActiveEditor", new Class[] {}); if(m != null) { m.setAccessible(true); Object result = m.invoke(multiPageEditor, new Object[]{}); return (result instanceof IEditorPart ? (IEditorPart)result : null); } } catch (NoSuchMethodException e) { // ignore } catch (IllegalArgumentException e) { // ignore } catch (IllegalAccessException e) { // ignore } catch (InvocationTargetException e) { // ignore } editorClass = editorClass.getSuperclass(); } return null; } /** * Returns the source viewer from AbstractTextEditor * * @param multiPageEditor * @return */ public static ISourceViewer getSourceViewer(AbstractTextEditor editor) { Class editorClass = editor.getClass(); while (editorClass != null) { try { Method m = editorClass.getDeclaredMethod("getSourceViewer", new Class[] {}); if(m != null) { m.setAccessible(true); Object result = m.invoke(editor, new Object[]{}); return (result instanceof ISourceViewer ? (ISourceViewer)result : null); } } catch (NoSuchMethodException e) { // ignore } catch (IllegalArgumentException e) { // ignore } catch (IllegalAccessException e) { // ignore } catch (InvocationTargetException e) { // ignore } editorClass = editorClass.getSuperclass(); } return null; } /* * Returns current Shell * * @return */ private Shell getShell() { return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); } // IWorkbenchPart fActiveWorkbenchPart = null; /* * Returns the workbench * * @return */ private IWorkbench getWorkbench() { return PlatformUI.getWorkbench(); } /* * Returns active workbench window * @return */ private IWorkbenchWindow getActiveWorkbenchWindow() { return (getWorkbench() == null ? null : getWorkbench().getActiveWorkbenchWindow()); } /* * Updates availability on the action delegate * * @param selection */ private void update(ISelection selection) { boolean enabled = false; try { IWorkbenchPart activeWorkbenchPart = getCurrentEditor(getActiveWorkbenchWindow()); if (!(activeWorkbenchPart instanceof IEditorPart)) return; ISourceViewer viewer = getEditorViewer((IEditorPart)activeWorkbenchPart); if (viewer == null) return; enabled = (getTextSelection(selection) != null); } finally { setBaseEnabled(enabled); } } // ISelectionListener public void selectionChanged(IWorkbenchPart part, ISelection selection) { update(getTextSelection(getEditorViewer(part))); } }