Mercurial > projects > dwt-addons
diff dwtx/jface/text/DefaultDocumentAdapter.d @ 129:eb30df5ca28b
Added JFace Text sources
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 23 Aug 2008 19:10:48 +0200 |
parents | |
children | c4fb132a086c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/text/DefaultDocumentAdapter.d Sat Aug 23 19:10:48 2008 +0200 @@ -0,0 +1,424 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 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 + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module dwtx.jface.text.DefaultDocumentAdapter; + +import dwt.dwthelper.utils; + + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import dwt.DWT; +import dwt.custom.TextChangeListener; +import dwt.custom.TextChangedEvent; +import dwt.custom.TextChangingEvent; +import dwtx.core.runtime.Assert; + + +/** + * Default implementation of {@link dwtx.jface.text.IDocumentAdapter}. + * <p> + * <strong>Note:</strong> This adapter does not work if the widget auto-wraps the text. + * </p> + */ +class DefaultDocumentAdapter : IDocumentAdapter, IDocumentListener, IDocumentAdapterExtension { + + /** The adapted document. */ + private IDocument fDocument; + /** The document clone for the non-forwarding case. */ + private IDocument fDocumentClone; + /** The original content */ + private String fOriginalContent; + /** The original line delimiters */ + private String[] fOriginalLineDelimiters; + /** The registered text change listeners */ + private List fTextChangeListeners= new ArrayList(1); + /** + * The remembered document event + * @since 2.0 + */ + private DocumentEvent fEvent; + /** The line delimiter */ + private String fLineDelimiter= null; + /** + * Indicates whether this adapter is forwarding document changes + * @since 2.0 + */ + private bool fIsForwarding= true; + /** + * Length of document at receipt of <code>documentAboutToBeChanged</code> + * @since 2.1 + */ + private int fRememberedLengthOfDocument; + /** + * Length of first document line at receipt of <code>documentAboutToBeChanged</code> + * @since 2.1 + */ + private int fRememberedLengthOfFirstLine; + /** + * The data of the event at receipt of <code>documentAboutToBeChanged</code> + * @since 2.1 + */ + private DocumentEvent fOriginalEvent= new DocumentEvent(); + + + /** + * Creates a new document adapter which is initially not connected to + * any document. + */ + public DefaultDocumentAdapter() { + } + + /** + * Sets the given document as the document to be adapted. + * + * @param document the document to be adapted or <code>null</code> if there is no document + */ + public void setDocument(IDocument document) { + + if (fDocument !is null) + fDocument.removePrenotifiedDocumentListener(this); + + fDocument= document; + fLineDelimiter= null; + + if (!fIsForwarding) { + fDocumentClone= null; + if (fDocument !is null) { + fOriginalContent= fDocument.get(); + fOriginalLineDelimiters= fDocument.getLegalLineDelimiters(); + } else { + fOriginalContent= null; + fOriginalLineDelimiters= null; + } + } + + if (fDocument !is null) + fDocument.addPrenotifiedDocumentListener(this); + } + + /* + * @see StyledTextContent#addTextChangeListener(TextChangeListener) + */ + public void addTextChangeListener(TextChangeListener listener) { + Assert.isNotNull(listener); + if (!fTextChangeListeners.contains(listener)) + fTextChangeListeners.add(listener); + } + + /* + * @see StyledTextContent#removeTextChangeListener(TextChangeListener) + */ + public void removeTextChangeListener(TextChangeListener listener) { + Assert.isNotNull(listener); + fTextChangeListeners.remove(listener); + } + + /** + * Tries to repair the line information. + * + * @param document the document + * @see IRepairableDocument#repairLineInformation() + * @since 3.0 + */ + private void repairLineInformation(IDocument document) { + if (document instanceof IRepairableDocument) { + IRepairableDocument repairable= (IRepairableDocument) document; + repairable.repairLineInformation(); + } + } + + /** + * Returns the line for the given line number. + * + * @param document the document + * @param line the line number + * @return the content of the line of the given number in the given document + * @throws BadLocationException if the line number is invalid for the adapted document + * @since 3.0 + */ + private String doGetLine(IDocument document, int line) throws BadLocationException { + IRegion r= document.getLineInformation(line); + return document.get(r.getOffset(), r.getLength()); + } + + private IDocument getDocumentForRead() { + if (!fIsForwarding) { + if (fDocumentClone is null) { + String content= fOriginalContent is null ? "" : fOriginalContent; //$NON-NLS-1$ + String[] delims= fOriginalLineDelimiters is null ? DefaultLineTracker.DELIMITERS : fOriginalLineDelimiters; + fDocumentClone= new DocumentClone(content, delims); + } + return fDocumentClone; + } + + return fDocument; + } + + /* + * @see StyledTextContent#getLine(int) + */ + public String getLine(int line) { + + IDocument document= getDocumentForRead(); + try { + return doGetLine(document, line); + } catch (BadLocationException x) { + repairLineInformation(document); + try { + return doGetLine(document, line); + } catch (BadLocationException x2) { + } + } + + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + return null; + } + + /* + * @see StyledTextContent#getLineAtOffset(int) + */ + public int getLineAtOffset(int offset) { + IDocument document= getDocumentForRead(); + try { + return document.getLineOfOffset(offset); + } catch (BadLocationException x) { + repairLineInformation(document); + try { + return document.getLineOfOffset(offset); + } catch (BadLocationException x2) { + } + } + + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + return -1; + } + + /* + * @see StyledTextContent#getLineCount() + */ + public int getLineCount() { + return getDocumentForRead().getNumberOfLines(); + } + + /* + * @see StyledTextContent#getOffsetAtLine(int) + */ + public int getOffsetAtLine(int line) { + IDocument document= getDocumentForRead(); + try { + return document.getLineOffset(line); + } catch (BadLocationException x) { + repairLineInformation(document); + try { + return document.getLineOffset(line); + } catch (BadLocationException x2) { + } + } + + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + return -1; + } + + /* + * @see StyledTextContent#getTextRange(int, int) + */ + public String getTextRange(int offset, int length) { + try { + return getDocumentForRead().get(offset, length); + } catch (BadLocationException x) { + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + return null; + } + } + + /* + * @see StyledTextContent#replaceTextRange(int, int, String) + */ + public void replaceTextRange(int pos, int length, String text) { + try { + fDocument.replace(pos, length, text); + } catch (BadLocationException x) { + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + } + } + + /* + * @see StyledTextContent#setText(String) + */ + public void setText(String text) { + fDocument.set(text); + } + + /* + * @see StyledTextContent#getCharCount() + */ + public int getCharCount() { + return getDocumentForRead().getLength(); + } + + /* + * @see StyledTextContent#getLineDelimiter() + */ + public String getLineDelimiter() { + if (fLineDelimiter is null) + fLineDelimiter= TextUtilities.getDefaultLineDelimiter(fDocument); + return fLineDelimiter; + } + + /* + * @see IDocumentListener#documentChanged(DocumentEvent) + */ + public void documentChanged(DocumentEvent event) { + // check whether the given event is the one which was remembered + if (fEvent is null || event !is fEvent) + return; + + if (isPatchedEvent(event) || (event.getOffset() is 0 && event.getLength() is fRememberedLengthOfDocument)) { + fLineDelimiter= null; + fireTextSet(); + } else { + if (event.getOffset() < fRememberedLengthOfFirstLine) + fLineDelimiter= null; + fireTextChanged(); + } + } + + /* + * @see IDocumentListener#documentAboutToBeChanged(DocumentEvent) + */ + public void documentAboutToBeChanged(DocumentEvent event) { + + fRememberedLengthOfDocument= fDocument.getLength(); + try { + fRememberedLengthOfFirstLine= fDocument.getLineLength(0); + } catch (BadLocationException e) { + fRememberedLengthOfFirstLine= -1; + } + + fEvent= event; + rememberEventData(fEvent); + fireTextChanging(); + } + + /** + * Checks whether this event has been changed between <code>documentAboutToBeChanged</code> and + * <code>documentChanged</code>. + * + * @param event the event to be checked + * @return <code>true</code> if the event has been changed, <code>false</code> otherwise + */ + private bool isPatchedEvent(DocumentEvent event) { + return fOriginalEvent.fOffset !is event.fOffset || fOriginalEvent.fLength !is event.fLength || fOriginalEvent.fText !is event.fText; + } + + /** + * Makes a copy of the given event and remembers it. + * + * @param event the event to be copied + */ + private void rememberEventData(DocumentEvent event) { + fOriginalEvent.fOffset= event.fOffset; + fOriginalEvent.fLength= event.fLength; + fOriginalEvent.fText= event.fText; + } + + /** + * Sends a text changed event to all registered listeners. + */ + private void fireTextChanged() { + + if (!fIsForwarding) + return; + + TextChangedEvent event= new TextChangedEvent(this); + + if (fTextChangeListeners !is null && fTextChangeListeners.size() > 0) { + Iterator e= new ArrayList(fTextChangeListeners).iterator(); + while (e.hasNext()) + ((TextChangeListener) e.next()).textChanged(event); + } + } + + /** + * Sends a text set event to all registered listeners. + */ + private void fireTextSet() { + + if (!fIsForwarding) + return; + + TextChangedEvent event = new TextChangedEvent(this); + + if (fTextChangeListeners !is null && fTextChangeListeners.size() > 0) { + Iterator e= new ArrayList(fTextChangeListeners).iterator(); + while (e.hasNext()) + ((TextChangeListener) e.next()).textSet(event); + } + } + + /** + * Sends the text changing event to all registered listeners. + */ + private void fireTextChanging() { + + if (!fIsForwarding) + return; + + try { + IDocument document= fEvent.getDocument(); + if (document is null) + return; + + TextChangingEvent event= new TextChangingEvent(this); + event.start= fEvent.fOffset; + event.replaceCharCount= fEvent.fLength; + event.replaceLineCount= document.getNumberOfLines(fEvent.fOffset, fEvent.fLength) - 1; + event.newText= fEvent.fText; + event.newCharCount= (fEvent.fText is null ? 0 : fEvent.fText.length()); + event.newLineCount= (fEvent.fText is null ? 0 : document.computeNumberOfLines(fEvent.fText)); + + if (fTextChangeListeners !is null && fTextChangeListeners.size() > 0) { + Iterator e= new ArrayList(fTextChangeListeners).iterator(); + while (e.hasNext()) + ((TextChangeListener) e.next()).textChanging(event); + } + + } catch (BadLocationException e) { + } + } + + /* + * @see IDocumentAdapterExtension#resumeForwardingDocumentChanges() + * @since 2.0 + */ + public void resumeForwardingDocumentChanges() { + fIsForwarding= true; + fDocumentClone= null; + fOriginalContent= null; + fOriginalLineDelimiters= null; + fireTextSet(); + } + + /* + * @see IDocumentAdapterExtension#stopForwardingDocumentChanges() + * @since 2.0 + */ + public void stopForwardingDocumentChanges() { + fDocumentClone= null; + fOriginalContent= fDocument.get(); + fOriginalLineDelimiters= fDocument.getLegalLineDelimiters(); + fIsForwarding= false; + } +}