/* * ==================================================================== * * 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; } }