/******************************************************************************* * Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is 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: * Exadel, Inc. and Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.common.model.ui.texteditors; import java.lang.reflect.InvocationTargetException; import java.util.Properties; import java.util.ResourceBundle; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IMarkerDelta; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.TextEvent; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.ui.texteditor.IAbstractTextEditorHelpContextIds; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.IDocumentProviderExtension; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.ui.texteditor.ITextEditorActionConstants; import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; import org.eclipse.ui.texteditor.ResourceAction; import org.eclipse.ui.texteditor.RevertToSavedAction; import org.eclipse.ui.texteditor.SaveAction; import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; import org.jboss.tools.common.editor.ObjectTextEditor; import org.jboss.tools.common.model.XModelException; import org.jboss.tools.common.model.XModelObject; import org.jboss.tools.common.model.filesystems.impl.DiscardFileHandler; import org.jboss.tools.common.model.filesystems.impl.FolderImpl; import org.jboss.tools.common.model.filesystems.impl.FolderLoader; import org.jboss.tools.common.model.plugin.ModelPlugin; import org.jboss.tools.common.model.ui.ModelUIPlugin; import org.jboss.tools.common.model.ui.editor.IModelObjectEditorInput; import org.jboss.tools.common.model.ui.messages.UIMessages; import org.jboss.tools.common.model.ui.texteditors.xmleditor.XMLTextEditor; import org.jboss.tools.common.model.util.PositionSearcher; public class XMLTextEditorComponent extends XMLTextEditor implements ObjectTextEditor, ITextProvider { protected TextEditorSupport support = createSupport(); protected boolean isObjectNull = false; private ICL changeListener = null; protected boolean isStandAlone = false; public XMLTextEditorComponent() { this(true); } public XMLTextEditorComponent(boolean useUseRHDSConfig) { super(useUseRHDSConfig); support.setProvider(this); /// XmlDocumentProvider p = (XmlDocumentProvider)getDocumentProvider(); /// p.disableElementContentChange(); ModelPlugin.getWorkspace().addResourceChangeListener(changeListener = new ICL()); } protected TextEditorSupport createSupport() { return new TextEditorSupport(); } public TextEditorSupport getSupport() { return support; } boolean isNullEditor = false; public void createPartControl(Composite parent) { if(getModel() == null) { setObject(null); isNullEditor = true; Label label = new Label(parent, SWT.NONE); label.setText(UIMessages.CANNOT_DISPLAY_DOCUMENT_CONTENTS); label.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); return; } else { super.createPartControl(parent); } } public void setObject(XModelObject object) { if(isNullEditor) return; isObjectNull = (object == null); if(isObjectNull) return; getDocumentListenerRegister().unregister(); try { support.setObject(object); } finally { getDocumentListenerRegister().register(); } } public void updateDocument() { support.update(); } public boolean isDirty() { return (isObjectNull || isStandAlone) ? super.isDirty() : false; } public String getText() { String text = null; ISourceViewer sv = getSourceViewer(); if(sv == null) return ""; //$NON-NLS-1$ IDocument d = sv.getDocument(); if(d == null) return ""; //$NON-NLS-1$ text = d.get(); return (text == null) ? "" : text; //$NON-NLS-1$ } public boolean isEditable() { return !isEditorInputReadOnly(); } public boolean isEditorInputReadOnly() { if(!(getEditorInput() instanceof IModelObjectEditorInput)) return super.isEditorInputReadOnly(); IModelObjectEditorInput input = (IModelObjectEditorInput)getEditorInput(); if(input == null || input.getXModelObject() == null) return true; XModelObject o = input.getXModelObject(); return !o.isObjectEditable() && !o.isAttributeEditable("body"); //$NON-NLS-1$ } public void setModified(boolean set) { if(set == support.isModified()) return; support.setModified(set); firePropertyChange(IEditorPart.PROP_DIRTY); } public boolean isModified() { return support.isModified(); } public void save() { if(isStandAlone) { super.save(); } else { if(!isObjectNull && !support.canSave(false)) return; if(isObjectNull) super.doSave(null); else support.save(); } } protected void doSaveYourself() { XModelObject o = getModelObject(); XModelObject f = o == null ? null : o.getParent(); if(f instanceof FolderImpl) { try { ((FolderImpl)f).saveChild(o); } catch (XModelException e) { ModelPlugin.getPluginLog().logError(e); } } else { // } } public void addFocusListener(FocusListener listener) { ISourceViewer sv = getSourceViewer(); if (sv != null) sv.getTextWidget().addFocusListener(listener); } public void removeFocusListener(FocusListener listener) { ISourceViewer sv = getSourceViewer(); if (sv != null) getSourceViewer().getTextWidget().removeFocusListener(listener); } public void setCursor(int line, int position) { ISourceViewer sv = getSourceViewer(); if(sv == null || sv.getDocument() == null) return; try { int i = sv.getDocument().getLineOffset(line - 1) + position -1; sv.setSelectedRange(i, 0); sv.revealRange(i, 0); } catch (BadLocationException e) { ModelUIPlugin.getPluginLog().logError(e); } catch (SWTException e) { ModelUIPlugin.getPluginLog().logError(e); } catch (IllegalArgumentException e) { ModelUIPlugin.getPluginLog().logError(e); } } public void doSaveAs() { if(isStandAlone) { super.doSaveAs(); } } public void performSaveAs(IProgressMonitor monitor){ XModelObject old = getModelObject(); super.performSaveAs(monitor); XModelObject o = getModelObject(); if(o != null) { if(o.getParent() instanceof FolderLoader) { ((FolderLoader)o.getParent()).update(); if(!o.isActive()) { o = getModelObject(); } } if(o != null) support.setObject(o); } if(old.isModified()) try { new DiscardFileHandler().executeHandler(old, new Properties()); } catch (XModelException e) { //ignore // ModelUIPlugin.log(e); } } public void doSave(IProgressMonitor monitor){ if(isObjectNull || isStandAlone) super.doSave(monitor); } private int textChangedLock = 0; public void textChanged(TextEvent event) { if(textChangedLock > 0) { firePropertyChange(IEditorPart.PROP_DIRTY); } else { support.lock++; try { setModified(true); } finally { support.lock--; } } } public void setText(String text) { textChangedLock++; try { if(getSourceViewer() == null || getSourceViewer().getDocument() == null) return; String txt = getSourceViewer().getDocument().get(); if(txt != null && txt.length() > 0) { if(!TextMerge.replace(getSourceViewer().getDocument(), text)) { getSourceViewer().getDocument().set(text); } } else { getSourceViewer().getDocument().set(text); } } finally { textChangedLock--; } } public boolean isEqualText(String text) { return (getSourceViewer().getDocument() != null && text.equals(getText())); } public void doSanityCheckState(IEditorInput input) { super.safelySanityCheckState(input); if(isObjectNull) return; Display.getDefault().syncExec( new Runnable() { public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { //ignore } support.save(true); } } ); } /** * Handles an external change of the editor's input element. */ protected void handleEditorInputChanged() { final IDocumentProvider provider= getDocumentProvider(); if (provider == null) { // fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=15066 close(false); return; } final IEditorInput input= getEditorInput(); if (provider instanceof IDocumentProviderExtension) { WorkspaceModifyOperation operation= new WorkspaceModifyOperation() { protected void execute(final IProgressMonitor monitor) throws CoreException { IDocumentProviderExtension extension= (IDocumentProviderExtension) provider; textChangedLock++; try { extension.synchronize(input); } finally { textChangedLock--; } } }; try { operation.run(getProgressMonitor()); } catch (InterruptedException x) { //ignore } catch (InvocationTargetException x) { //ignore } } else { try { doSetInput(input); } catch (CoreException x) { //ignore } } } public void doRevertToSaved() { support.save(); support.revertToSaved(); } protected void createActions() { super.createActions(); ResourceAction action = new RevertToSavedAction2(this); action.setHelpContextId(IAbstractTextEditorHelpContextIds.REVERT_TO_SAVED_ACTION); action.setActionDefinitionId(ITextEditorActionDefinitionIds.REVERT_TO_SAVED); setAction(ITextEditorActionConstants.REVERT_TO_SAVED, action); action = new SaveAction2(this); action.setHelpContextId(IAbstractTextEditorHelpContextIds.SAVE_ACTION); action.setActionDefinitionId(ITextEditorActionDefinitionIds.SAVE); setAction(ITextEditorActionConstants.SAVE, action); markAsPropertyDependentAction(ITextEditorActionConstants.SAVE, true); } public void selectModelObject(XModelObject object) { selectModelObject(object, null); } public void dispose() { super.dispose(); if(changeListener != null) { ModelPlugin.getWorkspace().removeResourceChangeListener(changeListener); changeListener = null; } } public void selectModelObject(XModelObject object, String attribute) { PositionSearcher searcher = new PositionSearcher(); searcher.init(getText(), object, attribute); searcher.execute(); int bp = searcher.getStartPosition(); int ep = searcher.getEndPosition(); if(ep >= bp && bp >= 0) { selectAndReveal(bp, ep - bp); } } public void updateModification() { XModelObject object = support.getModelObject(); if(object != null && !object.isModified() && support.isModified()) { //external update setModified(false); } else { firePropertyChange(ITextEditor.PROP_DIRTY); } } class ICL implements IResourceChangeListener { public void resourceChanged(IResourceChangeEvent event) { if(event == null || event.getDelta() == null || isUpdating) return; if(!(getEditorInput() instanceof IFileEditorInput)) return; IFile f = ((IFileEditorInput)getEditorInput()).getFile(); if(f == null) return; IMarkerDelta[] md = event.findMarkerDeltas(null, true); boolean b = false; for (int i = 0; i < md.length && !b; i++) { b = f.equals(md[i].getResource()); } if(b) updateAnnotationModel(); } } boolean isUpdating = false; private void updateAnnotationModel() { } public void gotoMarker(IMarker marker) { super.gotoMarker(marker); } XMLModelObjectFinder modelObjectFinder = new XMLModelObjectFinder(); public XModelObject findModelObjectAtCursor() { XModelObject o = getModelObject(); if(o == null) return null; ISelection selection = getSelectionProvider().getSelection(); if(!(selection instanceof ITextSelection)) return null; int offset = ((ITextSelection)selection).getOffset(); if(offset < 0) return o; IndexedRegion region = getModel().getIndexedRegion(offset); return modelObjectFinder.findModelObject(region, o); } // Point storedSelection = new Point(0,0); // // protected void handleCursorPositionChanged() { // super.handleCursorPositionChanged(); // ISelection selection = getSelectionProvider().getSelection(); // Point p = getTextViewer().getTextWidget().getSelection(); // if (storedSelection == null || !storedSelection.equals(p)) { // storedSelection = p; // if(selection instanceof ITextSelection) { // ITextSelection ts = (ITextSelection)selection; // if(ts.getLength() == 0) { // getSelectionProvider().setSelection(getSelectionProvider().getSelection()); // } // } // } // } } class RevertToSavedAction2 extends RevertToSavedAction { XMLTextEditorComponent t; RevertToSavedAction2(XMLTextEditorComponent t) { super(ResourceBundle.getBundle("org.eclipse.ui.texteditor.ConstructedEditorMessages"), "Editor.Revert.", t); //$NON-NLS-1$ //$NON-NLS-2$ this.t = t; } public void update() { setEnabled(t != null && t.support != null && (t.support.canRevertToSaved() || t.isModified())); } } class SaveAction2 extends SaveAction { XMLTextEditorComponent t; SaveAction2(XMLTextEditorComponent t) { super(ResourceBundle.getBundle("org.eclipse.ui.texteditor.ConstructedEditorMessages"), "Editor.Save.", t); //$NON-NLS-1$ //$NON-NLS-2$ this.t = t; } public void update() { XModelObject o = (t == null) ? null : t.getModelObject(); setEnabled(o != null && o.isModified()); } public void run() { IEditorPart p = getTextEditor().getSite().getPage().findEditor(t.getEditorInput()); if(p != null) getTextEditor().getSite().getPage().saveEditor(p, false); } }