/*******************************************************************************
* Copyright (c) 2005 - 2008 committers of openArchitectureWare and others. All
* rights reserved. This program and the accompanying materials are 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: committers of openArchitectureWare - initial API and
* implementation
******************************************************************************/
package org.eclipse.xtend.shared.ui.editor;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.ResourceBundle;
import java.util.Vector;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.ui.actions.IJavaEditorActionDefinitionIds;
import org.eclipse.jdt.ui.actions.JdtActionConstants;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.IDocumentExtension3;
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.DefaultCharacterPairMatcher;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IAnnotationModelExtension2;
import org.eclipse.jface.text.source.ICharacterPairMatcher;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.IPostSelectionProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.actions.ActionContext;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.MarkerAnnotation;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
import org.eclipse.ui.texteditor.TextOperationAction;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.eclipse.xtend.shared.ui.Activator;
import org.eclipse.xtend.shared.ui.editor.navigation.OpenAction;
import org.eclipse.xtend.shared.ui.editor.outlineview.AbstractExtXptContentOutlinePage;
import org.eclipse.xtend.shared.ui.editor.preferences.UiPreferenceConstants;
import org.eclipse.xtend.shared.ui.editor.search.actions.SearchActionGroup;
public abstract class AbstractXtendXpandEditor extends TextEditor {
private AbstractExtXptContentOutlinePage outlinePage = null;
private SearchActionGroup searchActionGroup;
private BreakpointActionGroup bpActionGroup;
private ISelectionChangedListener selectionChangedListener;
public final static String XTEND_MATCHING_BRACKETS = "xtendMatchingBrackets";
public final static String XTEND_MATCHING_BRACKETS_COLOR= "xtendMatchingBracketsColor";
private IPropertyChangeListener preferencesChangedListener;
/**
* @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#createPartControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createPartControl(Composite parent) {
super.createPartControl(parent);
selectionChangedListener = new ISelectionChangedListener() {
public void selectionChanged(final SelectionChangedEvent event) {
updateStatusLine();
}
};
installSelectionChangedListener();
preferencesChangedListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event)
{
if(event.getProperty().startsWith(UiPreferenceConstants.PREFIX))
{
AbstractXtendXpandSourceViewerConfiguration config = (AbstractXtendXpandSourceViewerConfiguration) getSourceViewerConfiguration();
config.refresh();
getSourceViewer().invalidateTextPresentation();
}
}
};
Activator.getDefault().getPreferenceStore().addPropertyChangeListener(preferencesChangedListener);
}
private void installSelectionChangedListener() {
final ISelectionProvider selectionProvider = getSelectionProvider();
if (selectionProvider instanceof IPostSelectionProvider) {
final IPostSelectionProvider postSelectionProvider = (IPostSelectionProvider) selectionProvider;
postSelectionProvider.addPostSelectionChangedListener(selectionChangedListener);
}
else {
getSelectionProvider().addSelectionChangedListener(selectionChangedListener);
}
}
/**
* @see org.eclipse.ui.editors.text.TextEditor#dispose()
*/
@Override
public void dispose() {
super.dispose();
uninstallSelectionChangedListener();
if (preferencesChangedListener != null) {
Activator.getDefault().getPreferenceStore().removePropertyChangeListener(preferencesChangedListener);
}
}
private void uninstallSelectionChangedListener() {
if (selectionChangedListener != null) {
final ISelectionProvider selectionProvider = getSelectionProvider();
if (selectionProvider != null) {
if (selectionProvider instanceof IPostSelectionProvider) {
final IPostSelectionProvider postSelectionProvider = (IPostSelectionProvider) selectionProvider;
postSelectionProvider.removePostSelectionChangedListener(selectionChangedListener);
}
else {
selectionProvider.removeSelectionChangedListener(selectionChangedListener);
}
}
}
}
@Override
public void doRevertToSaved() {
super.doRevertToSaved();
if (outlinePage != null) {
this.outlinePage.refresh();
}
}
@Override
public void doSave(final IProgressMonitor aMonitor) {
super.doSave(aMonitor);
if (outlinePage != null) {
this.outlinePage.refresh();
}
}
@Override
public void doSaveAs() {
super.doSaveAs();
if (outlinePage != null) {
this.outlinePage.refresh();
}
}
@Override
protected void editorContextMenuAboutToShow(final IMenuManager menu) {
menu.add(new Separator("Xpand"));
super.editorContextMenuAboutToShow(menu);
final ActionContext context = new ActionContext(getSelectionProvider().getSelection());
searchActionGroup.setContext(context);
searchActionGroup.fillContextMenu(menu);
searchActionGroup.setContext(null);
bpActionGroup.fillContextMenu(menu);
}
@SuppressWarnings("rawtypes")
@Override
public Object getAdapter(final Class aRequired) {
if (IContentOutlinePage.class.equals(aRequired)) {
if (this.outlinePage == null) {
outlinePage = createOutlinePage();
if (getEditorInput() != null) {
outlinePage.setInput(getEditorInput());
}
}
return outlinePage;
}
return super.getAdapter(aRequired);
}
protected abstract AbstractExtXptContentOutlinePage createOutlinePage();
@Override
protected void createActions() {
super.createActions();
final ResourceBundle rb = new ResourceBundle() {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Enumeration getKeys() {
return new Vector().elements();
}
@Override
protected Object handleGetObject(final String key) {
return null;
}
};
// content assist
IAction a = new TextOperationAction(rb, "ContentAssistProposal.", this, ISourceViewer.CONTENTASSIST_PROPOSALS);
a.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
setAction("ContentAssistProposal", a);
a = new TextOperationAction(rb, "ContentAssistTip.", this, ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION);
a.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_CONTEXT_INFORMATION);
setAction("ContentAssistTip", a);
// hyperlinking and F3 support
OpenAction openAction = new OpenAction(this);
openAction.setActionDefinitionId(IJavaEditorActionDefinitionIds.OPEN_EDITOR);
setAction(JdtActionConstants.OPEN, openAction);
// search
searchActionGroup = new SearchActionGroup(this);
// debug
bpActionGroup = new BreakpointActionGroup(this);
}
@Override
protected void configureSourceViewerDecorationSupport (SourceViewerDecorationSupport support) {
super.configureSourceViewerDecorationSupport(support);
char[] matchChars = {'(', ')', '[', ']', '{', '}'};
ICharacterPairMatcher matcher = new DefaultCharacterPairMatcher(matchChars ,
IDocumentExtension3.DEFAULT_PARTITIONING);
support.setCharacterPairMatcher(matcher);
support.setMatchingCharacterPainterPreferenceKeys(XTEND_MATCHING_BRACKETS,XTEND_MATCHING_BRACKETS_COLOR);
//Enable bracket highlighting in the preference store
IPreferenceStore store = getPreferenceStore();
store.setDefault(XTEND_MATCHING_BRACKETS, true);
store.setDefault(XTEND_MATCHING_BRACKETS_COLOR, "192,192,192");
}
@Override
protected void rulerContextMenuAboutToShow(final IMenuManager menu) {
menu.add(new Separator("Xpand")); //$NON-NLS-1$
super.rulerContextMenuAboutToShow(menu);
bpActionGroup.fillContextMenu(menu);
}
public ISourceViewer internalGetSourceViewer() {
return getSourceViewer();
}
protected void updateStatusLine() {
final ITextSelection selection = (ITextSelection) getSelectionProvider().getSelection();
final Annotation annotation = getAnnotation(selection.getOffset(), selection.getLength());
String message = null;
if (annotation != null) {
updateMarkerViews(annotation);
if (isProblemMarkerAnnotation(annotation)) {
message = annotation.getText();
}
}
setStatusLineMessage(message);
}
private Annotation getAnnotation(final int offset, final int length) {
final IAnnotationModel model = getDocumentProvider().getAnnotationModel(getEditorInput());
if (model == null)
return null;
Iterator<?> iterator;
if (model instanceof IAnnotationModelExtension2) {
iterator = ((IAnnotationModelExtension2) model).getAnnotationIterator(offset, length, true, true);
}
else {
iterator = model.getAnnotationIterator();
}
while (iterator.hasNext()) {
final Annotation a = (Annotation) iterator.next();
final Position p = model.getPosition(a);
if (p != null && p.overlapsWith(offset, length))
return a;
}
return null;
}
private boolean isProblemMarkerAnnotation(final Annotation annotation) {
if (!(annotation instanceof MarkerAnnotation))
return false;
try {
return (((MarkerAnnotation) annotation).getMarker().isSubtypeOf(IMarker.PROBLEM));
}
catch (final CoreException e) {
return false;
}
}
}