/**
* <copyright>
* </copyright>
*
*
*/
package org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui;
/**
* This class finds the positions to highlight and adds them to the document.
*/
public class MtextOccurrence {
public final static String OCCURRENCE_ANNOTATION_ID = "org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui.occurences";
public final static String DECLARATION_ANNOTATION_ID = "org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui.occurences.declaration";
private final static org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui.MtextPositionHelper positionHelper = new org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui.MtextPositionHelper();
private org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui.MtextTokenScanner tokenScanner;
private java.util.List<String> quotedTokenArray;
private org.eclipse.jface.text.source.projection.ProjectionViewer projectionViewer;
private org.feature.multi.perspective.mapping.viewmapping.resource.mtext.IMtextTextResource textResource;
private String tokenText = "";
private org.eclipse.jface.text.Region tokenRegion;
/**
* Creates the Occurrence class to find position to highlight.
*
* @param textResource the text resource for location
* @param sourceViewer the source viewer for the text
* @param tokenScanner the token scanner helps to find the searched tokens
*/
public MtextOccurrence(org.feature.multi.perspective.mapping.viewmapping.resource.mtext.IMtextTextResource textResource, org.eclipse.jface.text.source.projection.ProjectionViewer sourceViewer, org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui.MtextTokenScanner tokenScanner) {
this.textResource = textResource;
this.projectionViewer = sourceViewer;
quotedTokenArray = new java.util.ArrayList<String>();
String[] tokenNames = new org.feature.multi.perspective.mapping.viewmapping.resource.mtext.mopp.MtextMetaInformation().getTokenNames();
for (String tokenName : tokenNames) {
if (tokenName.startsWith("'") && tokenName.endsWith("'")) {
quotedTokenArray.add(tokenName.substring(1, tokenName.length() - 1).trim());
}
}
this.tokenScanner = tokenScanner;
tokenRegion = new org.eclipse.jface.text.Region(-1, 0);
}
private org.eclipse.emf.ecore.EObject getResolvedEObject(org.eclipse.emf.ecore.EObject eObject) {
return eObject.eIsProxy() ? org.eclipse.emf.ecore.util.EcoreUtil.resolve(eObject, textResource) : eObject;
}
/**
* Tries to resolve the first proxy object in a list.
*
* @param objects the <code>EObject</code>s at the text caret
*
* @return the resolved <code>EObject</code> of the first proxy
* <code>EObject</code> in a list. If there are none returns <code>null</code>
*/
public org.eclipse.emf.ecore.EObject tryToResolve(java.util.List<org.eclipse.emf.ecore.EObject> objects) {
for (org.eclipse.emf.ecore.EObject object : objects) {
if (object.eIsProxy()) {
return getResolvedEObject(object);
}
}
return null;
}
/**
*
* @return the eObject at the current cursor position.
*/
public org.eclipse.emf.ecore.EObject getEObjectAtCurrentPosition() {
org.eclipse.swt.custom.StyledText textWidget = projectionViewer.getTextWidget();
if (textWidget == null) {
return null;
}
int caretOffset = textWidget.getCaretOffset();
caretOffset = projectionViewer.widgetOffset2ModelOffset(caretOffset);
if (textResource == null) {
return null;
}
org.feature.multi.perspective.mapping.viewmapping.resource.mtext.IMtextLocationMap locationMap = textResource.getLocationMap();
java.util.List<org.eclipse.emf.ecore.EObject> elementsAtOffset = locationMap.getElementsAt(caretOffset);
if (elementsAtOffset == null || elementsAtOffset.isEmpty()) {
return null;
}
for (org.eclipse.emf.ecore.EObject candidate : elementsAtOffset) {
if (candidate.eIsProxy()) {
candidate = getResolvedEObject(candidate);
}
// Only accept elements that are actually contained in a resource. The location
// map might reference elements that were removed by a post processor and which
// are therefore not part of the resource anymore.
if (candidate.eResource() != null) {
return candidate;
}
}
return null;
}
/**
* Returns the token text at the caret.
*
* @return the token text
*/
public String getTokenText() {
return tokenText;
}
private int getLength(org.eclipse.emf.ecore.EObject eObject) {
org.feature.multi.perspective.mapping.viewmapping.resource.mtext.IMtextLocationMap locationMap = textResource.getLocationMap();
return locationMap.getCharEnd(eObject) - locationMap.getCharStart(eObject) + 1;
}
/**
* Finds the positions of the occurrences which will be highlighted. The brackets
* and the key words should not be highlighted.
*
* @param bracketSet the set of brackets which have to be ignored.
*/
public void handleOccurrenceHighlighting(org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui.MtextBracketSet bracketSet) {
if (textResource == null) {
return;
}
org.eclipse.swt.custom.StyledText textWidget = projectionViewer.getTextWidget();
int caretOffset = textWidget.getCaretOffset();
caretOffset = projectionViewer.widgetOffset2ModelOffset(caretOffset);
org.eclipse.jface.text.IDocument document = projectionViewer.getDocument();
if (caretOffset < 0 || caretOffset >= document.getLength()) {
return;
}
int tokenRegionOffset = tokenRegion.getOffset();
if (caretOffset >= tokenRegionOffset && caretOffset <= tokenRegionOffset + tokenRegion.getLength()) {
return;
}
tokenRegion = new org.eclipse.jface.text.Region(-1,0);
org.feature.multi.perspective.mapping.viewmapping.resource.mtext.IMtextLocationMap locationMap = textResource.getLocationMap();
java.util.List<org.eclipse.emf.ecore.EObject> elementsAtOffset = locationMap.getElementsAt(caretOffset);
if (elementsAtOffset == null || elementsAtOffset.size() < 1) {
return;
}
org.eclipse.emf.ecore.EObject firstElementAtOffset = elementsAtOffset.get(0);
org.eclipse.emf.ecore.EObject resolvedEO = tryToResolve(elementsAtOffset);
if (resolvedEO != null) {
elementsAtOffset = locationMap.getElementsAt(locationMap.getCharStart(resolvedEO));
}
tokenScanner.setRange(document, locationMap.getCharStart(firstElementAtOffset), getLength(firstElementAtOffset));
org.eclipse.jface.text.rules.IToken token = tokenScanner.nextToken();
while (!token.isEOF()) {
int tokenOffset = tokenScanner.getTokenOffset();
int tokenLength = tokenScanner.getTokenLength();
String text = tokenScanner.getTokenText();
if (tokenOffset <= caretOffset && tokenLength + tokenOffset > caretOffset) {
if (text.trim().equals("")) {
// the rejected elements
return;
}
tokenText = text;
tokenRegion = new org.eclipse.jface.text.Region(tokenOffset, tokenLength);
removeAnnotations();
break;
}
token = tokenScanner.nextToken();
}
if (tokenText == null || tokenText.equals("")) {
return;
}
if ((resolvedEO == null && quotedTokenArray.contains(tokenText)) || (resolvedEO == null && elementsAtOffset.get(0).eResource() == null) || bracketSet.isBracket(tokenText)) {
tokenText = "";
return;
}
try {
setHighlightingPositions(resolvedEO, elementsAtOffset);
} catch (Exception e) {
e.printStackTrace();
}
}
private void setHighlightingPositions(org.eclipse.emf.ecore.EObject definitionElement, java.util.List<org.eclipse.emf.ecore.EObject> elementsAtDefinition) {
org.eclipse.jface.text.IDocument document = projectionViewer.getDocument();
org.feature.multi.perspective.mapping.viewmapping.resource.mtext.IMtextLocationMap locationMap = textResource.getLocationMap();
org.eclipse.jface.text.rules.IToken token;
int defPosition = -1;
if (definitionElement == null) {
definitionElement = elementsAtDefinition.get(0);
}
org.eclipse.emf.ecore.resource.Resource resource = definitionElement.eResource();
if (resource == null) {
return;
}
if (resource.equals(textResource)) {
tokenScanner.setRange(projectionViewer.getDocument(), locationMap.getCharStart(definitionElement), getLength(definitionElement));
token = tokenScanner.nextToken();
while (!token.isEOF()) {
String text = tokenScanner.getTokenText();
if (text.equals(tokenText)) {
defPosition = tokenScanner.getTokenOffset();
addAnnotation(document, org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui.MtextPositionCategory.DEFINTION, text);
break;
}
token = tokenScanner.nextToken();
}
}
tokenScanner.setRange(projectionViewer.getDocument(), 0, projectionViewer.getDocument().getLength());
org.eclipse.emf.ecore.EObject occEO;
token = tokenScanner.nextToken();
while (!token.isEOF()) {
String text = tokenScanner.getTokenText();
if (text != null && text.equals(tokenText) && tokenScanner.getTokenOffset() != defPosition) {
occEO = tryToResolve(locationMap.getElementsAt(tokenScanner.getTokenOffset()));
if (occEO != null) {
if (elementsAtDefinition.contains(occEO) || definitionElement.equals(occEO)) {
addAnnotation(document, org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui.MtextPositionCategory.PROXY, text);
}
}
}
token = tokenScanner.nextToken();
}
}
private void addAnnotation(org.eclipse.jface.text.IDocument document, org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui.MtextPositionCategory type, String text) {
int tokenOffset = tokenScanner.getTokenOffset();
int tokenLength = tokenScanner.getTokenLength();
// for declarations and occurrences we do not need to add the position to the
// document
org.eclipse.jface.text.Position position = positionHelper.createPosition(tokenOffset, tokenLength);
// instead, an annotation is created
org.eclipse.jface.text.source.Annotation annotation = new org.eclipse.jface.text.source.Annotation(false);
if (type == org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui.MtextPositionCategory.DEFINTION) {
annotation.setText("Declaration of " + text);
annotation.setType(DECLARATION_ANNOTATION_ID);
} else {
annotation.setText("Occurrence of " + text);
annotation.setType(OCCURRENCE_ANNOTATION_ID);
}
projectionViewer.getAnnotationModel().addAnnotation(annotation, position);
}
private void removeAnnotations() {
removeAnnotations(org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui.MtextOccurrence.OCCURRENCE_ANNOTATION_ID);
removeAnnotations(org.feature.multi.perspective.mapping.viewmapping.resource.mtext.ui.MtextOccurrence.DECLARATION_ANNOTATION_ID);
}
private void removeAnnotations(String annotationTypeID) {
java.util.List<org.eclipse.jface.text.source.Annotation> annotationsToRemove = new java.util.ArrayList<org.eclipse.jface.text.source.Annotation>();
org.eclipse.jface.text.source.IAnnotationModel annotationModel = projectionViewer.getAnnotationModel();
java.util.Iterator<?> annotationIterator = annotationModel.getAnnotationIterator();
while (annotationIterator.hasNext()) {
Object object = (Object) annotationIterator.next();
if (object instanceof org.eclipse.jface.text.source.Annotation) {
org.eclipse.jface.text.source.Annotation annotation = (org.eclipse.jface.text.source.Annotation) object;
if (annotationTypeID.equals(annotation.getType())) {
annotationsToRemove.add(annotation);
}
}
}
for (org.eclipse.jface.text.source.Annotation annotation : annotationsToRemove) {
annotationModel.removeAnnotation(annotation);
}
}
/**
* Check whether it is time to remove the occurrence highlighting.
*
* @return <code>true</code> if the caret changed the token.
*/
public boolean isToRemoveHighlighting() {
org.eclipse.swt.custom.StyledText textWidget = projectionViewer.getTextWidget();
int caretOffset = textWidget.getCaretOffset();
caretOffset = projectionViewer.widgetOffset2ModelOffset(caretOffset);
if (caretOffset >= tokenRegion.getOffset() && caretOffset <= tokenRegion.getOffset() + tokenRegion.getLength()) {
return false;
}
return true;
}
/**
* Resets the token region to enable remove highlighting if the text is changing.
*/
public void resetTokenRegion(){
tokenRegion = new org.eclipse.jface.text.Region(-1, 0);
}
}