blob: 4cbf9efcaf70c9dd5d45bdb288662f4d84c38e09 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2004, 2008 Fraunhofer Gesellschaft, Munich, Germany,
* for its Fraunhofer Institute for Computer Architecture and Software
* Technology (FIRST), Berlin, Germany and Technical University Berlin,
* Germany.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
* Fraunhofer FIRST - Initial API and implementation
* Technical University Berlin - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.otdt.internal.ui.callinmarkers;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.RegistryFactory;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jdt.internal.ui.javaeditor.IClassFileEditorInput;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.source.IVerticalRulerInfo;
import org.eclipse.objectteams.otdt.core.IOTType;
import org.eclipse.objectteams.otdt.core.IRoleType;
import org.eclipse.objectteams.otdt.core.OTModelManager;
import org.eclipse.objectteams.otdt.internal.ui.OTDTUIPluginConstants;
import org.eclipse.objectteams.otdt.ui.IUpdateRulerActionExtender;
import org.eclipse.objectteams.otdt.ui.OTDTUIPlugin;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.texteditor.AbstractRulerActionDelegate;
import org.eclipse.ui.texteditor.ITextEditor;
/**
* Action that is executed when the user right clicks on a binding marker at
* the vertical ruler and chooses a mapping (bound role class or callin mapping)
* from the ObjectTeams submenu.
*
* @author brcan
* @version $Id: UpdateRulerAction.java 23435 2010-02-04 00:14:38Z stephan $
*/
public class UpdateRulerAction extends AbstractRulerActionDelegate
{
public final static String OT_PLAYEDBY_MENU_LABEL = OTDTUIPlugin.getResourceString("CallinMarker.menu_playedby_title"); //$NON-NLS-1$
public final static String OT_CALLIN_MENU_LABEL = OTDTUIPlugin.getResourceString("CallinMarker.menu_callin_title"); //$NON-NLS-1$
public final static String OT_CALLOUT_MENU_LABEL = OTDTUIPlugin.getResourceString("CallinMarker.menu_callout_title"); //$NON-NLS-1$
private IEditorPart _editor = null;
private IVerticalRulerInfo _rulerInfo = null;
private List<IUpdateRulerActionExtender> extenders = null;
public UpdateRulerAction()
{
}
public void setActiveEditor(IAction callerAction, IEditorPart targetEditor)
{
_editor = targetEditor;
super.setActiveEditor(callerAction, targetEditor);
}
protected IAction createAction(ITextEditor editor, IVerticalRulerInfo rulerInfo)
{
_rulerInfo = rulerInfo;
return null;
}
public void menuAboutToShow(IMenuManager contextMenu)
{
IDocument document = null;
int clickedLine = _rulerInfo.getLineOfLastMouseButtonActivity();
if (this._editor instanceof ITextEditor) {
ITextEditor textEditor = (ITextEditor) this._editor;
document= textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput());
}
try
{
IMarker[] markers = findCallinMarkers();
if (markers != null && markers.length != 0)
{
for (int idx = 0; idx < markers.length; idx++)
{
IMarker curMarker = markers[idx];
int line = curMarker.getAttribute(IMarker.LINE_NUMBER, -1);
if (line != -1)
{
if (line-1 == clickedLine) // IMarker.LINE_NUMBER is 1-based, others are 0-based
insertTeamMenus(contextMenu, curMarker);
} else if (document != null) {
// markers in ClassFileEditor have no line number, must go via position:
int start = curMarker.getAttribute(IMarker.CHAR_START, -1);
try {
if (clickedLine == document.getLineOfOffset(start))
insertTeamMenus(contextMenu, curMarker);
}
catch (BadLocationException e) { /* nop */ }
}
}
}
}
catch (CoreException ex)
{
OTDTUIPlugin.logException("Problems extending ruler context menu", ex); //$NON-NLS-1$
}
// load and notify extenders:
if (this.extenders == null)
loadExtenders();
for (IUpdateRulerActionExtender extender : this.extenders)
extender.menuAboutToShow(contextMenu, document, this._editor, clickedLine);
}
private IMarker[] findCallinMarkers() throws CoreException
{
final IEditorInput editorInput = _editor.getEditorInput();
if (editorInput instanceof IFileEditorInput)
{
IFileEditorInput fileEditorInput = (IFileEditorInput)editorInput;
IFile file = fileEditorInput.getFile();
IMarker[] result = CallinMarker.getAllBindingMarkers(file);
return result;
}
else if (editorInput instanceof IClassFileEditorInput)
{
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IMarker[] allMarkers = CallinMarker.getAllBindingMarkers(root);
// now we have all CallinMarkers for all class files in the workspace, need to filter now:
IClassFile classFile = ((IClassFileEditorInput) editorInput).getClassFile();
List<IMarker> filteredMarkers = new ArrayList<IMarker>(13);
for (IMarker marker : allMarkers)
if (JavaCore.isReferencedBy(classFile, marker))
filteredMarkers.add(marker);
return filteredMarkers.toArray(new IMarker[filteredMarkers.size()]);
}
return null;
}
/** Get the context menu of kind 'markerKind', creating it if ondemand. */
private IMenuManager getObjectTeamsMenu(IMenuManager contextMenu, String markerKind)
{
String label;
if (CallinMarker.CALLIN_ID.equals(markerKind))
label = OT_CALLIN_MENU_LABEL;
else if (CallinMarker.CALLOUT_ID.equals(markerKind))
label = OT_CALLOUT_MENU_LABEL;
else
label = OT_PLAYEDBY_MENU_LABEL;
IMenuManager subMenu = getSubMenu(contextMenu, label);
if (subMenu != null)
return subMenu;
MenuManager otMenu = new MenuManager(label, markerKind); // id cannot be null, re-use the markerKind
if (contextMenu.isEmpty())
contextMenu.add(otMenu);
else // insert on top
contextMenu.insertBefore(contextMenu.getItems()[0].getId(), otMenu);
return otMenu;
}
private IAction createOpenEditorAction(String label, final IJavaElement target)
{
Action result = new Action(label)
{
public void run()
{
try
{
IEditorPart part = EditorUtility.openInEditor(target);
if (target.exists()) // also initializes source positions if necessary
EditorUtility.revealInEditor(part, target);
}
catch (PartInitException ex)
{
OTDTUIPlugin.logException("Problems initializing editor", ex); //$NON-NLS-1$
}
}
};
return result;
}
List<IMember> getMappings (IMarker marker) throws CoreException
{
Object attr = marker.getAttribute(CallinMarker.ATTR_ROLE_ELEMENTS);
if (attr == null || !(attr instanceof String))
return null;
String str = (String)attr;
List<IMember> result = new ArrayList<IMember>();
int start = 0;
int pos;
while ((pos = str.indexOf('\n', start)) != -1) {
result.add((IMember)JavaCore.create(str.substring(start, pos)));
start = pos+1;
}
return result;
}
private void insertTeamMenus(IMenuManager contextMenu, IMarker marker) throws CoreException
{
List<IMember> mappings = getMappings(marker);
if (mappings == null) return;
IMenuManager otMenu = getObjectTeamsMenu(contextMenu, marker.getType());
for (IMember curMapping : mappings)
{
IType type = (IType)(curMapping.getAncestor(IJavaElement.TYPE));
IOTType otType = OTModelManager.getOTElement(type); // FIXME(SH): doesn't find role files??? (try StubUtility2)
if (otType == null || !otType.isRole())
continue;
IOTType teamType = ((IRoleType) otType).getTeam();
IMenuManager curTeamMenu = null;
if (!isSubMenuContained(otMenu, teamType.getElementName()))
{
curTeamMenu = new MenuManager(teamType.getElementName());
otMenu.add(curTeamMenu);
}
else
{
curTeamMenu = getSubMenu(otMenu, teamType.getElementName());
}
String actLabel = getMappingLabel(type, curMapping);
curTeamMenu.add(createOpenEditorAction(actLabel, curMapping));
}
}
private String getMappingLabel(IType type, IMember mapping)
{
if (type.equals(mapping)) return type.getElementName();
return type.getElementName() + ": " + mapping.getElementName(); //$NON-NLS-1$
}
private IMenuManager getSubMenu(IMenuManager otMenu, String subMenuName)
{
if (otMenu == null)
return null;
IContributionItem[] items = otMenu.getItems();
for (int idx = 0; idx < items.length; idx++)
{
if (items[idx] instanceof IMenuManager)
{
MenuManager cur = (MenuManager)items[idx];
if (cur.getMenuText().equals(subMenuName))
{
return cur;
}
}
}
return null;
}
private boolean isSubMenuContained(IMenuManager menu, String subMenuName)
{
return getSubMenu(menu, subMenuName) != null;
}
private void loadExtenders() {
this.extenders = new ArrayList<IUpdateRulerActionExtender>();
IConfigurationElement[] configs = RegistryFactory.getRegistry().getConfigurationElementsFor(
OTDTUIPluginConstants.UIPLUGIN_ID, OTDTUIPluginConstants.UPDATE_RULER_ACTION_EXTENDER_ID);
for (IConfigurationElement config : configs) {
try {
if (this._editor.getClass().getName().equals(config.getAttribute(OTDTUIPluginConstants.UPDATE_RULER_ACTION_EXTENDER_EDITORCLASS)))
this.extenders.add((IUpdateRulerActionExtender) config.createExecutableExtension(OTDTUIPluginConstants.UPDATE_RULER_ACTION_EXTENDER_CLASS));
} catch (CoreException e) {
OTDTUIPlugin.log(e);
}
}
}
}