diff options
Diffstat (limited to 'bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/StructuredDocumentToTextAdapter.java')
-rw-r--r-- | bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/StructuredDocumentToTextAdapter.java | 1332 |
1 files changed, 0 insertions, 1332 deletions
diff --git a/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/StructuredDocumentToTextAdapter.java b/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/StructuredDocumentToTextAdapter.java deleted file mode 100644 index 4a276fd591..0000000000 --- a/bundles/org.eclipse.wst.sse.ui/src/org/eclipse/wst/sse/ui/internal/StructuredDocumentToTextAdapter.java +++ /dev/null @@ -1,1332 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001, 2005 IBM Corporation 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: - * IBM Corporation - initial API and implementation - * Jens Lukowski/Innoopract - initial renaming/restructuring - * - *******************************************************************************/ -package org.eclipse.wst.sse.ui.internal; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.jobs.ILock; -import org.eclipse.jface.text.AbstractDocument; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.ConfigurableLineTracker; -import org.eclipse.jface.text.DefaultLineTracker; -import org.eclipse.jface.text.DocumentEvent; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IDocumentAdapter; -import org.eclipse.jface.text.IDocumentAdapterExtension; -import org.eclipse.jface.text.IDocumentListener; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.IRepairableDocument; -import org.eclipse.jface.text.ITextStore; -import org.eclipse.jface.text.Region; -import org.eclipse.jface.text.TextUtilities; -import org.eclipse.jface.text.projection.ProjectionDocument; -import org.eclipse.swt.custom.StyledText; -import org.eclipse.swt.custom.TextChangeListener; -import org.eclipse.swt.custom.TextChangedEvent; -import org.eclipse.swt.custom.TextChangingEvent; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.PlatformUI; -import org.eclipse.wst.sse.core.internal.ILockable; -import org.eclipse.wst.sse.core.internal.provisional.events.IStructuredDocumentListener; -import org.eclipse.wst.sse.core.internal.provisional.events.NewDocumentEvent; -import org.eclipse.wst.sse.core.internal.provisional.events.NoChangeEvent; -import org.eclipse.wst.sse.core.internal.provisional.events.RegionChangedEvent; -import org.eclipse.wst.sse.core.internal.provisional.events.RegionsReplacedEvent; -import org.eclipse.wst.sse.core.internal.provisional.events.StructuredDocumentEvent; -import org.eclipse.wst.sse.core.internal.provisional.events.StructuredDocumentRegionsReplacedEvent; -import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; -import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; -import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegionList; -import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; -import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList; -import org.eclipse.wst.sse.core.internal.util.Debug; -import org.eclipse.wst.sse.core.internal.util.Utilities; -import org.eclipse.wst.sse.ui.internal.util.Assert; - - -/** - * Adapts IStructuredDocument events and methods to StyledTextContent events - * and methods - */ -public class StructuredDocumentToTextAdapter implements IDocumentAdapter, IDocumentAdapterExtension { - - private class DocumentClone extends AbstractDocument { - - - /** - * Creates a new document clone with the given content. - * - * @param content - * the content - * @param lineDelimiters - * the line delimiters - */ - public DocumentClone(String content, String[] lineDelimiters) { - super(); - setTextStore(new StringTextStore(content)); - ConfigurableLineTracker tracker = new ConfigurableLineTracker(lineDelimiters); - setLineTracker(tracker); - getTracker().set(content); - completeInitialization(); - } - } - - // A pre-notification listener for the viewer's Document - class DocumentListener implements IDocumentListener { - protected boolean allTextChanged = false; - - protected DocumentEvent currentEvent; - - synchronized public void documentAboutToBeChanged(DocumentEvent event) { - if (isStoppedForwardingChanges()) - return; - - pendingDocumentChangedEvent = true; - allTextChanged = event.getOffset() <= 0 && event.getLength() >= StructuredDocumentToTextAdapter.this.getDocument().getLength(); - currentEvent = event; - - StructuredDocumentToTextAdapter.this.relayTextChanging(event.getOffset(), event.getLength(), event.getText()); - } - - synchronized public void documentChanged(DocumentEvent event) { - if (isStoppedForwardingChanges()) - return; - - if (currentEvent != null && event == currentEvent) { - if (allTextChanged) { - StructuredDocumentToTextAdapter.this.relayTextSet(); - } - else { - // temp work around for immediate thread - // problem. - // should have more general solution - // soon. 'syncExec' are rumored to be - // prone to hang. - StructuredDocumentToTextAdapter.this.relayTextChanged(); - } - } - - currentEvent = null; - pendingDocumentChangedEvent = false; - handlePendingEvents(); - lastEvent = null; - - } - } - - private static class StringTextStore implements ITextStore { - - private String fContent; - - /** - * Creates a new string text store with the given content. - * - * @param content - * the content - */ - public StringTextStore(String content) { - Assert.isNotNull(content, "content can not be null when setting text store"); //$NON-NLS-1$ - fContent = content; - } - - /* - * @see org.eclipse.jface.text.ITextStore#get(int) - */ - public char get(int offset) { - return fContent.charAt(offset); - } - - /* - * @see org.eclipse.jface.text.ITextStore#get(int, int) - */ - public String get(int offset, int length) { - return fContent.substring(offset, offset + length); - } - - /* - * @see org.eclipse.jface.text.ITextStore#getLength() - */ - public int getLength() { - return fContent.length(); - } - - /* - * @see org.eclipse.jface.text.ITextStore#replace(int, int, - * java.lang.String) - */ - public void replace(int offset, int length, String text) { - } - - /* - * @see org.eclipse.jface.text.ITextStore#set(java.lang.String) - */ - public void set(String text) { - } - - } - - /** - * Changes to the Document/IStructuredDocument can extend beyond the text - * change area and require more redrawing to keep the hilighting correct. - * The event must be saved so that the redraw is only sent after a - * textChanged event is received. - */ - class StructuredDocumentListener implements IStructuredDocumentListener { - - public void newModel(NewDocumentEvent structuredDocumentEvent) { - - if (isStoppedForwardingChanges()) { - // if - // (StructuredDocumentToTextAdapter.this.fStopRelayingChanges) - // { - if (Debug.debugStructuredDocument) { - System.out.println("skipped relaying StructuredDocumentEvent " + structuredDocumentEvent.getClass().getName()); //$NON-NLS-1$ - } - return; - } - // should use textSet when all contents have - // changed - // otherwise need to use the pair of - // textChanging and - // textChanged. - StructuredDocumentToTextAdapter.this.lastEvent = structuredDocumentEvent; - } - - public void noChange(final NoChangeEvent structuredDocumentEvent) { - - if (Debug.debugStructuredDocument) { - System.out.println("skipped relaying StructuredDocumentEvent " + structuredDocumentEvent.getClass().getName()); //$NON-NLS-1$ - } - if (structuredDocumentEvent.reason == NoChangeEvent.READ_ONLY_STATE_CHANGE) { - if (pendingDocumentChangedEvent) { - if (lastEventQueue == null) { - lastEventQueue = new ArrayList(); - } - lastEventQueue.add(structuredDocumentEvent); - } - else { - StructuredDocumentToTextAdapter.this.lastEvent = structuredDocumentEvent; - } - } - } - - public void nodesReplaced(StructuredDocumentRegionsReplacedEvent structuredDocumentEvent) { - - if (isStoppedForwardingChanges()) { - // if - // (StructuredDocumentToTextAdapter.this.fStopRelayingChanges) - // { - if (Debug.debugStructuredDocument) { - System.out.println("not relaying StructuredDocumentEvent " + structuredDocumentEvent.getClass().getName()); //$NON-NLS-1$ - } - return; - } - if (Debug.debugStructuredDocument) { - System.out.println("saving StructuredDocumentEvent " + structuredDocumentEvent.getClass().getName()); //$NON-NLS-1$ - } - StructuredDocumentToTextAdapter.this.lastEvent = structuredDocumentEvent; - } - - public void regionChanged(RegionChangedEvent structuredDocumentEvent) { - - if (isStoppedForwardingChanges()) { - // if - // (StructuredDocumentToTextAdapter.this.fStopRelayingChanges) - // { - if (Debug.debugStructuredDocument) { - System.out.println("not relaying StructuredDocumentEvent " + structuredDocumentEvent.getClass().getName()); //$NON-NLS-1$ - } - return; - } - if (Debug.debugStructuredDocument) { - System.out.println("saving StructuredDocumentEvent " + structuredDocumentEvent.getClass().getName()); //$NON-NLS-1$ - } - StructuredDocumentToTextAdapter.this.lastEvent = structuredDocumentEvent; - } - - public void regionsReplaced(RegionsReplacedEvent structuredDocumentEvent) { - - if (isStoppedForwardingChanges()) { - // if - // (StructuredDocumentToTextAdapter.this.fStopRelayingChanges) - // { - if (Debug.debugStructuredDocument) { - System.out.println("not relaying StructuredDocumentEvent " + structuredDocumentEvent.getClass().getName()); //$NON-NLS-1$ - } - return; - } - if (Debug.debugStructuredDocument) { - System.out.println("saving StructuredDocumentEvent " + structuredDocumentEvent.getClass().getName()); //$NON-NLS-1$ - } - StructuredDocumentToTextAdapter.this.lastEvent = structuredDocumentEvent; - } - } - - private static final String EMPTY_STRING = ""; //$NON-NLS-1$ - - private final static boolean redrawBackground = true; - - /** The visible child document. */ - private ProjectionDocument fChildDocument; - - /** The master document */ - private IDocument fDocument; - /** The document clone for the non-forwarding case. */ - private IDocument fDocumentClone; - - // only use this temp work around if on GTK - // it causes funny "cursor blinking" if used on windows - private final boolean forceRedrawOnRegionChanged = Platform.getWS().equals("gtk"); //$NON-NLS-1$ - /** The original content */ - private String fOriginalContent; - /** The original line delimiters */ - private String[] fOriginalLineDelimiters; - - private int fStopRelayingChangesRequests = 0; - - private StyledText fStyledTextWidget; - - /** The registered text changed listeners */ - TextChangeListener[] fTextChangeListeners; - protected DocumentListener internalDocumentListener; - - // The listeners for relaying DocumentEvents and - // requesting repaints - // after modification - private IStructuredDocumentListener internalStructuredDocumentListener; - - protected StructuredDocumentEvent lastEvent = null; - List lastEventQueue; - boolean pendingDocumentChangedEvent; - - private static final boolean DEBUG = false; - - /** - * TEST ONLY - TEST ONLY - TEST ONLY NOT API use this constructor only for - * tests. Creates a new document adapter which is initiallly not connected - * to any document. - */ - public StructuredDocumentToTextAdapter() { - - internalStructuredDocumentListener = new StructuredDocumentListener(); - internalDocumentListener = new DocumentListener(); - // for testing only - // setDocument(getModelManager().createStructuredDocumentFor(ContentTypeIdentifierForXML.ContentTypeID_XML)); - } - - /** - * Creates a new document adapter which is initiallly not connected to any - * document. - */ - public StructuredDocumentToTextAdapter(StyledText styledTextWidget) { - - // do not use 'this()' in this case - super(); - internalStructuredDocumentListener = new StructuredDocumentListener(); - internalDocumentListener = new DocumentListener(); - fStyledTextWidget = styledTextWidget; - } - - private void _setDocument(IDocument newDoc) { - if (fDocument instanceof IStructuredDocument) { - ((IStructuredDocument) fDocument).removeDocumentChangedListener(internalStructuredDocumentListener); - } - fDocument = newDoc; - if (!isStoppedForwardingChanges()) { - fDocumentClone = null; - fOriginalContent = getDocument() != null ? getDocument().get() : null; - fOriginalLineDelimiters = getDocument() != null ? getDocument().getLegalLineDelimiters() : null; - } - - if (DEBUG && fDocument != null && !(fDocument instanceof ILockable)) { - - System.out.println("Warning: non ILockable document used in StructuredDocumentToTextAdapter"); //$NON-NLS-1$ - System.out.println(" document updates on non-display thread will not be safe if editor open"); //$NON-NLS-1$ - } - if (fDocument instanceof IStructuredDocument) { - ((IStructuredDocument) fDocument).addDocumentChangedListener(internalStructuredDocumentListener); - } - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.swt.custom.StyledTextContent#addTextChangeListener(org.eclipse.swt.custom.TextChangeListener) - */ - public synchronized void addTextChangeListener(TextChangeListener listener) { - - // make sure listener is not already in listening - // (and if it is, print a warning to aid debugging, - // if needed) - - if (Utilities.contains(fTextChangeListeners, listener)) { - if (Debug.displayWarnings) { - System.out.println("StructuredDocumentToTextAdapter::addTextChangedListeners. listener " + listener + " was added more than once. "); //$NON-NLS-2$//$NON-NLS-1$ - } - } - else { - if (Debug.debugStructuredDocument) { - System.out.println("StructuredDocumentToTextAdapter::addTextChangedListeners. Adding an instance of " + listener.getClass() + " as a listener on text adapter."); //$NON-NLS-2$//$NON-NLS-1$ - } - int oldSize = 0; - if (fTextChangeListeners != null) { - // normally won't be null, but we need to be - // sure, for first time through - oldSize = fTextChangeListeners.length; - } - int newSize = oldSize + 1; - TextChangeListener[] newListeners = new TextChangeListener[newSize]; - if (fTextChangeListeners != null) { - System.arraycopy(fTextChangeListeners, 0, newListeners, 0, oldSize); - } - // add listener to last position - newListeners[newSize - 1] = listener; - // - // now switch new for old - fTextChangeListeners = newListeners; - // - } - } - - /* - * @see org.eclipse.swt.custom.StyledTextContent#getCharCount() - */ - public int getCharCount() { - - // getDocument can sometimes be null during startup - // and dispose - int result = 0; - IDocument doc = getDocument(); - if (doc != null) { - result = getSafeDocument().getLength(); - } - return result; - } - - private IDocument getClonedDocument() { - if (fDocumentClone == null) { - String content = fOriginalContent == null ? "" : fOriginalContent; //$NON-NLS-1$ - String[] delims = fOriginalLineDelimiters == null ? DefaultLineTracker.DELIMITERS : fOriginalLineDelimiters; - fDocumentClone = new DocumentClone(content, delims); - } - return fDocumentClone; - } - - Display getDisplay() { - - // Note: the workbench should always have a display - // (unless running headless), whereas Display.getCurrent() - // only returns the display if the currently executing thread - // has one. - if (PlatformUI.isWorkbenchRunning()) - return PlatformUI.getWorkbench().getDisplay(); - else - return null; - } - - /** - * Returns the visible document. - * - * @return IDocument - */ - protected IDocument getDocument() { - - if (fChildDocument == null) - return fDocument; - return fChildDocument; - } - - /** - * Returns region in master document of given region (should be region in - * projection document) - * - * @return region if no projection document exists, region of master - * document if possible, null otherwise - */ - private IRegion getProjectionToMasterRegion(IRegion region) { - IRegion originalRegion = region; - if (fChildDocument != null) { - try { - originalRegion = fChildDocument.getProjectionMapping().toOriginRegion(region); - } - catch (BadLocationException e) { - Logger.logException(e); - } - } - - return originalRegion; - } - - /** - * Returns offset in projection document of given offset (should be offset - * in master document) - * - * @return offset if no projection document exists, offset of projection - * document if possible, -1 otherwise - */ - private int getMasterToProjectionOffset(int offset) { - int originalOffset = offset; - if (fChildDocument != null) { - try { - originalOffset = fChildDocument.getProjectionMapping().toImageOffset(offset); - } - catch (BadLocationException e) { - Logger.logException(e); - } - } - - return originalOffset; - } - - /** - * Return the line at the given character offset without delimiters. - * <p> - * - * @param offset - * offset of the line to return. Does not include delimiters of - * preceeding lines. Offset 0 is the first character of the - * document. - * @return the line text without delimiters - */ - public java.lang.String getLine(int lineNumber) { - - String result = null; - if (lineNumber >= getLineCount()) { - if (Debug.displayWarnings) { - System.out.println("Development Debug: IStructuredDocument:getLine() error. lineNumber requested (" + lineNumber + ") was greater than number of lines(" + getLineCount() + "). EmptyString returned"); //$NON-NLS-1$//$NON-NLS-3$//$NON-NLS-2$ - } - result = EMPTY_STRING; - } - else { - IDocument doc = getSafeDocument(); - if (doc == null) { - result = EMPTY_STRING; - } - else { - try { - IRegion r = doc.getLineInformation(lineNumber); - if (r.getLength() > 0) { - result = doc.get(r.getOffset(), r.getLength()); - } - else { - result = EMPTY_STRING; - } - } - catch (BadLocationException e) { - result = EMPTY_STRING; - } - } - } - return result; - } - - /** - * Tries to repair the line information. - * - * @param document - * the document - * @see IRepairableDocument#repairLineInformation() - * @see Eclipse 3.0 - */ - private void repairLineInformation(IDocument document) { - if (document instanceof IRepairableDocument) { - IRepairableDocument repairable = (IRepairableDocument) document; - repairable.repairLineInformation(); - } - } - - /** - * Return the line index at the given character offset. - * <p> - * - * @param offset - * offset of the line to return. The first character of the - * document is at offset 0. An offset of getLength() is valid - * and should answer the number of lines. - * @return the line index. The first line is at index 0. If the character - * at offset is a delimiter character, answer the line index of - * the line that is delimited. For example, text = "\r\n\r\n", - * delimiter = "\r\n", then: getLineAtOffset(0) == 0 - * getLineAtOffset(1) == 0 getLineAtOffset(2) == 1 - * getLineAtOffset(3) == 1 getLineAtOffset(4) == 2 - */ - public int getLineAtOffset(int offset) { - - int result = 0; - IDocument doc = getSafeDocument(); - if (doc != null) { - try { - result = doc.getLineOfOffset(offset); - } - catch (BadLocationException x) { - repairLineInformation(doc); - try { - result = doc.getLineOfOffset(offset); - } - catch (BadLocationException x2) { - // should not occur, but seems to for projection - // documents, related to repainting overview ruler - result = 0; - } - } - } - return result; - } - - public int getLineCount() { - int result = 0; - IDocument doc = getSafeDocument(); - if (doc != null) { - result = doc.getNumberOfLines(); - } - return result; - } - - /* - * @see org.eclipse.swt.custom.StyledTextContent#getLineDelimiter - */ - public String getLineDelimiter() { - String result = null; - if (getParentDocument() instanceof IStructuredDocument) { - result = ((IStructuredDocument) getParentDocument()).getLineDelimiter(); - } - else { - IDocument doc = getSafeDocument(); - result = TextUtilities.getDefaultLineDelimiter(doc); - } - return result; - } - - /** - * Return the character offset of the first character of the given line. - * <p> - * - * @param lineIndex - * index of the line. The first line is at index 0. - * @return offset offset of the first character of the line. The first - * character of the document is at offset 0. The return value - * should include line delimiters. For example, text = - * "\r\ntest\r\n", delimiter = "\r\n", then: getOffsetAtLine(0) == - * 0 getOffsetAtLine(1) == 2 getOffsetAtLine(2) == 8 NOTE: When - * there is no text (i.e., no lines), getOffsetAtLine(0) is a - * valid call that should return 0. - */ - public int getOffsetAtLine(int lineIndex) { - - int result = 0; - IDocument doc = getSafeDocument(); - if (doc != null) { - try { - result = doc.getLineOffset(lineIndex); - } - catch (BadLocationException e) { - result = 0; - } - } - return result; - } - - /** - * Returns the parent document - * - * @return the parent document - */ - private IDocument getParentDocument() { - return fDocument; - } - - /** - * This is the document to use for request from the StyledText widget. Its - * either the live documnet or a clone of it, depending on stop/resume - * state. - */ - private IDocument getSafeDocument() { - IDocument result = null; - if (isStoppedForwardingChanges()) { - result = getClonedDocument(); - } - else { - // note, this document can be normal structured text document, - // or the projection/child document - result = getDocument(); - } - return result; - } - - /** - * @return org.eclipse.swt.custom.StyledText - */ - StyledText getStyledTextWidget() { - return fStyledTextWidget; - } - - /** - * Returns a string representing the content at the given range. - * <p> - * - * @param start - * the start offset of the text to return. Offset 0 is the - * first character of the document. - * @param length - * the length of the text to return - * @return the text at the given range - */ - public String getTextRange(int start, int length) { - String result = null; - try { - IDocument doc = getSafeDocument(); - result = doc.get(start, length); - } - catch (BadLocationException e) { - result = EMPTY_STRING; - } - return result; - } - - /** - * assume only for "no change" events, for now - */ - protected void handlePendingEvents() { - - if (lastEventQueue == null) - return; - - Iterator iterator = lastEventQueue.iterator(); - while (iterator.hasNext()) { - NoChangeEvent noChangeEvent = (NoChangeEvent) iterator.next(); - redrawNoChange(noChangeEvent); - } - - lastEventQueue = null; - lastEvent = null; - } - - boolean isStoppedForwardingChanges() { - return fStopRelayingChangesRequests > 0; - } - - /** - * this method is assumed to be called only for read only region changes. - */ - protected void redrawNoChange(NoChangeEvent structuredDocumentEvent) { - - if (isStoppedForwardingChanges()) - return; - if (Debug.debugStructuredDocument) { - System.out.println("maybe redraw stuff"); //$NON-NLS-1$ - } - - int startOffset = structuredDocumentEvent.getOffset(); - int length = structuredDocumentEvent.getLength(); - redrawRangeWithLength(startOffset, length); - - } - - /** - * Request a redraw of the text range occupied by the given - * StructuredDocumentRegionsReplacedEvent - * - * @param structuredDocumentEvent - */ - protected void redrawNodesReplaced(StructuredDocumentRegionsReplacedEvent structuredDocumentEvent) { - - if (isStoppedForwardingChanges()) - return; - if (Debug.debugStructuredDocument) { - System.out.println("maybe redraw stuff"); //$NON-NLS-1$ - } - // just the new stuff - IStructuredDocumentRegionList newStructuredDocumentRegions = structuredDocumentEvent.getNewStructuredDocumentRegions(); - - int nNewNodes = newStructuredDocumentRegions.getLength(); - if (nNewNodes > 0) { - IStructuredDocumentRegion firstNode = newStructuredDocumentRegions.item(0); - IStructuredDocumentRegion lastNode = newStructuredDocumentRegions.item(nNewNodes - 1); - redrawRange(firstNode.getStartOffset(), lastNode.getEndOffset()); - } - } - - /** - * Redraws the give offsets in terms of the StructuredDocument. If only - * part of the model is visible, ensures that only the visible portion of - * the given range is redrawn. - * - * @param startModelOffset - * @param endModelOffset - */ - private void redrawRange(final int startModelOffset, final int endModelOffset) { - - if (getDocument() == null) - return; - if (Debug.debugStructuredDocument) { - System.out.println("redraw stuff: " + startModelOffset + "-" + endModelOffset); //$NON-NLS-1$ //$NON-NLS-2$ - } - if (fChildDocument == null) { - Runnable runnable = new Runnable() { - public void run() { - getStyledTextWidget().redrawRange(startModelOffset, endModelOffset - startModelOffset, redrawBackground); - } - }; - runOnDisplayThreadIfNeedede(runnable); - - } - else { - int high = getDocument().getLength(); - int startOffset = getMasterToProjectionOffset(startModelOffset); - - int endOffset = getMasterToProjectionOffset(endModelOffset); - - // if offsets were not visible, just try to redraw everything in - // the child document - // // not visible - // if (endOffset < 0 || startOffset > high) - // return; - // restrict lower bound - if (startOffset < 0) { - startOffset = 0; - } - // restrict upper bound - // if (endOffset > high) { - // endOffset = high; - // } - if (endOffset < 0) { - endOffset = high; - } - - int length = endOffset - startOffset; - // redrawBackground with false would be faster - // but assumes background (or font) is not - // changing - final int finalStartOffset = startOffset; - final int finallength = length; - - Runnable runnable = new Runnable() { - public void run() { - getStyledTextWidget().redrawRange(finalStartOffset, finallength, redrawBackground); - } - }; - runOnDisplayThreadIfNeedede(runnable); - - } - } - - /** - * Redraws the give offsets in terms of the Flat Node model. If only part - * of the model is visible, ensures that only the visible portion of the - * given range is redrawn. - * - * @param startModelOffset - * @param endModelOffset - */ - private void redrawRangeWithLength(final int startModelOffset, final int length) { - - if (getDocument() == null) - return; - if (Debug.debugStructuredDocument) { - System.out.println("redraw stuff: " + startModelOffset + "-" + length); //$NON-NLS-1$ //$NON-NLS-2$ - } - if (fChildDocument == null) { - Runnable runnable = new Runnable() { - public void run() { - getStyledTextWidget().redrawRange(startModelOffset, length, redrawBackground); - } - }; - runOnDisplayThreadIfNeedede(runnable); - } - else { - int high = getDocument().getLength(); - // TODO need to take into account segmented visible regions - int startOffset = getMasterToProjectionOffset(startModelOffset); - // not visible - if (startOffset > high || length < 1) - return; - // restrict lower bound - if (startOffset < 0) { - startOffset = 0; - } - int endOffset = startOffset + length - 1; - // restrict upper bound - if (endOffset > high) { - endOffset = high; - } - - // note: length of the child documnet should be - // updated, - // need to investigate why its not at this - // point, but is - // probably just because the document event - // handling is not - // completely finished. - int newLength = endOffset - startOffset; // d283007 - - // redrawBackground with false would be faster - // but assumes background (or font) is not - // changing - final int finalStartOffset = startOffset; - final int finalNewLength = newLength; - Runnable runnable = new Runnable() { - public void run() { - getStyledTextWidget().redrawRange(finalStartOffset, finalNewLength, redrawBackground); - } - }; - runOnDisplayThreadIfNeedede(runnable); - } - } - - /** - * Request a redraw of the text range occupied by the given - * RegionChangedEvent for certain (not all) ITextRegion contexts - * - * @param structuredDocumentEvent - */ - protected void redrawRegionChanged(RegionChangedEvent structuredDocumentEvent) { - - if (isStoppedForwardingChanges()) { - return; - } - if (Debug.debugStructuredDocument) { - System.out.println("maybe redraw stuff"); //$NON-NLS-1$ - } - - - // (nsd) TODO: try to make this reliable somehow - // without being directly content dependent - // if ((region instanceof ITextRegionContainer) || - // (type == XMLJSPRegionContexts.BLOCK_TEXT) || - // (type == XMLJSPRegionContexts.JSP_CONTENT)) { - // IStructuredDocumentRegion flatNode = - // structuredDocumentEvent.getStructuredDocumentRegion(); - // // redraw background of false is faster, - // // but assumes background (or font) is not - // changing - // redrawRange(flatNode.getStartOffset(region), - // flatNode.getEndOffset(region)); - // } - if (forceRedrawOnRegionChanged) { - // workaround for redrawing problems on Linux-GTK - int startOffset = structuredDocumentEvent.getOffset(); - int endOffset = structuredDocumentEvent.getOffset() + structuredDocumentEvent.getLength(); - try { - IRegion startLine = structuredDocumentEvent.fDocument.getLineInformationOfOffset(startOffset); - IRegion endLine = structuredDocumentEvent.fDocument.getLineInformationOfOffset(endOffset); - if (startLine != null && endLine != null) { - redrawRange(startLine.getOffset(), endLine.getOffset() + endLine.getLength()); - } - } - catch (BadLocationException e) { - // nothing for now - } - } - } - - /** - * Request a redraw of the text range occupied by the given - * RegionsReplacedEvent - * - * @param structuredDocumentEvent - */ - protected void redrawRegionsReplaced(RegionsReplacedEvent structuredDocumentEvent) { - - if (isStoppedForwardingChanges()) - return; - if (Debug.debugStructuredDocument) { - System.out.println("maybe redraw stuff"); //$NON-NLS-1$ - } - ITextRegionList newRegions = structuredDocumentEvent.getNewRegions(); - int nRegions = newRegions.size(); - if (nRegions > 0) { - ITextRegion firstRegion = newRegions.get(0); - ITextRegion lastRegion = newRegions.get(nRegions - 1); - IStructuredDocumentRegion flatNode = structuredDocumentEvent.getStructuredDocumentRegion(); - redrawRange(flatNode.getStartOffset(firstRegion), flatNode.getEndOffset(lastRegion)); - } - } - - protected void redrawTextChanged() { - - if (lastEvent != null) { - // update display, since some cases can effect - // highlighting beyond the changed text area. - if (lastEvent instanceof StructuredDocumentRegionsReplacedEvent) - redrawNodesReplaced((StructuredDocumentRegionsReplacedEvent) lastEvent); - if (lastEvent instanceof RegionsReplacedEvent) - redrawRegionsReplaced((RegionsReplacedEvent) lastEvent); - if (lastEvent instanceof RegionChangedEvent) - redrawRegionChanged((RegionChangedEvent) lastEvent); - // moved following line to 'document changed' so - // the "last event" can be - // re-drawn after pending re-draws - // lastEvent = null; - } - } - - /** - * Sends a text replace event to all registered listeners. - */ - protected void relayTextChanged() { - - if (isStoppedForwardingChanges()) { - if (Debug.debugStructuredDocument && getDocument() != null) { - System.out.println("NOT relaying text changed (" + getDocument().getLength() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ - } - return; - } - if (Debug.debugStructuredDocument && getDocument() != null) { - System.out.println("relaying text changed (" + getDocument().getLength() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ - } - final TextChangedEvent textChangedEvent = new TextChangedEvent(this); - - // we must assign listeners to local variable, since - // the add and remove listener - // methods can change the actual instance of the - // listener array from another thread - - Runnable runnable = new Runnable() { - public void run() { - if (fTextChangeListeners != null) { - Object[] holdListeners = fTextChangeListeners; - for (int i = 0; i < holdListeners.length; i++) { - // this is a safe cast, since addListeners - // requires a IStructuredDocumentListener - ((TextChangeListener) holdListeners[i]).textChanged(textChangedEvent); - } - } - } - }; - runOnDisplayThreadIfNeedede(runnable); - redrawTextChanged(); - } - - /** - * Sends a text change to all registered listeners - */ - protected void relayTextChanging(int requestedStart, int requestedLength, String requestedChange) { - - if (getDocument() == null) - return; - if (isStoppedForwardingChanges()) { - if (Debug.debugStructuredDocument && getDocument() != null) { - System.out.println("NOT relaying text changing: " + requestedStart + ":" + getDocument().getLength()); //$NON-NLS-1$ //$NON-NLS-2$ - } - return; - } - if (Debug.debugStructuredDocument && getDocument() != null) { - System.out.println("relaying text changing: " + requestedStart + ":" + getDocument().getLength()); //$NON-NLS-1$ //$NON-NLS-2$ - } - lastEvent = null; - try { - final TextChangingEvent textChangingEvent = new TextChangingEvent(this); - - textChangingEvent.start = requestedStart; - textChangingEvent.replaceCharCount = requestedLength; - textChangingEvent.newCharCount = (requestedChange == null ? 0 : requestedChange.length()); - textChangingEvent.replaceLineCount = getDocument().getNumberOfLines(requestedStart, requestedLength) - 1; - textChangingEvent.newText = requestedChange; - textChangingEvent.newLineCount = (requestedChange == null ? 0 : getDocument().computeNumberOfLines(requestedChange)); - - // we must assign listeners to local variable, - // since the add and remove listner - // methods can change the actual instance of the - // listener array from another thread - Runnable runnable = new Runnable() { - public void run() { - if (fTextChangeListeners != null) { - TextChangeListener[] holdListeners = fTextChangeListeners; - for (int i = 0; i < holdListeners.length; i++) { - // this is a safe cast, since - // addListeners requires a - // IStructuredDocumentListener - holdListeners[i].textChanging(textChangingEvent); - } - } - } - }; - runOnDisplayThreadIfNeedede(runnable); - } - catch (BadLocationException e) { - // log for now, unless we find reason not to - Logger.log(Logger.INFO, e.getMessage()); - } - } - - /** - * Sends a text set event to all registered listeners. Widget should - * redraw itself automatically. - */ - protected void relayTextSet() { - - if (isStoppedForwardingChanges()) { - if (Debug.debugStructuredDocument && getDocument() != null) { - System.out.println("NOT relaying text set (" + getDocument().getLength() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ - } - return; - } - if (Debug.debugStructuredDocument && getDocument() != null) { - System.out.println("relaying text set (" + getDocument().getLength() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ - } - lastEvent = null; - final TextChangedEvent textChangedEvent = new TextChangedEvent(this); - - // we must assign listeners to local variable, since - // the add and remove listner - // methods can change the actual instance of the - // listener array from another thread - Runnable runnable = new Runnable() { - public void run() { - if (fTextChangeListeners != null) { - TextChangeListener[] holdListeners = fTextChangeListeners; - for (int i = 0; i < holdListeners.length; i++) { - holdListeners[i].textSet(textChangedEvent); - } - } - } - }; - runOnDisplayThreadIfNeedede(runnable); - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.swt.custom.StyledTextContent#removeTextChangeListener(org.eclipse.swt.custom.TextChangeListener) - */ - public synchronized void removeTextChangeListener(final TextChangeListener listener) { - - if ((fTextChangeListeners != null) && (listener != null)) { - // if its not in the listeners, we'll ignore the - // request - if (!Utilities.contains(fTextChangeListeners, listener)) { - if (Debug.displayWarnings) { - System.out.println("StructuredDocumentToTextAdapter::removeTextChangedListeners. listener " + listener + " was not present. "); //$NON-NLS-2$//$NON-NLS-1$ - } - } - else { - if (Debug.debugStructuredDocument) { - System.out.println("StructuredDocumentToTextAdapter::addTextChangedListeners. Removing an instance of " + listener.getClass() + " as a listener on text adapter."); //$NON-NLS-2$//$NON-NLS-1$ - } - final int oldSize = fTextChangeListeners.length; - int newSize = oldSize - 1; - final TextChangeListener[] newListeners = new TextChangeListener[newSize]; - - Runnable runnable = new Runnable() { - public void run() { - int index = 0; - for (int i = 0; i < oldSize; i++) { - if (fTextChangeListeners[i] != listener) { - // copy old to new if its not the - // one we are removing - newListeners[index++] = fTextChangeListeners[i]; - } - } - } - }; - runOnDisplayThreadIfNeedede(runnable); - // now that we have a new array, let's - // switch it for the old one - fTextChangeListeners = newListeners; - } - } - } - - /** - * Replace the text with "newText" starting at position "start" for a - * length of "replaceLength". - * <p> - * Implementors have to notify TextChanged listeners after the content has - * been updated. The TextChangedEvent should be set as follows: - * <ul> - * <li>event.type = SWT.TextReplaced - * <li>event.start = start of the replaced text - * <li>event.numReplacedLines = number of replaced lines - * <li>event.numNewLines = number of new lines - * <li>event.replacedLength = length of the replaced text - * <li>event.newLength = length of the new text - * </ul> - * <b>NOTE: </b> numNewLines is the number of inserted lines and - * numReplacedLines is the number of deleted lines based on the change - * that occurs visually. For example: - * <ul> - * <li>(replacedText, newText) ==> (numReplacedLines, numNewLines) - * <li>("", "\n") ==> (0, 1) - * <li>("\n\n", "a") ==> (2, 0) - * <li>("a", "\n\n") ==> (0, 2) - * <li>("\n", "") ==> (1, 0) - * </ul> - * </p> - * - * @param start - * start offset of text to replace, none of the offsets include - * delimiters of preceeding lines, offset 0 is the first - * character of the document - * @param replaceLength - * start offset of text to replace - * @param newText - * start offset of text to replace - */ - public void replaceTextRange(int start, int replaceLength, String text) { - - if (getParentDocument() instanceof IStructuredDocument) { - // the structuredDocument initiates the "changing" - // and "changed" events. - // they are both fired by the time this method - // returns. - IRegion region = getProjectionToMasterRegion(new Region(start, replaceLength)); - if (region != null) { - ((IStructuredDocument) getParentDocument()).replaceText(this, region.getOffset(), region.getLength(), text); - return; - } - } - // default is to just try and replace text range in current document - try { - getDocument().replace(start, replaceLength, text); - } - catch (BadLocationException e) { - // log for now, unless we find reason not to - Logger.log(Logger.INFO, e.getMessage()); - } - } - - /** - * @see org.eclipse.jface.text.IDocumentAdapterExtension#resumeForwardingDocumentChanges() - */ - public void resumeForwardingDocumentChanges() { - - // from re-reading the textSet API in StyledText, we - // must call - // textSet if all the contents changed. If all the - // contents did - // not change, we need to call the pair of APIs, - // textChanging and - // textChanged. So, if we ever keep careful track of - // changes - // during stop forwarding and resume forwarding, we - // can - // investigate change make use of the pair of APIs. - fStopRelayingChangesRequests--; - if (fStopRelayingChangesRequests == 0) { - // fIsForwarding= true; - fDocumentClone = null; - fOriginalContent = null; - fOriginalLineDelimiters = null; - // fireTextSet(); - relayTextSet(); - } - } - - /** - * This 'Runnable' should be very brief, and should not "call out" to - * other code which itself might call syncExec, or deadlock might occur. - * - * @param r - */ - private void runOnDisplayThreadIfNeedede(Runnable r) { - // if there is no Display at all (that is, running headless), - // or if we are already running on the display thread, then - // simply execute the runnable. - if (getDisplay() == null || (Thread.currentThread() == getDisplay().getThread())) { - r.run(); - } - else { - // otherwise force the runnable to run on the display thread. - // - // Its unclear if we need this at all, once - // we "force" document update to always take place on display - // thread. - IDocument doc = getDocument(); - if (doc instanceof ILockable) { - - ILock lock = null; - try { - lock = ((ILockable) doc).getLockObject(); - lock.acquire(); - getDisplay().syncExec(r); - } - finally { - if (lock != null) { - lock.release(); - } - } - } - else { - // else, ignore!, since risk of deadlock - throw new IllegalStateException("non lockable document used for structuredDocumentToTextAdapter"); //$NON-NLS-1$ - } - } - } - - /** - * @param newModel - */ - public void setDocument(IDocument document) { - - if (getDocument() != null) { - getDocument().removePrenotifiedDocumentListener(internalDocumentListener); - } - lastEvent = null; - if (document instanceof ProjectionDocument) { - fChildDocument = (ProjectionDocument) document; - _setDocument(fChildDocument.getMasterDocument()); - } - else { - fChildDocument = null; - _setDocument(document); - } - if (getDocument() != null) { - getDocument().addPrenotifiedDocumentListener(internalDocumentListener); - } - } - - /** - * @see IDocument#setText - */ - public void setText(String string) { - - if (isStoppedForwardingChanges()) { - fDocumentClone = null; - fOriginalContent = getDocument().get(); - fOriginalLineDelimiters = getDocument().getLegalLineDelimiters(); - } - else if (getParentDocument() instanceof IStructuredDocument) { - ((IStructuredDocument) getDocument()).setText(this, string); - } - else { - getDocument().set(string); - } - relayTextSet(); - } - - /** - * This method was added to make testing easier. Normally, the widget is - * specified on the constructor. - */ - public void setWidget(StyledText widget) { - - fStyledTextWidget = widget; - } - - /** - * @see org.eclipse.jface.text.IDocumentAdapterExtension#stopForwardingDocumentChanges() - */ - public void stopForwardingDocumentChanges() { - - fStopRelayingChangesRequests++; - // only need to take snapshot on first request - if (fStopRelayingChangesRequests == 1) { - fDocumentClone = null; - fOriginalContent = getDocument().get(); - fOriginalLineDelimiters = getDocument().getLegalLineDelimiters(); - } - } -} |