/*
* ====================================================================
*
* The ObjectStyle Group Software License, Version 1.0
*
* Copyright (c) 2005 - 2006 The ObjectStyle Group and individual authors of the
* software. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: 1.
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. The end-user documentation
* included with the redistribution, if any, must include the following
* acknowlegement: "This product includes software developed by the ObjectStyle
* Group (http://objectstyle.org/)." Alternately, this acknowlegement may
* appear in the software itself, if and wherever such third-party
* acknowlegements normally appear. 4. The names "ObjectStyle Group" and
* "Cayenne" must not be used to endorse or promote products derived from this
* software without prior written permission. For written permission, please
* contact andrus@objectstyle.org. 5. Products derived from this software may
* not be called "ObjectStyle" nor may "ObjectStyle" appear in their names
* without prior written permission of the ObjectStyle Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* OBJECTSTYLE GROUP OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the ObjectStyle Group. For more information on the ObjectStyle
* Group, please see <http://objectstyle.org/> .
*
*/
package org.objectstyle.wolips.wodclipse.editor;
import java.util.ResourceBundle;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.eclipse.ui.texteditor.ContentAssistAction;
import org.eclipse.ui.texteditor.IAbstractTextEditorHelpContextIds;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.objectstyle.wolips.baseforplugins.util.Throttle;
import org.objectstyle.wolips.bindings.wod.IWodElement;
import org.objectstyle.wolips.bindings.wod.IWodModel;
import org.objectstyle.wolips.components.editor.ComponentEditorInteraction;
import org.objectstyle.wolips.components.editor.IEmbeddedEditor;
import org.objectstyle.wolips.components.editor.IWebobjectTagListener;
import org.objectstyle.wolips.components.editor.IWodDocumentProvider;
import org.objectstyle.wolips.locate.LocateException;
import org.objectstyle.wolips.locate.LocatePlugin;
import org.objectstyle.wolips.locate.result.LocalizedComponentsLocateResult;
import org.objectstyle.wolips.wodclipse.WodclipsePlugin;
import org.objectstyle.wolips.wodclipse.core.Activator;
import org.objectstyle.wolips.wodclipse.core.completion.WodParserCache;
import org.objectstyle.wolips.wodclipse.core.document.DocumentWodElement;
import org.objectstyle.wolips.wodclipse.core.document.ITextWOEditor;
import org.objectstyle.wolips.wodclipse.core.util.CursorPositionSupport;
import org.objectstyle.wolips.wodclipse.core.util.ICursorPositionListener;
import org.objectstyle.wolips.wodclipse.core.util.WodModelUtils;
/**
* @author mike
* @author uli
*/
public class WodEditor extends TextEditor implements IEmbeddedEditor, IWebobjectTagListener, IWodDocumentProvider, ITextWOEditor {
private WodParserCache _cache;
private CursorPositionSupport _cursorPositionSupport;
private WodContentOutlinePage _contentOutlinePage;
private IEditorInput _input;
private LocalizedComponentsLocateResult _componentsLocateResults;
private ComponentEditorInteraction _editorInteraction;
private Throttle _wodOutlineUpdateThrottle;
public WodEditor() {
_wodOutlineUpdateThrottle = new Throttle("WodOutline", 1000, new WodOutlineUpdater());
_cursorPositionSupport = new CursorPositionSupport(this);
setSourceViewerConfiguration(new WodSourceViewerConfiguration(this));
}
@Override
public void doSave(IProgressMonitor progressMonitor) {
if (_editorInteraction == null || _editorInteraction.embeddedEditorWillSave(progressMonitor)) {
super.doSave(progressMonitor);
updateValidation();
_editorInteraction.fireWebObjectChanged();
}
}
@Override
public void doSaveAs() {
super.doSaveAs();
}
@Override
protected void doSetInput(IEditorInput input) throws CoreException {
super.doSetInput(input);
_cache = null;
updateValidation();
}
@Override
public void createPartControl(Composite parent) {
super.createPartControl(parent);
getSourceViewer().getTextWidget().getParent().setBackground(parent.getBackground());
}
@Override
protected void performRevert() {
super.performRevert();
updateValidation();
_editorInteraction.fireWebObjectChanged();
}
@Override
protected void performSaveAs(IProgressMonitor progressMonitor) {
super.performSaveAs(progressMonitor);
updateValidation();
_editorInteraction.fireWebObjectChanged();
}
@Override
protected void performSave(boolean overwrite, IProgressMonitor progressMonitor) {
super.performSave(overwrite, progressMonitor);
}
public WodParserCache getParserCache() throws CoreException, LocateException {
if (_cache == null) {
IFileEditorInput input = (IFileEditorInput) getEditorInput();
IFile inputFile = input.getFile();
_cache = WodParserCache.parser(inputFile);
}
return _cache;
}
protected void updateValidation() {
try {
getParserCache().scheduleValidate(true, true);
}
catch (Throwable e) {
Activator.getDefault().log(e);
}
}
public synchronized void addCursorPositionListener(ICursorPositionListener listener) {
_cursorPositionSupport.addCursorPositionListener(listener);
}
public synchronized void removeCursorPositionListener(ICursorPositionListener listener) {
_cursorPositionSupport.removeCursorPositionListener(listener);
}
@Override
protected void handleCursorPositionChanged() {
super.handleCursorPositionChanged();
_cursorPositionSupport.cursorPositionChanged(getViewer().getSelectedRange());
}
public ISourceViewer getViewer() {
return getSourceViewer();
}
protected void initializeKeyBindingScopes() {
setKeyBindingScopes(new String[] { "org.objectstyle.wolips.componenteditor.componentEditorScope" });
}
protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler verticalRuler, int styles) {
return super.createSourceViewer(parent, verticalRuler, styles);
}
protected void createActions() {
super.createActions();
String BUNDLE_FOR_CONSTRUCTED_KEYS = "org.eclipse.jdt.internal.ui.javaeditor.ConstructedJavaEditorMessages";//$NON-NLS-1$
ResourceBundle fgBundleForConstructedKeys = ResourceBundle.getBundle(BUNDLE_FOR_CONSTRUCTED_KEYS);
// WodclipsePlugin.getDefault().getResourceBundle()
ContentAssistAction action = new ContentAssistAction(fgBundleForConstructedKeys, "ContentAssistProposal.", this); //$NON-NLS-1$
action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
setAction("ContentAssistProposal", action);
markAsStateDependentAction("ContentAssistProposal", true);
PlatformUI.getWorkbench().getHelpSystem().setHelp(action, IAbstractTextEditorHelpContextIds.CONTENT_ASSIST_ACTION);
}
public void updateWebObjectsTagNames() {
// MS: Come back to this
// try {
// IDocument document =
// getDocumentProvider().getDocument(getEditorInput());
// Set elementNamesSet = WodScanner.getTextForRulesOfType(document,
// ElementNameRule.class);
// String[] elementNames = (String[]) elementNamesSet.toArray(new
// String[elementNamesSet.size()]);
// HtmleditorPlugin.getDefault().setWebObjectsTagNames(elementNames);
// } catch (BadLocationException t) {
// // null means no tags
// // the user has to enter the name manually
// HtmleditorPlugin.getDefault().setWebObjectsTagNames(null);
// }
}
public Object getAdapter(Class adapter) {
if (IContentOutlinePage.class.equals(adapter)) {
if (_contentOutlinePage == null) {
_contentOutlinePage = new WodContentOutlinePage(getDocumentProvider(), this);
_contentOutlinePage.setInput(_input);
}
return _contentOutlinePage;
}
return super.getAdapter(adapter);
}
protected Throttle getWodOutlineUpdateThrottle() {
return _wodOutlineUpdateThrottle;
}
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
super.init(site, input);
_wodOutlineUpdateThrottle.stop();
_input = input;
IDocument document = getDocumentProvider().getDocument(getEditorInput());
document.addDocumentListener(new IDocumentListener() {
public void documentAboutToBeChanged(DocumentEvent event) {
// Do nothing
}
public void documentChanged(DocumentEvent event) {
getWodOutlineUpdateThrottle().ping();
}
});
try {
getParserCache().getWodEntry().setDocument(document);
} catch (Exception e) {
e.printStackTrace();
}
_wodOutlineUpdateThrottle.start();
}
public void dispose() {
try {
getParserCache().getWodEntry().setDocument(null);
} catch (Exception e) {
e.printStackTrace();
}
_wodOutlineUpdateThrottle.stop();
super.dispose();
}
protected class WodOutlineUpdater implements Runnable {
public void run() {
IContentOutlinePage contentOutlinePage = (IContentOutlinePage) WodEditor.this.getAdapter(IContentOutlinePage.class);
if (contentOutlinePage instanceof WodContentOutlinePage) {
final WodContentOutlinePage wodContentOutlinePage = (WodContentOutlinePage) contentOutlinePage;
Display.getDefault().asyncExec(new Runnable() {
public void run() {
wodContentOutlinePage.update();
}
});
}
}
}
public LocalizedComponentsLocateResult getComponentsLocateResults() throws CoreException, LocateException {
if (_componentsLocateResults == null) {
_componentsLocateResults = LocatePlugin.getDefault().getLocalizedComponentsLocateResult(((IFileEditorInput) _input).getFile());
}
return _componentsLocateResults;
}
public void initEditorInteraction(ComponentEditorInteraction editorInteraction) {
_editorInteraction = editorInteraction;
_editorInteraction.addWebObjectTagListener(this);
_editorInteraction.setWodDocumentProvider(this);
}
public void webObjectChanged() {
// DO NOTHING
}
public void webObjectTagSelected(String name) {
try {
IWodElement wodElement = getWodModel(false).getElementNamed(name);
if (wodElement instanceof DocumentWodElement) {
DocumentWodElement docWodElement = (DocumentWodElement)wodElement;
Position namePosition = docWodElement.getElementNamePosition();
getSourceViewer().setSelectedRange(namePosition.getOffset(), namePosition.getLength());
getSourceViewer().revealRange(namePosition.getOffset(), namePosition.getLength());
//setHighlightRange(namePosition.getOffset(), namePosition.getLength(), true);
}
} catch (BadLocationException e) {
WodclipsePlugin.getDefault().log(e);
} catch (Exception e) {
WodclipsePlugin.getDefault().log(e);
}
}
public IDocument getWodEditDocument() {
IDocument document = getDocumentProvider().getDocument(getEditorInput());
return document;
}
public ComponentEditorInteraction getEditorInteraction() {
return _editorInteraction;
}
public ISourceViewer getWOSourceViewer() {
return getViewer();
}
public StyledText getWOEditorControl() {
return getViewer().getTextWidget();
}
public int getOffsetAtPoint(Point point) {
StyledText st = getViewer().getTextWidget();
int modelOffset;
if (!st.getBounds().contains(point)) {
modelOffset = -1;
} else {
try {
int offset = st.getOffsetAtLocation(point);
modelOffset = AbstractTextEditor.widgetOffset2ModelOffset(getSourceViewer(), offset);
} catch (IllegalArgumentException e) {
modelOffset = -1;
}
}
return modelOffset;
}
public IWodModel getWodModel(boolean refreshModel) throws Exception {
WodParserCache cache = getParserCache();
IWodModel model;
if (refreshModel || isDirty()) {
model = WodModelUtils.createWodModel(cache.getWodEntry().getFile(), cache.getWodEntry().getDocument());
cache.getWodEntry().setModel(model);
} else {
model = cache.getWodEntry().getModel();
}
return model;
}
public IWodElement getWodElementAtPoint(Point point, boolean resolveWodElement, boolean refreshModel) throws Exception {
int offset = getOffsetAtPoint(point);
IWodElement element = getWodModel(refreshModel).getWodElementAtIndex(offset);
return element;
}
public IWodElement getSelectedElement(boolean resolveWodElement, boolean refreshModel) throws Exception {
IWodElement element = null;
ISelectionProvider selectionProvider = getSelectionProvider();
if (selectionProvider != null) {
ISelection selection = selectionProvider.getSelection();
if (selection instanceof ITextSelection) {
int offset = ((ITextSelection) selection).getOffset();
element = getWodModel(refreshModel).getWodElementAtIndex(offset);
}
}
return element;
}
}