package org.insightech.er.editor;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.commands.operations.IOperationApprover;
import org.eclipse.core.commands.operations.IOperationHistory;
import org.eclipse.core.commands.operations.OperationHistoryFactory;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.text.source.SourceViewerConfiguration;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.text.undo.DocumentUndoManagerRegistry;
import org.eclipse.text.undo.IDocumentUndoManager;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorRegistry;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.texteditor.DocumentProviderRegistry;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.IDocumentProviderExtension;
import org.eclipse.ui.texteditor.IDocumentProviderExtension2;
import org.eclipse.ui.texteditor.IDocumentProviderExtension3;
import org.eclipse.ui.texteditor.IElementStateListener;
import org.eclipse.ui.texteditor.IElementStateListenerExtension;
import org.insightech.er.Activator;
import org.osgi.framework.Bundle;
public class TestEditor extends EditorPart {
class ElementStateListener implements IElementStateListener,
IElementStateListenerExtension {
class Validator implements VerifyListener {
public void verifyText(VerifyEvent e) {
IDocument document = getDocumentProvider().getDocument(
getEditorInput());
final boolean[] documentChanged = new boolean[1];
IDocumentListener listener = new IDocumentListener() {
public void documentAboutToBeChanged(DocumentEvent event) {
}
public void documentChanged(DocumentEvent event) {
documentChanged[0] = true;
}
};
try {
if (document != null)
document.addDocumentListener(listener);
if (!validateEditorInputState() || documentChanged[0])
e.doit = false;
} finally {
if (document != null)
document.removeDocumentListener(listener);
}
}
}
private Validator fValidator;
private Display fDisplay;
public void elementStateValidationChanged(final Object element,
final boolean isStateValidated) {
if (element != null && element.equals(getEditorInput())) {
Runnable r = new Runnable() {
public void run() {
enableSanityChecking(true);
if (isStateValidated) {
if (fValidator != null) {
ISourceViewer viewer = fSourceViewer;
if (viewer != null) {
StyledText textWidget = viewer
.getTextWidget();
if (textWidget != null
&& !textWidget.isDisposed())
textWidget
.removeVerifyListener(fValidator);
fValidator = null;
}
}
enableStateValidation(false);
} else if (!isStateValidated && fValidator == null) {
ISourceViewer viewer = fSourceViewer;
if (viewer != null) {
StyledText textWidget = viewer.getTextWidget();
if (textWidget != null
&& !textWidget.isDisposed()) {
fValidator = new Validator();
enableStateValidation(true);
textWidget.addVerifyListener(fValidator);
}
}
}
}
};
execute(r, false);
}
}
/*
* @see IElementStateListener#elementDirtyStateChanged(Object, boolean)
*/
public void elementDirtyStateChanged(Object element, boolean isDirty) {
if (element != null && element.equals(getEditorInput())) {
Runnable r = new Runnable() {
public void run() {
enableSanityChecking(true);
firePropertyChange(PROP_DIRTY);
}
};
execute(r, false);
}
}
/*
* @see IElementStateListener#elementContentAboutToBeReplaced(Object)
*/
public void elementContentAboutToBeReplaced(Object element) {
if (element != null && element.equals(getEditorInput())) {
Runnable r = new Runnable() {
public void run() {
enableSanityChecking(true);
}
};
execute(r, false);
}
}
/*
* @see IElementStateListener#elementContentReplaced(Object)
*/
public void elementContentReplaced(Object element) {
if (element != null && element.equals(getEditorInput())) {
Runnable r = new Runnable() {
public void run() {
enableSanityChecking(true);
firePropertyChange(PROP_DIRTY);
}
};
execute(r, false);
}
}
/*
* @see IElementStateListener#elementDeleted(Object)
*/
public void elementDeleted(Object deletedElement) {
if (deletedElement != null
&& deletedElement.equals(getEditorInput())) {
Runnable r = new Runnable() {
public void run() {
enableSanityChecking(true);
close(false);
}
};
execute(r, false);
}
}
/*
* @see IElementStateListener#elementMoved(Object, Object)
*/
public void elementMoved(final Object originalElement,
final Object movedElement) {
if (originalElement != null
&& originalElement.equals(getEditorInput())) {
final boolean doValidationAsync = Display.getCurrent() != null;
Runnable r = new Runnable() {
public void run() {
enableSanityChecking(true);
if (fSourceViewer == null)
return;
if (movedElement == null
|| movedElement instanceof IEditorInput) {
final IDocumentProvider d = getDocumentProvider();
final String previousContent;
IDocumentUndoManager previousUndoManager = null;
IDocument changed = null;
boolean wasDirty = isDirty();
changed = d.getDocument(getEditorInput());
if (changed != null) {
if (wasDirty)
previousContent = changed.get();
else
previousContent = null;
previousUndoManager = DocumentUndoManagerRegistry
.getDocumentUndoManager(changed);
if (previousUndoManager != null)
previousUndoManager.connect(this);
} else
previousContent = null;
setInput((IEditorInput) movedElement);
// The undo manager needs to be replaced with one
// for the new document.
// Transfer the undo history and then disconnect
// from the old undo manager.
if (previousUndoManager != null) {
IDocument newDocument = getDocumentProvider()
.getDocument(movedElement);
if (newDocument != null) {
IDocumentUndoManager newUndoManager = DocumentUndoManagerRegistry
.getDocumentUndoManager(newDocument);
if (newUndoManager != null)
newUndoManager
.transferUndoHistory(previousUndoManager);
}
previousUndoManager.disconnect(this);
}
if (wasDirty && changed != null) {
Runnable r2 = new Runnable() {
public void run() {
validateState(getEditorInput());
d.getDocument(getEditorInput()).set(
previousContent);
}
};
execute(r2, doValidationAsync);
}
}
}
};
execute(r, false);
}
}
/*
* @see IElementStateListenerExtension#elementStateChanging(Object)
* @since 2.0
*/
public void elementStateChanging(Object element) {
if (element != null && element.equals(getEditorInput()))
enableSanityChecking(false);
}
/*
* @see IElementStateListenerExtension#elementStateChangeFailed(Object)
* @since 2.0
*/
public void elementStateChangeFailed(Object element) {
if (element != null && element.equals(getEditorInput()))
enableSanityChecking(true);
}
private void execute(Runnable runnable, boolean postAsync) {
if (postAsync || Display.getCurrent() == null) {
if (fDisplay == null)
fDisplay = getSite().getShell().getDisplay();
fDisplay.asyncExec(runnable);
} else
runnable.run();
}
}
private IDocumentProvider fImplicitDocumentProvider;
private SourceViewerConfiguration fConfiguration;
private ISourceViewer fSourceViewer;
private Image fTitleImage;
private IElementStateListener fElementStateListener = new ElementStateListener();
private long fModificationStamp = -1;
private boolean fIsSanityCheckEnabled = true;
private boolean fIsStateValidationEnabled = true;
private IOperationApprover fNonLocalOperationApprover;
private IOperationApprover fLinearUndoViolationApprover;
public IDocumentProvider getDocumentProvider() {
return fImplicitDocumentProvider;
}
protected final SourceViewerConfiguration getSourceViewerConfiguration() {
return fConfiguration;
}
protected final ISourceViewer getSourceViewer() {
return fSourceViewer;
}
protected void setSourceViewerConfiguration(
SourceViewerConfiguration configuration) {
Assert.isNotNull(configuration);
fConfiguration = configuration;
}
public boolean isEditable() {
IDocumentProvider provider = getDocumentProvider();
if (provider instanceof IDocumentProviderExtension) {
IDocumentProviderExtension extension = (IDocumentProviderExtension) provider;
return extension.isModifiable(getEditorInput());
}
return false;
}
protected final void internalInit(IWorkbenchWindow window,
final IEditorSite site, final IEditorInput input)
throws PartInitException {
IRunnableWithProgress runnable = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
try {
if (getDocumentProvider() instanceof IDocumentProviderExtension2) {
IDocumentProviderExtension2 extension = (IDocumentProviderExtension2) getDocumentProvider();
extension.setProgressMonitor(monitor);
}
doSetInput(input);
} catch (CoreException x) {
throw new InvocationTargetException(x);
} finally {
if (getDocumentProvider() instanceof IDocumentProviderExtension2) {
IDocumentProviderExtension2 extension = (IDocumentProviderExtension2) getDocumentProvider();
extension.setProgressMonitor(null);
}
}
}
};
try {
getSite().getWorkbenchWindow().run(false, true, runnable);
} catch (InterruptedException x) {
} catch (InvocationTargetException e) {
Activator.log(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public void init(final IEditorSite site, final IEditorInput input)
throws PartInitException {
setSite(site);
internalInit(site.getWorkbenchWindow(), site, input);
}
protected ISourceViewer createSourceViewer(Composite parent,
IVerticalRuler ruler, int styles) {
return new SourceViewer(parent, ruler, styles);
}
/**
* {@inheritDoc}
*/
@Override
public void createPartControl(Composite parent) {
int styles = SWT.V_SCROLL;
fSourceViewer = createSourceViewer(parent, null, styles);
if (fConfiguration == null)
fConfiguration = new SourceViewerConfiguration();
fSourceViewer.configure(fConfiguration);
initializeSourceViewer(getEditorInput());
}
private void initializeSourceViewer(IEditorInput input) {
IDocumentProvider documentProvider = getDocumentProvider();
IAnnotationModel model = documentProvider.getAnnotationModel(input);
IDocument document = documentProvider.getDocument(input);
if (document != null) {
fSourceViewer.setDocument(document, model);
fSourceViewer.setEditable(isEditable());
fSourceViewer.showAnnotations(model != null);
}
if (fElementStateListener instanceof IElementStateListenerExtension) {
boolean isStateValidated = false;
if (documentProvider instanceof IDocumentProviderExtension)
isStateValidated = ((IDocumentProviderExtension) documentProvider)
.isStateValidated(input);
IElementStateListenerExtension extension = (IElementStateListenerExtension) fElementStateListener;
extension.elementStateValidationChanged(input, isStateValidated);
}
}
private void initializeTitle(IEditorInput input) {
Image oldImage = fTitleImage;
fTitleImage = null;
String title = ""; //$NON-NLS-1$
if (input != null) {
IEditorRegistry editorRegistry = PlatformUI.getWorkbench()
.getEditorRegistry();
IEditorDescriptor editorDesc = editorRegistry.findEditor(getSite()
.getId());
ImageDescriptor imageDesc = editorDesc != null ? editorDesc
.getImageDescriptor() : null;
fTitleImage = imageDesc != null ? imageDesc.createImage() : null;
title = input.getName();
}
setTitleImage(fTitleImage);
setPartName(title);
firePropertyChange(PROP_DIRTY);
if (oldImage != null && !oldImage.isDisposed())
oldImage.dispose();
}
protected void setDocumentProvider(IEditorInput input) {
fImplicitDocumentProvider = DocumentProviderRegistry.getDefault()
.getDocumentProvider(input);
}
private void updateDocumentProvider(IEditorInput input) {
IProgressMonitor rememberedProgressMonitor = null;
IDocumentProvider provider = getDocumentProvider();
if (provider != null) {
provider.removeElementStateListener(fElementStateListener);
if (provider instanceof IDocumentProviderExtension2) {
IDocumentProviderExtension2 extension = (IDocumentProviderExtension2) provider;
rememberedProgressMonitor = extension.getProgressMonitor();
extension.setProgressMonitor(null);
}
}
setDocumentProvider(input);
provider = getDocumentProvider();
if (provider != null) {
provider.addElementStateListener(fElementStateListener);
if (provider instanceof IDocumentProviderExtension2) {
IDocumentProviderExtension2 extension = (IDocumentProviderExtension2) provider;
extension.setProgressMonitor(rememberedProgressMonitor);
}
}
}
protected void doSetInput(IEditorInput input) throws CoreException {
if (input == null) {
close(isSaveOnCloseNeeded());
} else {
IEditorInput oldInput = getEditorInput();
if (oldInput != null)
getDocumentProvider().disconnect(oldInput);
super.setInput(input);
updateDocumentProvider(input);
IDocumentProvider provider = getDocumentProvider();
provider.connect(input);
initializeTitle(input);
if (fSourceViewer != null) {
initializeSourceViewer(input);
}
}
}
/**
* {@inheritDoc}
*/
@Override
protected final void setInputWithNotify(IEditorInput input) {
try {
doSetInput(input);
firePropertyChange(IEditorPart.PROP_INPUT);
} catch (CoreException e) {
Activator.log(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public final void setInput(IEditorInput input) {
setInputWithNotify(input);
}
/*
* @see ITextEditor#close
*/
public void close(final boolean save) {
enableSanityChecking(false);
Display display = getSite().getShell().getDisplay();
display.asyncExec(new Runnable() {
public void run() {
if (fSourceViewer != null)
getSite().getPage().closeEditor(TestEditor.this, save);
}
});
}
/**
* The <code>AbstractTextEditor</code> implementation of this
* <code>IWorkbenchPart</code> method may be extended by subclasses.
* Subclasses must call <code>super.dispose()</code>.
* <p>
* Note that many methods may return <code>null</code> after the editor is
* disposed.
* </p>
*/
@Override
public void dispose() {
if (fTitleImage != null) {
fTitleImage.dispose();
fTitleImage = null;
}
disposeDocumentProvider();
if (fSourceViewer != null) {
fSourceViewer = null;
}
if (fConfiguration != null)
fConfiguration = null;
IOperationHistory history = OperationHistoryFactory
.getOperationHistory();
if (history != null) {
if (fNonLocalOperationApprover != null)
history.removeOperationApprover(fNonLocalOperationApprover);
if (fLinearUndoViolationApprover != null)
history.removeOperationApprover(fLinearUndoViolationApprover);
}
fNonLocalOperationApprover = null;
fLinearUndoViolationApprover = null;
super.dispose();
}
/**
* Disposes of the connection with the document provider. Subclasses may
* extend.
*
* @since 3.0
*/
protected void disposeDocumentProvider() {
IDocumentProvider provider = getDocumentProvider();
if (provider != null) {
IEditorInput input = getEditorInput();
if (input != null)
provider.disconnect(input);
if (fElementStateListener != null) {
provider.removeElementStateListener(fElementStateListener);
fElementStateListener = null;
}
}
fImplicitDocumentProvider = null;
}
/**
* {@inheritDoc}
*/
@Override
public void doSaveAs() {
}
/**
* {@inheritDoc}
*/
@Override
public void doSave(IProgressMonitor progressMonitor) {
}
/**
* Enables/disables sanity checking.
*
* @param enable
* <code>true</code> if sanity checking should be enabled,
* <code>false</code> otherwise
* @since 2.0
*/
protected void enableSanityChecking(boolean enable) {
synchronized (this) {
fIsSanityCheckEnabled = enable;
}
}
/**
* Checks the state of the given editor input if sanity checking is enabled.
*
* @param input
* the editor input whose state is to be checked
* @since 2.0
*/
protected void safelySanityCheckState(IEditorInput input) {
boolean enabled = false;
synchronized (this) {
enabled = fIsSanityCheckEnabled;
}
if (enabled)
sanityCheckState(input);
}
/**
* Checks the state of the given editor input.
*
* @param input
* the editor input whose state is to be checked
* @since 2.0
*/
protected void sanityCheckState(IEditorInput input) {
IDocumentProvider p = getDocumentProvider();
if (p == null)
return;
if (p instanceof IDocumentProviderExtension3) {
long stamp = p.getModificationStamp(input);
if (stamp != fModificationStamp) {
fModificationStamp = stamp;
}
} else {
if (fModificationStamp == -1)
fModificationStamp = p.getSynchronizationStamp(input);
long stamp = p.getModificationStamp(input);
if (stamp != fModificationStamp) {
fModificationStamp = stamp;
}
}
updateState(getEditorInput());
}
/**
* Enables/disables state validation.
*
* @param enable
* <code>true</code> if state validation should be enabled,
* <code>false</code> otherwise
* @since 2.1
*/
protected void enableStateValidation(boolean enable) {
synchronized (this) {
fIsStateValidationEnabled = enable;
}
}
protected void validateState(IEditorInput input) {
IDocumentProvider provider = getDocumentProvider();
if (!(provider instanceof IDocumentProviderExtension))
return;
IDocumentProviderExtension extension = (IDocumentProviderExtension) provider;
try {
extension.validateState(input, getSite().getShell());
} catch (CoreException x) {
IStatus status = x.getStatus();
if (status == null || status.getSeverity() != IStatus.CANCEL) {
Bundle bundle = Platform.getBundle(PlatformUI.PLUGIN_ID);
ILog log = Platform.getLog(bundle);
log.log(x.getStatus());
Shell shell = getSite().getShell();
String title = "EditorMessages.Editor_error_validateEdit_title";
String msg = "EditorMessages.Editor_error_validateEdit_message";
ErrorDialog.openError(shell, title, msg, x.getStatus());
}
return;
}
if (fSourceViewer != null)
fSourceViewer.setEditable(isEditable());
}
/*
* @see org.eclipse.ui.texteditor.ITextEditorExtension2#validateEditorInputState()
* @since 2.1
*/
public boolean validateEditorInputState() {
boolean enabled = false;
synchronized (this) {
enabled = fIsStateValidationEnabled;
}
if (enabled) {
ISourceViewer viewer = fSourceViewer;
if (viewer == null)
return false;
final IEditorInput input = getEditorInput();
BusyIndicator.showWhile(getSite().getShell().getDisplay(),
new Runnable() {
/*
* @see java.lang.Runnable#run()
*/
public void run() {
validateState(input);
}
});
sanityCheckState(input);
return true;
}
return true;
}
protected void updateState(IEditorInput input) {
IDocumentProvider provider = getDocumentProvider();
if (provider instanceof IDocumentProviderExtension) {
IDocumentProviderExtension extension = (IDocumentProviderExtension) provider;
try {
extension.updateStateCache(input);
if (fSourceViewer != null)
fSourceViewer.setEditable(isEditable());
} catch (CoreException e) {
Activator.log(e);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean isSaveAsAllowed() {
return false;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isDirty() {
IDocumentProvider p = getDocumentProvider();
return p == null ? false : p.canSaveDocument(getEditorInput());
}
/**
* {@inheritDoc}
*/
@Override
public Object getAdapter(Class required) {
return super.getAdapter(required);
}
/**
* {@inheritDoc}
*/
@Override
public void setFocus() {
}
/**
* {@inheritDoc}
*/
@Override
protected void firePropertyChange(int property) {
super.firePropertyChange(property);
}
}