blob: 1dab2751a0c58d8b5818c94aadb60d703863328e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* IBM Corporation - initial API and implementation
* Miguel Garcia (Tech Univ Hamburg-Harburg) - customization for EMF Generics
*******************************************************************************/
package org.eclipse.emf.emfatic.ui.editor;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.emfatic.core.lang.gen.ast.BoundExceptWildcard;
import org.eclipse.emf.emfatic.core.lang.gen.ast.CompUnit;
import org.eclipse.emf.emfatic.core.lang.gen.ast.EmfaticASTNode;
import org.eclipse.emf.emfatic.core.lang.gen.ast.TopLevelDecl;
import org.eclipse.gymnast.runtime.core.ast.ASTNode;
import org.eclipse.gymnast.runtime.core.outline.OutlineNode;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ISynchronizable;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IAnnotationModelExtension;
import org.eclipse.jface.viewers.IPostSelectionProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.ui.texteditor.IDocumentProvider;
public class EmfaticEditorSelectionListener implements ISelectionChangedListener {
private EmfaticEditor _editor = null;
public EmfaticEditorSelectionListener(EmfaticEditor editor) {
_editor = editor;
}
/**
* places as in the Java editor a highlight range on the left for the chosen
* class, datatype, enum, or mapentry
*/
public void highlightRangeForTopLevelDecl(ITextSelection selection) {
_editor.resetHighlightRange();
ITextSelection ts = (ITextSelection) selection;
/*
* highlight the border of the top-level declaration at the cursor, if
* any
*/
int offset = ts.getOffset();
int length = ts.getLength();
ASTNode declAtCursor = _editor.getClosestEnclosingASTNodeAt(offset, length, TopLevelDecl.class);
if ((declAtCursor != null) && declAtCursor instanceof TopLevelDecl) {
_editor.setHighlightRange(declAtCursor.getRangeStart(), declAtCursor.getRangeLength(), false);
}
}
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
if (selection instanceof ITextSelection) {
ITextSelection textSelection = (ITextSelection) selection;
highlightRangeForTopLevelDecl(textSelection);
markOccurrences(textSelection);
selectInOutline(textSelection);
}
}
private void selectInOutline(ITextSelection ts) {
int offset = ts.getOffset();
int length = ts.getLength();
EmfaticASTNode n = _editor.getClosestEnclosingASTNodeAt(offset, length, Object.class);
CompUnit compUnit = (CompUnit) _editor.getParseRoot();
if (compUnit == null) {
return;
}
Map<ASTNode, OutlineNode> a2o = compUnit.getCst2Outline();
OutlineNode toHighlight = findOutlineNodeFor(n, a2o);
if (toHighlight == null) {
return;
}
ISelection currentOutlineSelection = _editor.getContentOutlinePage().getSelection();
OutlineNode selected = null;
if (currentOutlineSelection instanceof TreeSelection) {
selected = (OutlineNode) ((TreeSelection) currentOutlineSelection).getFirstElement();
}
boolean skipSelect = (selected == toHighlight);
if (!skipSelect) {
_editor.getContentOutlinePage().selectFromEditor(toHighlight);
}
}
private OutlineNode findOutlineNodeFor(ASTNode n, Map<ASTNode, OutlineNode> a2o) {
if (a2o == null) {
return null;
}
OutlineNode res = a2o.get(n);
if (res != null) {
return res;
}
if (n != null && n.getParent() != null) {
res = findOutlineNodeFor(n.getParent(), a2o);
return res;
}
return null;
}
private void markOccurrences(ITextSelection ts) {
removeOccurrenceAnnotations();
int offset = ts.getOffset();
int length = ts.getLength();
BoundExceptWildcard cstUse = (BoundExceptWildcard) _editor.getClosestEnclosingASTNodeAt(offset, length,
BoundExceptWildcard.class);
if (cstUse == null) {
return;
}
EObject ecoreDecl = _editor.getEcoreDecl2CstUse().getInv(cstUse.getRawTNameOrTVarOrParamzedTName());
if (ecoreDecl == null) {
return;
}
Set<ASTNode> occuNodes = _editor.getEcoreDecl2CstUse().get(ecoreDecl);
Map<Annotation, Position> annotationMap = new HashMap<Annotation, Position>();
for (ASTNode n : occuNodes) {
String message = "";
Position pos = new Position(n.getRangeStart(), n.getRangeLength());
try {
message = _editor.getDocument().get(pos.offset, pos.length);
} catch (BadLocationException ex) {
// Skip this match
continue;
}
Annotation ann = new Annotation("org.eclipse.jdt.ui.occurrences", false, message);
annotationMap.put(ann, pos);
}
IDocumentProvider documentProvider = _editor.getDocumentProvider();
IDocument document = _editor.getDocument();
IAnnotationModel annotationModel = documentProvider.getAnnotationModel(_editor.getEditorInput());
if (annotationModel == null)
return;
Object lock = getLockObject(document);
if (lock == null) {
updateAnnotations(annotationModel, annotationMap);
} else {
synchronized (lock) {
updateAnnotations(annotationModel, annotationMap);
}
}
}
private void updateAnnotations(IAnnotationModel annotationModel, Map annotationMap) {
if (annotationModel instanceof IAnnotationModelExtension) {
((IAnnotationModelExtension) annotationModel).replaceAnnotations(fOccurrenceAnnotations, annotationMap);
} else {
removeOccurrenceAnnotations();
Iterator iter = annotationMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry mapEntry = (Map.Entry) iter.next();
annotationModel.addAnnotation((Annotation) mapEntry.getKey(), (Position) mapEntry.getValue());
}
}
fOccurrenceAnnotations = (Annotation[]) annotationMap.keySet().toArray(
new Annotation[annotationMap.keySet().size()]);
}
private void removeOccurrenceAnnotations() {
IDocumentProvider documentProvider = _editor.getDocumentProvider();
if (documentProvider == null) {
return;
}
IAnnotationModel annotationModel = documentProvider.getAnnotationModel(_editor.getEditorInput());
if (annotationModel == null || fOccurrenceAnnotations == null) {
return;
}
IDocument document = documentProvider.getDocument(_editor.getEditorInput());
Object lock = getLockObject(document);
if (lock == null) {
updateAnnotationModelForRemoves(annotationModel);
} else {
synchronized (lock) {
updateAnnotationModelForRemoves(annotationModel);
}
}
}
private void updateAnnotationModelForRemoves(IAnnotationModel annotationModel) {
if (annotationModel instanceof IAnnotationModelExtension) {
((IAnnotationModelExtension) annotationModel).replaceAnnotations(fOccurrenceAnnotations, null);
} else {
for (int i = 0, length = fOccurrenceAnnotations.length; i < length; i++) {
annotationModel.removeAnnotation(fOccurrenceAnnotations[i]);
}
}
fOccurrenceAnnotations = null;
}
private Annotation[] fOccurrenceAnnotations = null;
/**
* Installs this selection changed listener with the given selection
* provider. If the selection provider is a post selection provider, post
* selection changed events are the preferred choice, otherwise normal
* selection changed events are requested.
*
* @param selectionProvider
*/
public void install(ISelectionProvider selectionProvider) {
if (selectionProvider == null) {
return;
}
if (selectionProvider instanceof IPostSelectionProvider) {
IPostSelectionProvider provider = (IPostSelectionProvider) selectionProvider;
provider.addPostSelectionChangedListener(this);
} else {
selectionProvider.addSelectionChangedListener(this);
}
}
/**
* Removes this selection changed listener from the given selection
* provider.
*
* @param selectionProvider
*/
public void uninstall(ISelectionProvider selectionProvider) {
if (selectionProvider == null) {
return;
}
if (selectionProvider instanceof IPostSelectionProvider) {
IPostSelectionProvider provider = (IPostSelectionProvider) selectionProvider;
provider.removePostSelectionChangedListener(this);
} else {
selectionProvider.removeSelectionChangedListener(this);
}
}
private Object getLockObject(IDocument doc) {
Object lock = null;
if (doc instanceof ISynchronizable) {
lock = ((ISynchronizable) doc).getLockObject();
}
return lock;
}
}